From 24cbdfccbe23c9481920a1ede2e428adc535d5d5 Mon Sep 17 00:00:00 2001 From: shalinilohia50 <46928246+shalinilohia50@users.noreply.github.com> Date: Mon, 6 Mar 2023 13:30:18 +0530 Subject: [PATCH 001/363] Fix the column "is_ms_shipped" of the view "sys.all_views" (#1312) (#1318) The column "is_ms_shipped" of the view "sys.all_views" should be correctly set to 0 or 1 based on the view being a system view or a user created view. Currently, is_ms_shipped is hardcoded to "0" which means SSMS treats all the system views as User defined views which is incorrect. Task: BABEL-4040 Signed-off-by: Shalini Lohia lshalini@amazon.com --- contrib/babelfishpg_tsql/sql/sys_views.sql | 5 +++- .../babelfishpg_tsql--2.3.0--2.4.0.sql | 5 +++- .../babelfishpg_tsql--3.0.0--3.1.0.sql | 5 +++- .../JDBC/expected/sys-all_views-vu-verify.out | 26 +++++++++++++++++++ .../input/views/sys-all_views-vu-verify.sql | 21 +++++++++++++++ 5 files changed, 59 insertions(+), 3 deletions(-) diff --git a/contrib/babelfishpg_tsql/sql/sys_views.sql b/contrib/babelfishpg_tsql/sql/sys_views.sql index e186928ae8..f664b33ed6 100644 --- a/contrib/babelfishpg_tsql/sql/sys_views.sql +++ b/contrib/babelfishpg_tsql/sql/sys_views.sql @@ -1527,7 +1527,10 @@ SELECT , CAST('VIEW'as sys.nvarchar(60)) as type_desc , CAST(null as sys.datetime) as create_date , CAST(null as sys.datetime) as modify_date - , CAST(0 as sys.bit) as is_ms_shipped + , CAST(case when (c.relnamespace::regnamespace::text = 'sys') then 1 + when c.relname in (select name from sys.shipped_objects_not_in_sys nis + where nis.name = c.relname and nis.schemaid = c.relnamespace and nis.type = 'V') then 1 + else 0 end as sys.bit) AS is_ms_shipped , CAST(0 as sys.bit) as is_published , CAST(0 as sys.bit) as is_schema_published , CAST(0 as sys.BIT) AS is_replicated diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.3.0--2.4.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.3.0--2.4.0.sql index bd8ec79f1a..b5397cabf7 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.3.0--2.4.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.3.0--2.4.0.sql @@ -1496,7 +1496,10 @@ SELECT , CAST('VIEW'as sys.nvarchar(60)) as type_desc , CAST(null as sys.datetime) as create_date , CAST(null as sys.datetime) as modify_date - , CAST(0 as sys.bit) as is_ms_shipped + , CAST(case when (c.relnamespace::regnamespace::text = 'sys') then 1 + when c.relname in (select name from sys.shipped_objects_not_in_sys nis + where nis.name = c.relname and nis.schemaid = c.relnamespace and nis.type = 'V') then 1 + else 0 end as sys.bit) AS is_ms_shipped , CAST(0 as sys.bit) as is_published , CAST(0 as sys.bit) as is_schema_published , CAST(0 as sys.BIT) AS is_replicated diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.0.0--3.1.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.0.0--3.1.0.sql index b7bcc53a89..573775a629 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.0.0--3.1.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.0.0--3.1.0.sql @@ -2198,7 +2198,10 @@ SELECT , CAST('VIEW'as sys.nvarchar(60)) as type_desc , CAST(null as sys.datetime) as create_date , CAST(null as sys.datetime) as modify_date - , CAST(0 as sys.bit) as is_ms_shipped + , CAST(case when (c.relnamespace::regnamespace::text = 'sys') then 1 + when c.relname in (select name from sys.shipped_objects_not_in_sys nis + where nis.name = c.relname and nis.schemaid = c.relnamespace and nis.type = 'V') then 1 + else 0 end as sys.bit) AS is_ms_shipped , CAST(0 as sys.bit) as is_published , CAST(0 as sys.bit) as is_schema_published , CAST(0 as sys.BIT) AS is_replicated diff --git a/test/JDBC/expected/sys-all_views-vu-verify.out b/test/JDBC/expected/sys-all_views-vu-verify.out index fdb66d665c..96f7a3c735 100644 --- a/test/JDBC/expected/sys-all_views-vu-verify.out +++ b/test/JDBC/expected/sys-all_views-vu-verify.out @@ -74,6 +74,32 @@ sys_all_views_select_chk_option_vu_prepare#!##!#V #!#VIEW#!##!##!#V #!#VIEW#!##!##!#1#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0 +~~END~~ + + SELECT COUNT(*) FROM sys.all_columns WHERE object_id = object_id('sys.all_views'); GO ~~START~~ diff --git a/test/JDBC/input/views/sys-all_views-vu-verify.sql b/test/JDBC/input/views/sys-all_views-vu-verify.sql index ec2aa9533f..02ab10652f 100644 --- a/test/JDBC/input/views/sys-all_views-vu-verify.sql +++ b/test/JDBC/input/views/sys-all_views-vu-verify.sql @@ -50,5 +50,26 @@ FROM sys.all_views WHERE name = 'sys_all_views_select_chk_option_vu_prepare' GO +-- query a system view +SELECT + name + , principal_id + , type + , type_desc + , create_date + , modify_date + , is_ms_shipped + , is_published + , is_schema_published + , is_replicated + , has_replication_filter + , has_opaque_metadata + , has_unchecked_assembly_data + , with_check_option + , is_date_correlation_view +FROM sys.all_views +WHERE name = 'all_views' +GO + SELECT COUNT(*) FROM sys.all_columns WHERE object_id = object_id('sys.all_views'); GO From 97e8cbe2ca6d3dbbbc2c95fc448be26ec3d4c081 Mon Sep 17 00:00:00 2001 From: Aditya Verma <45755382+aadityavermaa@users.noreply.github.com> Date: Mon, 6 Mar 2023 22:14:27 +0530 Subject: [PATCH 002/363] Do not dump ROWVERSION/TIMESTAMP column values (#1308) ROWVERSION/TIMESTAMP column values should not get dumped by pg_dump, instead these columns should be recomputed in the target cluster. engine repository PR: babelfish-for-postgresql/postgresql_modified_for_babelfish#110 Issues Resolved BABEL-3819 --------- Signed-off-by: Aditya Verma Co-authored-by: Aditya Verma --- .../dump-restore-util/action.yml | 1 - test/JDBC/expected/ISC-Views-vu-verify.out | 4 ++-- test/JDBC/expected/ISC-Views.out | 4 ++-- .../expected/TestRowVersion-vu-cleanup.out | 3 +++ .../expected/TestRowVersion-vu-prepare.out | 16 +++++++++++++++ .../expected/TestRowVersion-vu-verify.out | 20 +++++++++++++++++++ test/JDBC/input/ISC-Views-vu-verify.sql | 2 +- test/JDBC/input/ISC-Views.sql | 2 +- .../datatypes/TestRowVersion-vu-cleanup.sql | 3 +++ .../datatypes/TestRowVersion-vu-prepare.sql | 10 ++++++++++ .../datatypes/TestRowVersion-vu-verify.sql | 6 ++++++ test/JDBC/upgrade/latest/schedule | 1 + 12 files changed, 65 insertions(+), 7 deletions(-) diff --git a/.github/composite-actions/dump-restore-util/action.yml b/.github/composite-actions/dump-restore-util/action.yml index 689c3f908e..53cb5d7f68 100644 --- a/.github/composite-actions/dump-restore-util/action.yml +++ b/.github/composite-actions/dump-restore-util/action.yml @@ -79,7 +79,6 @@ runs: # Temporarily disable certain tests until fixed sed -i "/BABEL-3513/d" test/JDBC/upgrade/$base_dir/schedule sed -i "/BABEL_OBJECT_ID/d" test/JDBC/upgrade/$base_dir/schedule - sed -i "/ISC-Views/d" test/JDBC/upgrade/$base_dir/schedule sed -i "/TestNotNull/d" test/JDBC/upgrade/$base_dir/schedule sed -i "/TestSQLVariant/d" test/JDBC/upgrade/$base_dir/schedule sed -i "/babel_datatype_sqlvariant/d" test/JDBC/upgrade/$base_dir/schedule diff --git a/test/JDBC/expected/ISC-Views-vu-verify.out b/test/JDBC/expected/ISC-Views-vu-verify.out index 76f36d1e1b..67d2fda4ca 100644 --- a/test/JDBC/expected/ISC-Views-vu-verify.out +++ b/test/JDBC/expected/ISC-Views-vu-verify.out @@ -161,7 +161,7 @@ use master go -- Tests for numeric scale and precision -select column_name,numeric_precision, numeric_scale from information_schema.columns where column_name like '_numcol_%'; +select column_name,numeric_precision, numeric_scale from information_schema.columns where column_name like '_numcol_%' order by column_name; GO ~~START~~ nvarchar#!#tinyint#!#int @@ -169,8 +169,8 @@ _numcol_bbf_13d0#!#13#!#0 _numcol_bbf_13n0#!#13#!#0 _numcol_bbf_15d6#!#15#!#6 _numcol_bbf_15n6#!#15#!#6 -_numcol_numeric_test#!#15#!#6 _numcol_decimal_test#!#15#!#6 +_numcol_numeric_test#!#15#!#6 ~~END~~ diff --git a/test/JDBC/expected/ISC-Views.out b/test/JDBC/expected/ISC-Views.out index 27c8c48bd0..9698f00ef4 100644 --- a/test/JDBC/expected/ISC-Views.out +++ b/test/JDBC/expected/ISC-Views.out @@ -378,7 +378,7 @@ GO create table babel_2863(_numcol_bbf_13d0 decimal(13), _numcol_bbf_13n0 numeric(13), _numcol_bbf_15d6 decimal(15,6), _numcol_bbf_15n6 numeric(15,6), _numcol_numeric_test numeric_test, _numcol_decimal_test decimal_test) GO -select column_name,numeric_precision, numeric_scale from information_schema.columns where column_name like '_numcol_%'; +select column_name,numeric_precision, numeric_scale from information_schema.columns where column_name like '_numcol_%' order by column_name; GO ~~START~~ nvarchar#!#tinyint#!#int @@ -386,8 +386,8 @@ _numcol_bbf_13d0#!#13#!#0 _numcol_bbf_13n0#!#13#!#0 _numcol_bbf_15d6#!#15#!#6 _numcol_bbf_15n6#!#15#!#6 -_numcol_numeric_test#!#15#!#6 _numcol_decimal_test#!#15#!#6 +_numcol_numeric_test#!#15#!#6 ~~END~~ diff --git a/test/JDBC/expected/TestRowVersion-vu-cleanup.out b/test/JDBC/expected/TestRowVersion-vu-cleanup.out index 552e9748fa..229f754a20 100644 --- a/test/JDBC/expected/TestRowVersion-vu-cleanup.out +++ b/test/JDBC/expected/TestRowVersion-vu-cleanup.out @@ -41,5 +41,8 @@ go drop table babel_3139_t; go +drop table babel_3819_t; +go + EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_rowversion', 'strict'; go diff --git a/test/JDBC/expected/TestRowVersion-vu-prepare.out b/test/JDBC/expected/TestRowVersion-vu-prepare.out index a6edd7b8ae..07e2ade220 100644 --- a/test/JDBC/expected/TestRowVersion-vu-prepare.out +++ b/test/JDBC/expected/TestRowVersion-vu-prepare.out @@ -128,6 +128,9 @@ go create table babel_3139_t(c1 int, rv rowversion, dbts_after_insert binary(8)); go +CREATE TABLE babel_3819_t(col1 int, timestamp); +GO + begin tran; @@ -152,5 +155,18 @@ go ~~ROW COUNT: 1~~ +begin tran; +insert into babel_3819_t(col1) values(1); +insert into babel_3819_t(col1) values(2); +insert into babel_3819_t(col1) values(3); +commit; +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_rowversion', 'strict'; go diff --git a/test/JDBC/expected/TestRowVersion-vu-verify.out b/test/JDBC/expected/TestRowVersion-vu-verify.out index 2145029b90..2b32d27bf6 100644 --- a/test/JDBC/expected/TestRowVersion-vu-verify.out +++ b/test/JDBC/expected/TestRowVersion-vu-verify.out @@ -185,6 +185,26 @@ increasing ~~END~~ +-- tests for BABEL-3819 +select case when CAST(rv as int) = CAST(CAST(xmin AS varchar) AS int) then 'equal' else 'not-equal' end from babel_3139_t; +go +~~START~~ +text +equal +equal +equal +~~END~~ + + +select case when CAST(timestamp as int) = CAST(CAST(xmin AS varchar) AS int) then 'equal' else 'not-equal' end from babel_3819_t; +go +~~START~~ +text +equal +equal +equal +~~END~~ + EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_rowversion', 'strict'; go diff --git a/test/JDBC/input/ISC-Views-vu-verify.sql b/test/JDBC/input/ISC-Views-vu-verify.sql index 406a514160..7b073f7f91 100644 --- a/test/JDBC/input/ISC-Views-vu-verify.sql +++ b/test/JDBC/input/ISC-Views-vu-verify.sql @@ -59,6 +59,6 @@ use master go -- Tests for numeric scale and precision -select column_name,numeric_precision, numeric_scale from information_schema.columns where column_name like '_numcol_%'; +select column_name,numeric_precision, numeric_scale from information_schema.columns where column_name like '_numcol_%' order by column_name; GO diff --git a/test/JDBC/input/ISC-Views.sql b/test/JDBC/input/ISC-Views.sql index 184bba8187..137bdb2b6e 100644 --- a/test/JDBC/input/ISC-Views.sql +++ b/test/JDBC/input/ISC-Views.sql @@ -249,7 +249,7 @@ GO create table babel_2863(_numcol_bbf_13d0 decimal(13), _numcol_bbf_13n0 numeric(13), _numcol_bbf_15d6 decimal(15,6), _numcol_bbf_15n6 numeric(15,6), _numcol_numeric_test numeric_test, _numcol_decimal_test decimal_test) GO -select column_name,numeric_precision, numeric_scale from information_schema.columns where column_name like '_numcol_%'; +select column_name,numeric_precision, numeric_scale from information_schema.columns where column_name like '_numcol_%' order by column_name; GO drop table babel_2863; diff --git a/test/JDBC/input/datatypes/TestRowVersion-vu-cleanup.sql b/test/JDBC/input/datatypes/TestRowVersion-vu-cleanup.sql index 552e9748fa..229f754a20 100644 --- a/test/JDBC/input/datatypes/TestRowVersion-vu-cleanup.sql +++ b/test/JDBC/input/datatypes/TestRowVersion-vu-cleanup.sql @@ -41,5 +41,8 @@ go drop table babel_3139_t; go +drop table babel_3819_t; +go + EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_rowversion', 'strict'; go diff --git a/test/JDBC/input/datatypes/TestRowVersion-vu-prepare.sql b/test/JDBC/input/datatypes/TestRowVersion-vu-prepare.sql index 6e7aea679b..d3db6c0786 100644 --- a/test/JDBC/input/datatypes/TestRowVersion-vu-prepare.sql +++ b/test/JDBC/input/datatypes/TestRowVersion-vu-prepare.sql @@ -88,6 +88,9 @@ go create table babel_3139_t(c1 int, rv rowversion, dbts_after_insert binary(8)); go +CREATE TABLE babel_3819_t(col1 int, timestamp); +GO + begin tran; insert into babel_3139_t(c1) values(1); update babel_3139_t set dbts_after_insert = @@dbts where c1 = 1; @@ -100,5 +103,12 @@ update babel_3139_t set dbts_after_insert = @@dbts where c1 = 3; commit; go +begin tran; +insert into babel_3819_t(col1) values(1); +insert into babel_3819_t(col1) values(2); +insert into babel_3819_t(col1) values(3); +commit; +go + EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_rowversion', 'strict'; go diff --git a/test/JDBC/input/datatypes/TestRowVersion-vu-verify.sql b/test/JDBC/input/datatypes/TestRowVersion-vu-verify.sql index 16db0b411a..4093b318e7 100644 --- a/test/JDBC/input/datatypes/TestRowVersion-vu-verify.sql +++ b/test/JDBC/input/datatypes/TestRowVersion-vu-verify.sql @@ -100,6 +100,12 @@ select case when dbts_after_insert > prev_dbts then 'increasing' else 'not incre where prev_dbts is not null; go +-- tests for BABEL-3819 +select case when CAST(rv as int) = CAST(CAST(xmin AS varchar) AS int) then 'equal' else 'not-equal' end from babel_3139_t; +go + +select case when CAST(timestamp as int) = CAST(CAST(xmin AS varchar) AS int) then 'equal' else 'not-equal' end from babel_3819_t; +go EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_rowversion', 'strict'; go diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index 0db8e141fb..ef55ec0d3c 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -25,6 +25,7 @@ TestInt TestMoney TestNumeric TestReal +TestRowVersion TestSmallDatetime TestSmallInt TestSmallMoney From a4a99221e67d96440310faee0a38bd1f518843ee Mon Sep 17 00:00:00 2001 From: Kristian Lejao <1741885+lejaokri@users.noreply.github.com> Date: Mon, 6 Mar 2023 15:54:07 -0800 Subject: [PATCH 003/363] dev-tools.sh supporting MVU upgrade tests (#1306) Modified dev-tools.sh to support running MVU test cases manually. - The dev-tools.sh script has been updated to support running MVU (upgrade) testing. - A new parameter has been introduced called TEST_MODE : [normal, prepare, verify]. Executing ./dev-tools.sh without any parameter shows more information. - In order to run the non-MVU tests under input/ directory, the command now becomes ./dev-tools.sh test normal instead of the old way ./dev-tools.sh test input. Signed-off-by: Kristian Lejao --- dev-tools.sh | 70 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 60 insertions(+), 10 deletions(-) diff --git a/dev-tools.sh b/dev-tools.sh index e351a5b455..c2dde81767 100755 --- a/dev-tools.sh +++ b/dev-tools.sh @@ -32,8 +32,11 @@ if [ ! $1 ]; then echo " pg_upgrade SOURCE_WS [TARGET_WS]" echo " run pg_upgrade from SOURCE_WS to TARGET_WS" echo "" - echo " test INPUT_DIR [MIGRATION_MODE]" - echo " run JDBC test, default migration_mode is single-db" + echo " test normal [MIGRATION_MODE] [TEST_BASE_DIR]" + echo " run a normal JDBC test, default migration mode and test dir are single-db and input, respectively" + echo "" + echo " test TEST_MODE MIGRATION_MODE TEST_BASE_DIR" + echo " run a prepare/verify JDBC test using a schedule file in TEST_BASE_DIR" echo "" echo " minor_version_upgrade SOURCE_WS [TARGET_WS]" echo " upgrade minor version using ALTER EXTENSION ... UPDATE" @@ -60,9 +63,32 @@ if [ "$1" == "pg_upgrade" ] || [ "$1" == "minor_version_upgrade" ] || [ "$1" == TARGET_WS=$3 elif [ "$1" == "test" ]; then TARGET_WS=$CUR_WS + TEST_MODE=$2 + if [ ! $TEST_MODE ]; then + echo "Error: TEST_MODE should be specified, normal, prepare or verify" 1>&2 + exit 1 + elif [ "${TEST_MODE}" != "normal" ] && [ "${TEST_MODE}" != "prepare" ] && [ "${TEST_MODE}" != "verify" ]; then + echo "Error: TEST_MODE should be one of: normal, prepare or verify" 1>&2 + exit 1 + fi + MIGRATION_MODE=$3 - if [ ! $MIGRATION_MODE ]; then - MIGRATION_MODE="single-db" + if [ ! ${MIGRATION_MODE} ]; then + if [ "${TEST_MODE?}" == "normal" ]; then + MIGRATION_MODE="single-db" + else + echo "Error: MIGRATION_MODE should be specified, single-db or multi-db" 1>&2 + exit 1 + fi + fi + + TEST_BASE_DIR=$4 + if [ ! $TEST_BASE_DIR ]; then + if [ "${TEST_MODE?}" == "normal" ]; then + TEST_BASE_DIR="input" + else + echo "Error: TEST_BASE_DIR should be specified" 1>&2 + fi fi fi if [ ! $TARGET_WS ]; then @@ -211,8 +237,6 @@ elif [ "$1" == "pg_upgrade" ]; then cd $TARGET_WS if [ ! -d "./upgrade" ]; then mkdir upgrade - else - rm upgrade/* fi cd upgrade ../postgres/bin/pg_upgrade -U $USER \ @@ -235,18 +259,44 @@ elif [ "$1" == "pg_upgrade" ]; then "SELECT pg_reload_conf();" exit 0 elif [ "$1" == "test" ]; then - INPUT_DIR=$2 - cd $TARGET_WS/postgres + # Set migration_mode + cd $TARGET_WS/postgres bin/psql -d $TEST_DB -U $USER -c \ "ALTER SYSTEM SET babelfishpg_tsql.migration_mode = '$MIGRATION_MODE';" bin/psql -d $TEST_DB -U $USER -c \ "SELECT pg_reload_conf();" + # Remove output directory cd $CUR_WS/babelfish_extensions/test/JDBC - rm -rf output - export inputFilesPath=$INPUT_DIR + rm -rf output temp_schedule + + export inputFilesPath=input + if [ "$TEST_MODE" == "normal" ]; then + export inputFilesPath=${TEST_BASE_DIR?} + elif [ "$TEST_MODE" == "prepare" ]; then + for filename in $(grep -v "^ignore.*\|^#.*\|^cmd.*\|^all.*\|^$" $TEST_BASE_DIR/schedule); do + if [[ ! ($(find input/ -name $filename"-vu-prepare.*") || $(find input/ -name $filename"-vu-verify.*")) ]]; then + printf '%s\n' "ERROR: Cannot find Test file "$filename"-vu-prepare or "$filename"-vu-verify in input directory !!" >&2 + exit 1 + fi + done + cat $TEST_BASE_DIR/schedule > temp_schedule + for filename in $(grep -v "^ignore.*\|^#.*\|^cmd.*\|^all.*\|^$" temp_schedule); do + sed -i "s/$filename[ ]*$/$filename-vu-prepare/g" temp_schedule + done + export scheduleFile=temp_schedule + elif [ "$TEST_MODE" == "verify" ]; then + for filename in $(grep -v "^ignore.*\|^#.*\|^cmd.*\|^all.*\|^$" $TEST_BASE_DIR/schedule); do + trimmed=$(awk '{$1=$1;print}' <<< "$filename") + echo $trimmed-vu-verify >> temp_schedule; + echo $trimmed-vu-cleanup >> temp_schedule; + done + export scheduleFile=temp_schedule + fi + mvn test + rm -rf temp_schedule exit 0 elif [ "$1" == "minor_version_upgrade" ]; then echo "Building from $SOURCE_WS..." From 78b7570640aa1c4d0aa23ea35a01f20d193d16d6 Mon Sep 17 00:00:00 2001 From: ZhenyeLee <73271404+ZhenyeLee@users.noreply.github.com> Date: Tue, 7 Mar 2023 11:35:04 -0800 Subject: [PATCH 004/363] Make DATETIME accepted DATETIME2(7) parameter (#1277) * Make DATETIME accepted DATETIME2(7) parameter Before this PR, DATETIME not accepted for DATETIME2(7) parameter and BABELFISH throws error datetime2(7) precision must be between 0 and 6. In our code, we use MAX_TIMESTAMP_PRECISION as 6 as the same as engine side, but DATETIME2 should accept 7 when doing scale. In this PR, we reuse constant value MAX_DATETIME2_PRECISION as 7 in order to let DATETIME accepted DATETIME2(7) parameter. --------- Signed-off-by: Zhenye Li Co-authored-by: Zhenye Li --- contrib/babelfishpg_common/src/datetime2.c | 13 +++++--- test/JDBC/expected/BABEL-2934.out | 36 ++++++++++++++++++++++ test/JDBC/input/BABEL-2934.sql | 26 ++++++++++++++++ 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/contrib/babelfishpg_common/src/datetime2.c b/contrib/babelfishpg_common/src/datetime2.c index 268d69c046..3dc12e8137 100644 --- a/contrib/babelfishpg_common/src/datetime2.c +++ b/contrib/babelfishpg_common/src/datetime2.c @@ -154,34 +154,37 @@ datetime2_in(PG_FUNCTION_ARGS) static void AdjustDatetime2ForTypmod(Timestamp *time, int32 typmod) { - static const int64 TimestampScales[MAX_TIMESTAMP_PRECISION + 1] = { + static const int64 TimestampScales[MAX_DATETIME2_PRECISION + 1] = { INT64CONST(1000000), INT64CONST(100000), INT64CONST(10000), INT64CONST(1000), INT64CONST(100), INT64CONST(10), + INT64CONST(1), INT64CONST(1) }; - static const int64 TimestampOffsets[MAX_TIMESTAMP_PRECISION + 1] = { + static const int64 TimestampOffsets[MAX_DATETIME2_PRECISION + 1] = { INT64CONST(500000), INT64CONST(50000), INT64CONST(5000), INT64CONST(500), INT64CONST(50), INT64CONST(5), + INT64CONST(0), INT64CONST(0) }; /* new offset for negative timestamp value */ - static const int64 TimestampOffsetsNegative[MAX_TIMESTAMP_PRECISION + 1] = { + static const int64 TimestampOffsetsNegative[MAX_DATETIME2_PRECISION + 1] = { INT64CONST(499999), INT64CONST(49999), INT64CONST(4999), INT64CONST(499), INT64CONST(49), INT64CONST(4), + INT64CONST(0), INT64CONST(0) }; @@ -190,11 +193,11 @@ AdjustDatetime2ForTypmod(Timestamp *time, int32 typmod) if (!TIMESTAMP_NOT_FINITE(*time) && (typmod != -1)) { - if (typmod < 0 || typmod > MAX_TIMESTAMP_PRECISION) + if (typmod < 0 || typmod > MAX_DATETIME2_PRECISION) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("datetime2(%d) precision must be between %d and %d", - typmod, 0, MAX_TIMESTAMP_PRECISION))); + typmod, 0, MAX_DATETIME2_PRECISION))); if (*time >= INT64CONST(0)) { diff --git a/test/JDBC/expected/BABEL-2934.out b/test/JDBC/expected/BABEL-2934.out index 6343e76540..b967eb8252 100644 --- a/test/JDBC/expected/BABEL-2934.out +++ b/test/JDBC/expected/BABEL-2934.out @@ -89,3 +89,39 @@ time 12:15:04.123457 ~~END~~ + +-- BABEL-3570 +CREATE FUNCTION BABEL_3570_function (@p datetime2(7)) RETURNS INT +AS +BEGIN +RETURN 0 +END +GO + +SELECT BABEL_3570_function(getdate()) +GO +~~START~~ +int +0 +~~END~~ + + +DECLARE @BABEL_3570_dt datetime = getdate() +SELECT BABEL_3570_function(@BABEL_3570_dt) +GO +~~START~~ +int +0 +~~END~~ + + +CREATE PROC BABEL_3570_proc @p datetime2(7) as print 'pass' +GO + +DECLARE @BABEL_3570_dt datetime = getdate() +EXEC BABEL_3570_proc @BABEL_3570_dt +GO + +DROP FUNCTION BABEL_3570_function +DROP PROC BABEL_3570_proc +GO diff --git a/test/JDBC/input/BABEL-2934.sql b/test/JDBC/input/BABEL-2934.sql index 16508e8398..57ce5295c4 100644 --- a/test/JDBC/input/BABEL-2934.sql +++ b/test/JDBC/input/BABEL-2934.sql @@ -48,3 +48,29 @@ go select cast('12:15:04.1234567' as TIME(7)) go + +-- BABEL-3570 +CREATE FUNCTION BABEL_3570_function (@p datetime2(7)) RETURNS INT +AS +BEGIN +RETURN 0 +END +GO + +SELECT BABEL_3570_function(getdate()) +GO + +DECLARE @BABEL_3570_dt datetime = getdate() +SELECT BABEL_3570_function(@BABEL_3570_dt) +GO + +CREATE PROC BABEL_3570_proc @p datetime2(7) as print 'pass' +GO + +DECLARE @BABEL_3570_dt datetime = getdate() +EXEC BABEL_3570_proc @BABEL_3570_dt +GO + +DROP FUNCTION BABEL_3570_function +DROP PROC BABEL_3570_proc +GO From 6b74658edc41ec7eabf5aafb9c9dbef5273df029 Mon Sep 17 00:00:00 2001 From: Jake Owen Date: Thu, 9 Mar 2023 15:09:35 -0500 Subject: [PATCH 005/363] JSON_MODIFY() does not properly handle JSON_QUERY, SELECT FOR JSON, or JSON_MODIFY inputs (#1295) Currently Babelfish does not properly handle the JSON_MODIFY function when the new value parameter is JSON_QUERY, SELECT FOR JSON, or JSON MODIFY. This change adds support to correctly handle these cases. Task: Babel-3696 Author: Jacob Owen --- .../babelfishpg_tsql/sql/sys_functions.sql | 21 ++- .../babelfishpg_tsql--3.1.0--3.2.0.sql | 160 ++++++++++++++++++ .../src/backend_parser/gram-tsql-decl.y | 2 +- .../src/backend_parser/gram-tsql-epilogue.y.c | 50 ++++++ .../src/backend_parser/gram-tsql-prologue.y.h | 3 + .../src/backend_parser/gram-tsql-rule.y | 7 +- .../src/backend_parser/kwlist.h | 1 + contrib/babelfishpg_tsql/src/multidb.c | 144 ++++++++++++++++ contrib/babelfishpg_tsql/src/multidb.h | 1 + test/JDBC/expected/BABEL-3696-vu-cleanup.out | 35 ++++ test/JDBC/expected/BABEL-3696-vu-prepare.out | 82 +++++++++ test/JDBC/expected/BABEL-3696-vu-verify.out | 88 ++++++++++ .../json_modify/BABEL-3696-vu-cleanup.sql | 35 ++++ .../json_modify/BABEL-3696-vu-prepare.sql | 80 +++++++++ .../json_modify/BABEL-3696-vu-verify.sql | 32 ++++ .../BABEL-937-vu-cleanup.sql | 0 .../BABEL-937-vu-prepare.sql | 0 .../{ => json_modify}/BABEL-937-vu-verify.sql | 0 test/JDBC/upgrade/latest/schedule | 1 + .../expected_dependency.out | 1 - 20 files changed, 733 insertions(+), 10 deletions(-) create mode 100644 test/JDBC/expected/BABEL-3696-vu-cleanup.out create mode 100644 test/JDBC/expected/BABEL-3696-vu-prepare.out create mode 100644 test/JDBC/expected/BABEL-3696-vu-verify.out create mode 100644 test/JDBC/input/json_modify/BABEL-3696-vu-cleanup.sql create mode 100644 test/JDBC/input/json_modify/BABEL-3696-vu-prepare.sql create mode 100644 test/JDBC/input/json_modify/BABEL-3696-vu-verify.sql rename test/JDBC/input/{ => json_modify}/BABEL-937-vu-cleanup.sql (100%) rename test/JDBC/input/{ => json_modify}/BABEL-937-vu-prepare.sql (100%) rename test/JDBC/input/{ => json_modify}/BABEL-937-vu-verify.sql (100%) diff --git a/contrib/babelfishpg_tsql/sql/sys_functions.sql b/contrib/babelfishpg_tsql/sql/sys_functions.sql index 0417e41e12..a0bceb77d6 100644 --- a/contrib/babelfishpg_tsql/sql/sys_functions.sql +++ b/contrib/babelfishpg_tsql/sql/sys_functions.sql @@ -2823,7 +2823,7 @@ AS 'babelfishpg_tsql', 'tsql_json_query' LANGUAGE C IMMUTABLE PARALLEL SAFE; * 2) To convert the input path into the expected jsonb_path. * 3) To implement the main logic of the JSON_MODIFY function by dividing it into 8 different cases. */ -CREATE OR REPLACE FUNCTION sys.json_modify(in expression sys.NVARCHAR,in path_json TEXT, in new_value TEXT) +CREATE OR REPLACE FUNCTION sys.json_modify(in expression sys.NVARCHAR,in path_json TEXT, in new_value TEXT, in escape bool) RETURNS sys.NVARCHAR AS $BODY$ @@ -2841,6 +2841,7 @@ DECLARE key_exists BOOL; key_value JSONB; json_expression JSONB = expression::JSONB; + json_new_value JSONB; result_json sys.NVARCHAR; BEGIN path_split_array = regexp_split_to_array(TRIM(path_json) COLLATE "C",'\s+'); @@ -2893,7 +2894,13 @@ BEGIN new_jsonb_path = CONCAT('{',json_path_convert,'}'); -- Final required format of path by jsonb_set key_exists = jsonb_path_exists(json_expression,json_path::jsonpath); -- To check if key exist in the given path - + + IF escape THEN + json_new_value = new_value::JSONB; + ELSE + json_new_value = to_jsonb(new_value); + END IF; + --This if else block is to call the jsonb_set function based on the create_if_missing and append_modifier flags IF append_modifier THEN IF key_exists THEN @@ -2909,7 +2916,7 @@ BEGIN IF new_value IS NULL THEN result_json = jsonb_insert(json_expression,new_jsonb_path,'null'); -- This needs to be done because "to_jsonb(coalesce(new_value, 'null'))" does not result in a JSON NULL ELSE - result_json = jsonb_insert(json_expression,new_jsonb_path,to_jsonb(new_value)); + result_json = jsonb_insert(json_expression,new_jsonb_path,json_new_value); END IF; ELSE IF NOT create_if_missing THEN @@ -2928,22 +2935,22 @@ BEGIN ELSE --When no append modifier is present IF new_value IS NOT NULL THEN IF key_exists OR create_if_missing THEN - result_json = jsonb_set_lax(json_expression,new_jsonb_path,to_jsonb(new_value),create_if_missing); + result_json = jsonb_set_lax(json_expression,new_jsonb_path,json_new_value,create_if_missing); ELSE RAISE sql_json_object_not_found; END IF; ELSE IF key_exists THEN IF NOT create_if_missing THEN - result_json = jsonb_set_lax(json_expression,new_jsonb_path,to_jsonb(new_value)); + result_json = jsonb_set_lax(json_expression,new_jsonb_path,json_new_value); ELSE - result_json = jsonb_set_lax(json_expression,new_jsonb_path,to_jsonb(new_value),create_if_missing,'delete_key'); + result_json = jsonb_set_lax(json_expression,new_jsonb_path,json_new_value,create_if_missing,'delete_key'); END IF; ELSE IF NOT create_if_missing THEN RAISE sql_json_object_not_found; ELSE - result_json = jsonb_set_lax(json_expression,new_jsonb_path,to_jsonb(new_value),FALSE); + result_json = jsonb_set_lax(json_expression,new_jsonb_path,json_new_value,FALSE); END IF; END IF; END IF; diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql index 9c67eac604..e9130216bf 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql @@ -70,6 +70,166 @@ LANGUAGE C VOLATILE; SELECT sys.pg_extension_config_remove('sys.babelfish_configurations'); +ALTER FUNCTION sys.json_modify RENAME TO json_modify_deprecated_in_3_2_0; + +CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'json_modify_deprecated_in_3_2_0'); + +/* + * JSON MODIFY + * This function is used to update the value of a property in a JSON string and returns the updated JSON string. + * It has been implemented in three parts: + * 1) Set the append and create_if_missing flag as postgres functions do not directly take append and lax/strict mode in the jsonb_path. + * 2) To convert the input path into the expected jsonb_path. + * 3) To implement the main logic of the JSON_MODIFY function by dividing it into 8 different cases. + */ +CREATE OR REPLACE FUNCTION sys.json_modify(in expression sys.NVARCHAR,in path_json TEXT, in new_value TEXT, in escape bool) +RETURNS sys.NVARCHAR +AS +$BODY$ +DECLARE + json_path TEXT; + json_path_convert TEXT; + new_jsonb_path TEXT[]; + key_value_type TEXT; + path_split_array TEXT[]; + comparison_string TEXT COLLATE "C"; + len_array INTEGER; + word_count INTEGER; + create_if_missing BOOL = TRUE; + append_modifier BOOL = FALSE; + key_exists BOOL; + key_value JSONB; + json_expression JSONB = expression::JSONB; + json_new_value JSONB; + result_json sys.NVARCHAR; +BEGIN + path_split_array = regexp_split_to_array(TRIM(path_json) COLLATE "C",'\s+'); + word_count = array_length(path_split_array,1); + /* + * This if else block is added to set the create_if_missing and append_modifier flags. + * These flags will be used to know the mode and if the optional modifier append is present in the input path_json. + * It is necessary as postgres functions do not directly take append and lax/strict mode in the jsonb_path. + * Comparisons for comparison_string are case-sensitive. + */ + IF word_count = 1 THEN + json_path = path_split_array[1]; + create_if_missing = TRUE; + append_modifier = FALSE; + ELSIF word_count = 2 THEN + json_path = path_split_array[2]; + comparison_string = path_split_array[1]; -- append or lax/strict mode + IF comparison_string = 'append' THEN + append_modifier = TRUE; + ELSIF comparison_string = 'strict' THEN + create_if_missing = FALSE; + ELSIF comparison_string = 'lax' THEN + create_if_missing = TRUE; + ELSE + RAISE invalid_json_text; + END IF; + ELSIF word_count = 3 THEN + json_path = path_split_array[3]; + comparison_string = path_split_array[1]; -- append mode + IF comparison_string = 'append' THEN + append_modifier = TRUE; + ELSE + RAISE invalid_json_text; + END IF; + comparison_string = path_split_array[2]; -- lax/strict mode + IF comparison_string = 'strict' THEN + create_if_missing = FALSE; + ELSIF comparison_string = 'lax' THEN + create_if_missing = TRUE; + ELSE + RAISE invalid_json_text; + END IF; + ELSE + RAISE invalid_json_text; + END IF; + + -- To convert input jsonpath to the required jsonb_path format + json_path_convert = regexp_replace(json_path, '\$\.|]|\$\[' , '' , 'ig'); -- To remove "$." and "]" sign from the string + json_path_convert = regexp_replace(json_path_convert, '\.|\[' , ',' , 'ig'); -- To replace "." and "[" with "," to change into required format + new_jsonb_path = CONCAT('{',json_path_convert,'}'); -- Final required format of path by jsonb_set + + key_exists = jsonb_path_exists(json_expression,json_path::jsonpath); -- To check if key exist in the given path + + IF escape THEN + json_new_value = new_value::JSONB; + ELSE + json_new_value = to_jsonb(new_value); + END IF; + + --This if else block is to call the jsonb_set function based on the create_if_missing and append_modifier flags + IF append_modifier THEN + IF key_exists THEN + key_value = jsonb_path_query_first(json_expression,json_path::jsonpath); -- To get the value of the key + key_value_type = jsonb_typeof(key_value); + IF key_value_type = 'array' THEN + len_array = jsonb_array_length(key_value); + /* + * As jsonb_insert requires the index of the value to be inserted, so the below FORMAT function changes the path format into the required jsonb_insert path format. + * Eg: JSON_MODIFY('{"name":"John","skills":["C#","SQL"]}','append $.skills','Azure'); -> converts the path from '$.skills' to '{skills,2}' instead of '{skills}' + */ + new_jsonb_path = FORMAT('%s,%s}',TRIM('}' FROM new_jsonb_path::TEXT),len_array); + IF new_value IS NULL THEN + result_json = jsonb_insert(json_expression,new_jsonb_path,'null'); -- This needs to be done because "to_jsonb(coalesce(new_value, 'null'))" does not result in a JSON NULL + ELSE + result_json = jsonb_insert(json_expression,new_jsonb_path,json_new_value); + END IF; + ELSE + IF NOT create_if_missing THEN + RAISE sql_json_array_not_found; + ELSE + result_json = json_expression; + END IF; + END IF; + ELSE + IF NOT create_if_missing THEN + RAISE sql_json_object_not_found; + ELSE + result_json = jsonb_insert(json_expression,new_jsonb_path,to_jsonb(array_agg(new_value))); -- array_agg is used to convert the new_value text into array format as we append functionality is being used + END IF; + END IF; + ELSE --When no append modifier is present + IF new_value IS NOT NULL THEN + IF key_exists OR create_if_missing THEN + result_json = jsonb_set_lax(json_expression,new_jsonb_path,json_new_value,create_if_missing); + ELSE + RAISE sql_json_object_not_found; + END IF; + ELSE + IF key_exists THEN + IF NOT create_if_missing THEN + result_json = jsonb_set_lax(json_expression,new_jsonb_path,json_new_value); + ELSE + result_json = jsonb_set_lax(json_expression,new_jsonb_path,json_new_value,create_if_missing,'delete_key'); + END IF; + ELSE + IF NOT create_if_missing THEN + RAISE sql_json_object_not_found; + ELSE + result_json = jsonb_set_lax(json_expression,new_jsonb_path,json_new_value,FALSE); + END IF; + END IF; + END IF; + END IF; -- If append_modifier block ends here + RETURN result_json; +EXCEPTION + WHEN invalid_json_text THEN + RAISE USING MESSAGE = 'JSON path is not properly formatted', + DETAIL = FORMAT('Unexpected keyword "%s" is found.',comparison_string), + HINT = 'Change "modifier/mode" parameter to the proper value and try again.'; + WHEN sql_json_array_not_found THEN + RAISE USING MESSAGE = 'array cannot be found in the specified JSON path', + HINT = 'Change JSON path to target array property and try again.'; + WHEN sql_json_object_not_found THEN + RAISE USING MESSAGE = 'property cannot be found on the specified JSON path'; +END; +$BODY$ +LANGUAGE plpgsql STABLE; + + -- Drops the temporary procedure used by the upgrade script. -- Please have this be one of the last statements executed in this upgrade script. DROP PROCEDURE sys.babelfish_drop_deprecated_object(varchar, varchar, varchar); diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-decl.y b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-decl.y index c414483b55..7521076041 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-decl.y +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-decl.y @@ -107,7 +107,7 @@ TSQL_NOCHECK TSQL_NOLOCK TSQL_READUNCOMMITTED TSQL_UPDLOCK TSQL_REPEATABLEREAD TSQL_READCOMMITTED TSQL_TABLOCK TSQL_TABLOCKX TSQL_PAGLOCK TSQL_ROWLOCK TSQL_TOP TSQL_PERCENT - TSQL_AUTO TSQL_EXPLICIT TSQL_RAW TSQL_PATH TSQL_FOR TSQL_BASE64 TSQL_ROOT TSQL_READPAST TSQL_XLOCK TSQL_NOEXPAND OPENJSON + TSQL_AUTO TSQL_EXPLICIT TSQL_RAW TSQL_PATH TSQL_FOR TSQL_BASE64 TSQL_ROOT TSQL_READPAST TSQL_XLOCK TSQL_NOEXPAND OPENJSON JSON_MODIFY TSQL_JSON TSQL_INCLUDE_NULL_VALUES TSQL_WITHOUT_ARRAY_WRAPPER TSQL_MEMBER TSQL_SERVER TSQL_WINDOWS TSQL_CERTIFICATE TSQL_DEFAULT_DATABASE TSQL_DEFAULT_LANGUAGE TSQL_HASHED diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c index fe8032290d..f16bf47657 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c @@ -590,6 +590,56 @@ int getElemTypMod(TypeName *t) } } +/* + * TsqlJsonModifyMakeFuncCall checks if the new value argument for json_modify is + * a json_modify or json_query function call. If it is one of these two arguments it + * sets the escape parameter to true + */ +Node* +TsqlJsonModifyMakeFuncCall(Node* expr, Node* path, Node* newValue) +{ + FuncCall* fc; + List* func_args = list_make3(expr, path, newValue); + bool escape = false; + if(IsA(newValue, FuncCall)) + { + FuncCall* fc_newval = (FuncCall*) newValue; + if(is_json_modify(fc_newval->funcname) || is_json_query(fc_newval->funcname)) + { + escape = true; + } + } + func_args = lappend(func_args, makeBoolAConst(escape, -1)); + fc = makeFuncCall(TsqlSystemFuncName("json_modify"), func_args, COERCE_EXPLICIT_CALL, -1); + return (Node*) fc; +} + +bool +is_json_query(List *name) +{ + switch(list_length(name)) + { + case 1: + { + Node *func = (Node *) linitial(name); + if(strncmp("json_query", strVal(func), 10) == 0) + return true; + return false; + } + case 2: + { + Node *schema = (Node *) linitial(name); + Node *func = (Node *) lsecond(name); + if(strncmp("sys", strVal(schema), 3) == 0 && + strncmp("json_query", strVal(func), 10) == 0) + return true; + return false; + } + default: + return false; + } +} + /* * helper macro to compare relname in * function tsql_update_delete_stmt_with_join diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-prologue.y.h b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-prologue.y.h index 00daa6f7ec..0effc69038 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-prologue.y.h +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-prologue.y.h @@ -58,6 +58,9 @@ static TypeName* setCharTypmodForOpenjson(TypeName *t); static bool isCharType(char* typenameStr); static bool isNVarCharType(char* typenameStr); +static Node *TsqlJsonModifyMakeFuncCall(Node* expr, Node* path, Node* newValue); +static bool is_json_query(List *name); + char * construct_unique_index_name(char *index_name, char *relation_name); static Node *tsql_update_delete_stmt_with_join(Node *n, List* from_clause, Node* diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y index 8e1703e518..b7d17e68d2 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y @@ -1889,7 +1889,11 @@ func_expr_common_subexpr: | TSQL_ATAT LANGUAGE { $$ = (Node *) makeFuncCall(TsqlSystemFuncName2("language"),NIL, COERCE_EXPLICIT_CALL, @1); - } + } + | JSON_MODIFY '(' a_expr ',' a_expr ',' a_expr ')' + { + $$ = (Node *) TsqlJsonModifyMakeFuncCall($3, $5, $7); + } ; target_el: @@ -4261,6 +4265,7 @@ createdb_opt_item: col_name_keyword: TSQL_NVARCHAR | OPENJSON + | JSON_MODIFY ; unreserved_keyword: diff --git a/contrib/babelfishpg_tsql/src/backend_parser/kwlist.h b/contrib/babelfishpg_tsql/src/backend_parser/kwlist.h index 3aad82df71..6c0e09c5f4 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/kwlist.h +++ b/contrib/babelfishpg_tsql/src/backend_parser/kwlist.h @@ -239,6 +239,7 @@ PG_KEYWORD("isowk", TSQL_ISOWK, UNRESERVED_KEYWORD) PG_KEYWORD("isoww", TSQL_ISOWW, UNRESERVED_KEYWORD) PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD) PG_KEYWORD("json", TSQL_JSON, UNRESERVED_KEYWORD) +PG_KEYWORD("json_modify", JSON_MODIFY, COL_NAME_KEYWORD) PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD) PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD) PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD) diff --git a/contrib/babelfishpg_tsql/src/multidb.c b/contrib/babelfishpg_tsql/src/multidb.c index edaa5bcb47..a4fce7d05d 100644 --- a/contrib/babelfishpg_tsql/src/multidb.c +++ b/contrib/babelfishpg_tsql/src/multidb.c @@ -32,6 +32,10 @@ static void rewrite_role_list(List *rolespecs); /* list of RoleSpecs */ static bool rewrite_relation_walker(Node *node, void *context); +static bool is_select_for_json(SelectStmt *stmt); +static void select_json_modify(SelectStmt *stmt); +static bool is_for_json(FuncCall *fc); +static bool get_array_wrapper(List* for_json_args); @@ -69,6 +73,15 @@ rewrite_object_refs(Node *stmt) switch (stmt->type) { case T_SelectStmt: + { + SelectStmt* selectStmt = (SelectStmt*) stmt; + select_json_modify(selectStmt); + /* walker supported stmts */ + raw_expression_tree_walker(stmt, + rewrite_relation_walker, + (void *) NULL); + break; + } case T_UpdateStmt: case T_DeleteStmt: case T_InsertStmt: @@ -667,6 +680,137 @@ rewrite_relation_walker(Node *node, void *context) return raw_expression_tree_walker(node, rewrite_relation_walker, context); } +/* + * select_json_modify takes in a select statement + * If the target is json_modify and the from clause is for json we set the escape + * parameter to true + * Otherwise we set it to false + */ +static void select_json_modify(SelectStmt* stmt) +{ + List* targList = stmt->targetList; + List* fromList = stmt->fromClause; + if(list_length(targList) != 0 && list_length(fromList) != 0) + { + Node* n = linitial(targList); + Node* n_from = linitial(fromList); + if(IsA(n, ResTarget) && IsA(n_from, RangeSubselect)) + { + ResTarget* rt = (ResTarget*) n; + RangeSubselect* rs = (RangeSubselect*) n_from; + if(IsA(rt->val, FuncCall) && IsA(rs->subquery, SelectStmt)) + { + FuncCall* json_mod_fc = (FuncCall*) rt->val; + SelectStmt* from_sel_stmt = (SelectStmt*) rs->subquery; + rewrite_plain_name(json_mod_fc->funcname); + if(is_json_modify(json_mod_fc->funcname) && is_select_for_json(from_sel_stmt)) + { + Node *n = lfourth(json_mod_fc->args); + A_Const *escape = (A_Const*) n; + escape->val.boolval.boolval = true; + } + } + } + } +} + +/* + * is_json_modify takes in a string list and returns true if the list is + * ["json_modify"] or ["sys", "json_modify"] and false otherwise + * It is the caller's responsibility to pass in a list of strings + */ +bool +is_json_modify(List *name) +{ + switch(list_length(name)) + { + case 1: + { + Node *func = (Node *) linitial(name); + if(strncmp("json_modify", strVal(func), 11) == 0) + return true; + return false; + } + case 2: + { + Node *schema = (Node *) linitial(name); + Node *func = (Node *) lsecond(name); + if(strncmp("sys", strVal(schema), 3) == 0 && + strncmp("json_modify", strVal(func), 11) == 0) + return true; + return false; + } + default: + return false; + } +} + +/* + * is_select_for_json takes in a select statement + * returns true if the target function call is for json and array_wrapper is false + * returns false otherwise + */ +static bool is_select_for_json(SelectStmt *stmt) +{ + List* targetList = stmt->targetList; + ListCell* lc = (ListCell*) targetList->elements; + Node* n = lfirst(lc); + if(IsA(n, ResTarget)) + { + ResTarget* rt = (ResTarget*) n; + if(IsA(rt->val, FuncCall)) + { + FuncCall* fc = (FuncCall*) rt->val; + return is_for_json(fc); + } + } + return false; +} + +/* + * is_for_json takes a FuncCall and returns true if the function name is sys.tsql_select_for_json_result + * where the get_array_wrapper parameter is false. This function is specifically used to determine + * how to set the json_modify escape parameter + */ +static bool +is_for_json(FuncCall *fc) +{ + // In this case, we need to check that the function name is correct, and also that the without_array_wrapper param is not true + List* funcname = fc->funcname; + List* fc_args = fc->args; + + switch(list_length(funcname)) + { + case 2: + { + Node *schema = (Node *) linitial(funcname); + Node *func = (Node *) lsecond(funcname); + if(strncmp("sys", strVal(schema), 3) == 0 && + strncmp("tsql_select_for_json_result", strVal(func), 27) == 0) + { + // If without array wrapper is true, we want to keep the escape characters so we return false + return !get_array_wrapper(fc_args); + } + return false; + } + default: + return false; + } +} + +/* + * get_array_wrapper takes the arguments from sys.tsql_select_for_json_result function call + * and returns the value of the array_wrapper parameter. It is the caller's responsibility + * to ensure they are passing the correct input + */ +static bool get_array_wrapper(List* for_json_args) { + FuncCall* agg_fc = (FuncCall *) linitial(for_json_args); + List* agg_fc_args = agg_fc->args; + + Node* arr_wrap = lfourth(agg_fc_args); + return ((A_Const*) arr_wrap)->val.boolval.boolval; +} + /************************************************************* * Rewriting Functions *************************************************************/ diff --git a/contrib/babelfishpg_tsql/src/multidb.h b/contrib/babelfishpg_tsql/src/multidb.h index bf9a3ff929..55f78f3f66 100644 --- a/contrib/babelfishpg_tsql/src/multidb.h +++ b/contrib/babelfishpg_tsql/src/multidb.h @@ -29,5 +29,6 @@ extern void truncate_tsql_identifier(char *ident); extern bool physical_schema_name_exists(char *phys_schema_name); extern bool is_builtin_database(const char *dbname); extern bool is_user_database_singledb(const char *dbname); +extern bool is_json_modify(List *name); #endif diff --git a/test/JDBC/expected/BABEL-3696-vu-cleanup.out b/test/JDBC/expected/BABEL-3696-vu-cleanup.out new file mode 100644 index 0000000000..a23e01a771 --- /dev/null +++ b/test/JDBC/expected/BABEL-3696-vu-cleanup.out @@ -0,0 +1,35 @@ +DROP VIEW babel_3696_1 +GO + +DROP VIEW babel_3696_2 +GO + +DROP VIEW babel_3696_3 +GO + +DROP VIEW babel_3696_4 +GO + +DROP VIEW babel_3696_5 +GO + +DROP VIEW babel_3696_6 +GO + +DROP VIEW babel_3696_7 +GO + +DROP VIEW babel_3696_8 +GO + +DROP TABLE t1 +GO + +DROP VIEW babel_3696_9 +GO + +DROP PROCEDURE babel_3696_10 +GO + +DROP PROCEDURE babel_3696_11 +GO diff --git a/test/JDBC/expected/BABEL-3696-vu-prepare.out b/test/JDBC/expected/BABEL-3696-vu-prepare.out new file mode 100644 index 0000000000..41fef7608b --- /dev/null +++ b/test/JDBC/expected/BABEL-3696-vu-prepare.out @@ -0,0 +1,82 @@ +create view babel_3696_1 as +SELECT json_modify('{"Brand":"HP","Product":"Laptop","Accessories":["Keyboard","Mouse","Monitor"]}', '$.Accessories', JSON_QUERY('["Mouse","Monitor"]')) +go + +create view babel_3696_2 as +SELECT json_modify('{"Brand":"HP","Product":"Laptop"}', '$.Accessories', JSON_Query('["Keyboard","Mouse","Monitor"]')) +go + +create view babel_3696_3 as +select JSON_MODIFY(JSON_MODIFY('{"Brand":"HP","Product":"Laptop"}', '$.Parts', JSON_VALUE('{"Brand":"HP","Product":"Laptop"}','$.Product')), '$.Product',NULL) +go + +create view babel_3696_4 as +select JSON_MODIFY(JSON_MODIFY('{"Brand":"HP","Product":"Laptop","Accessories":["Keyboard","Mouse","Monitor"]}', '$.Accessories', JSON_QUERY('["HDMI","USB"]')), '$.Brand', 'Lenovo') +go + + +create view babel_3696_5 as +select JSON_MODIFY('{"name":"John","skills":["C#","SQL"]}','$.skills',JSON_QUERY('["C#","T-SQL","Azure"]')) +go + + +create table t1 (x nvarchar(20)) +insert into t1 values ('some string') +go +~~ROW COUNT: 1~~ + + +create view babel_3696_6 as +select json_modify('{"a":"b"}', '$.a', x) from (select * from t1 for json path) a ([x]) +go + +create view babel_3696_7 as +select json_modify('{"a":"b"}', '$.a', x) from (select * from t1 for json path, without_array_wrapper) a ([x]) +go + +create view babel_3696_8 as +select json_modify('{"a":"b"}', '$.a', json_modify('{"a":"b"}', '$.a', 'c')) +go + + +create view babel_3696_9 as +select json_modify('{"a":"b"}', '$.a', json_modify('{"a":"b"}', 'STRICT $.a', 'c')) +go + +create procedure babel_3696_10 +as +begin +DECLARE @data NVARCHAR(4000) +SET @data=N'{ + "Suspect": { + "Name": "Homer Simpson", + "Address": { + "City": "Dunedin", + "Region": "Otago", + "Country": "New Zealand" + }, + "Hobbies": ["Eating", "Sleeping", "Base Jumping"] + } + }' +select JSON_MODIFY(@data,'$.Suspect.Address.City', 'Timaru') AS 'Modified Array'; +end; +go + +create procedure babel_3696_11 +as +begin +DECLARE @data NVARCHAR(4000) +SET @data=N'{ + "Suspect": { + "Name": "Homer Simpson", + "Address": { + "City": "Dunedin", + "Region": "Otago", + "Country": "New Zealand" + }, + "Hobbies": ["Eating", "Sleeping", "Base Jumping"] + } + }' +select JSON_MODIFY(@data,'$.Suspect.Hobbies', JSON_QUERY('["Chess", "Brain Surgery"]')) AS 'Updated Hobbies'; +end; +go diff --git a/test/JDBC/expected/BABEL-3696-vu-verify.out b/test/JDBC/expected/BABEL-3696-vu-verify.out new file mode 100644 index 0000000000..e18207aa73 --- /dev/null +++ b/test/JDBC/expected/BABEL-3696-vu-verify.out @@ -0,0 +1,88 @@ +SELECT * FROM babel_3696_1 +GO +~~START~~ +nvarchar +{"Brand": "HP", "Product": "Laptop", "Accessories": ["Mouse", "Monitor"]} +~~END~~ + + +SELECT * FROM babel_3696_2 +GO +~~START~~ +nvarchar +{"Brand": "HP", "Product": "Laptop", "Accessories": ["Keyboard", "Mouse", "Monitor"]} +~~END~~ + + +SELECT * FROM babel_3696_3 +GO +~~START~~ +nvarchar +{"Brand": "HP", "Parts": "Laptop"} +~~END~~ + + +SELECT * FROM babel_3696_4 +GO +~~START~~ +nvarchar +{"Brand": "Lenovo", "Product": "Laptop", "Accessories": ["HDMI", "USB"]} +~~END~~ + + +SELECT * FROM babel_3696_5 +GO +~~START~~ +nvarchar +{"name": "John", "skills": ["C#", "T-SQL", "Azure"]} +~~END~~ + + +SELECT * FROM babel_3696_6 +GO +~~START~~ +nvarchar +{"a": [{"x": "some string"}]} +~~END~~ + + +SELECT * FROM babel_3696_7 +GO +~~START~~ +nvarchar +{"a": "{\"x\":\"some string\"}"} +~~END~~ + + +SELECT * FROM babel_3696_8 +GO +~~START~~ +nvarchar +{"a": {"a": "c"}} +~~END~~ + + +SELECT * FROM babel_3696_9 +GO +~~START~~ +nvarchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: JSON path is not properly formatted)~~ + + +EXEC babel_3696_10 +GO +~~START~~ +nvarchar +{"Suspect": {"Name": "Homer Simpson", "Address": {"City": "Timaru", "Region": "Otago", "Country": "New Zealand"}, "Hobbies": ["Eating", "Sleeping", "Base Jumping"]}} +~~END~~ + + +EXEC babel_3696_11 +GO +~~START~~ +nvarchar +{"Suspect": {"Name": "Homer Simpson", "Address": {"City": "Dunedin", "Region": "Otago", "Country": "New Zealand"}, "Hobbies": ["Chess", "Brain Surgery"]}} +~~END~~ + diff --git a/test/JDBC/input/json_modify/BABEL-3696-vu-cleanup.sql b/test/JDBC/input/json_modify/BABEL-3696-vu-cleanup.sql new file mode 100644 index 0000000000..a23e01a771 --- /dev/null +++ b/test/JDBC/input/json_modify/BABEL-3696-vu-cleanup.sql @@ -0,0 +1,35 @@ +DROP VIEW babel_3696_1 +GO + +DROP VIEW babel_3696_2 +GO + +DROP VIEW babel_3696_3 +GO + +DROP VIEW babel_3696_4 +GO + +DROP VIEW babel_3696_5 +GO + +DROP VIEW babel_3696_6 +GO + +DROP VIEW babel_3696_7 +GO + +DROP VIEW babel_3696_8 +GO + +DROP TABLE t1 +GO + +DROP VIEW babel_3696_9 +GO + +DROP PROCEDURE babel_3696_10 +GO + +DROP PROCEDURE babel_3696_11 +GO diff --git a/test/JDBC/input/json_modify/BABEL-3696-vu-prepare.sql b/test/JDBC/input/json_modify/BABEL-3696-vu-prepare.sql new file mode 100644 index 0000000000..f7526d46a8 --- /dev/null +++ b/test/JDBC/input/json_modify/BABEL-3696-vu-prepare.sql @@ -0,0 +1,80 @@ +create view babel_3696_1 as +SELECT json_modify('{"Brand":"HP","Product":"Laptop","Accessories":["Keyboard","Mouse","Monitor"]}', '$.Accessories', JSON_QUERY('["Mouse","Monitor"]')) +go + +create view babel_3696_2 as +SELECT json_modify('{"Brand":"HP","Product":"Laptop"}', '$.Accessories', JSON_Query('["Keyboard","Mouse","Monitor"]')) +go + +create view babel_3696_3 as +select JSON_MODIFY(JSON_MODIFY('{"Brand":"HP","Product":"Laptop"}', '$.Parts', JSON_VALUE('{"Brand":"HP","Product":"Laptop"}','$.Product')), '$.Product',NULL) +go + +create view babel_3696_4 as +select JSON_MODIFY(JSON_MODIFY('{"Brand":"HP","Product":"Laptop","Accessories":["Keyboard","Mouse","Monitor"]}', '$.Accessories', JSON_QUERY('["HDMI","USB"]')), '$.Brand', 'Lenovo') +go + + +create view babel_3696_5 as +select JSON_MODIFY('{"name":"John","skills":["C#","SQL"]}','$.skills',JSON_QUERY('["C#","T-SQL","Azure"]')) +go + + +create table t1 (x nvarchar(20)) +insert into t1 values ('some string') +go + +create view babel_3696_6 as +select json_modify('{"a":"b"}', '$.a', x) from (select * from t1 for json path) a ([x]) +go + +create view babel_3696_7 as +select json_modify('{"a":"b"}', '$.a', x) from (select * from t1 for json path, without_array_wrapper) a ([x]) +go + +create view babel_3696_8 as +select json_modify('{"a":"b"}', '$.a', json_modify('{"a":"b"}', '$.a', 'c')) +go + + +create view babel_3696_9 as +select json_modify('{"a":"b"}', '$.a', json_modify('{"a":"b"}', 'STRICT $.a', 'c')) +go + +create procedure babel_3696_10 +as +begin +DECLARE @data NVARCHAR(4000) +SET @data=N'{ + "Suspect": { + "Name": "Homer Simpson", + "Address": { + "City": "Dunedin", + "Region": "Otago", + "Country": "New Zealand" + }, + "Hobbies": ["Eating", "Sleeping", "Base Jumping"] + } + }' +select JSON_MODIFY(@data,'$.Suspect.Address.City', 'Timaru') AS 'Modified Array'; +end; +go + +create procedure babel_3696_11 +as +begin +DECLARE @data NVARCHAR(4000) +SET @data=N'{ + "Suspect": { + "Name": "Homer Simpson", + "Address": { + "City": "Dunedin", + "Region": "Otago", + "Country": "New Zealand" + }, + "Hobbies": ["Eating", "Sleeping", "Base Jumping"] + } + }' +select JSON_MODIFY(@data,'$.Suspect.Hobbies', JSON_QUERY('["Chess", "Brain Surgery"]')) AS 'Updated Hobbies'; +end; +go diff --git a/test/JDBC/input/json_modify/BABEL-3696-vu-verify.sql b/test/JDBC/input/json_modify/BABEL-3696-vu-verify.sql new file mode 100644 index 0000000000..ad7ea30a3d --- /dev/null +++ b/test/JDBC/input/json_modify/BABEL-3696-vu-verify.sql @@ -0,0 +1,32 @@ +SELECT * FROM babel_3696_1 +GO + +SELECT * FROM babel_3696_2 +GO + +SELECT * FROM babel_3696_3 +GO + +SELECT * FROM babel_3696_4 +GO + +SELECT * FROM babel_3696_5 +GO + +SELECT * FROM babel_3696_6 +GO + +SELECT * FROM babel_3696_7 +GO + +SELECT * FROM babel_3696_8 +GO + +SELECT * FROM babel_3696_9 +GO + +EXEC babel_3696_10 +GO + +EXEC babel_3696_11 +GO diff --git a/test/JDBC/input/BABEL-937-vu-cleanup.sql b/test/JDBC/input/json_modify/BABEL-937-vu-cleanup.sql similarity index 100% rename from test/JDBC/input/BABEL-937-vu-cleanup.sql rename to test/JDBC/input/json_modify/BABEL-937-vu-cleanup.sql diff --git a/test/JDBC/input/BABEL-937-vu-prepare.sql b/test/JDBC/input/json_modify/BABEL-937-vu-prepare.sql similarity index 100% rename from test/JDBC/input/BABEL-937-vu-prepare.sql rename to test/JDBC/input/json_modify/BABEL-937-vu-prepare.sql diff --git a/test/JDBC/input/BABEL-937-vu-verify.sql b/test/JDBC/input/json_modify/BABEL-937-vu-verify.sql similarity index 100% rename from test/JDBC/input/BABEL-937-vu-verify.sql rename to test/JDBC/input/json_modify/BABEL-937-vu-verify.sql diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index ef55ec0d3c..0eb957a81c 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -399,6 +399,7 @@ test_windows_alter_login sys-systypes openjson BABEL-3702 +BABEL-3696 Test-sp_babelfish_volatility BABEL_OBJECT_DEFINITION Test-sp_rename diff --git a/test/python/expected/upgrade_validation/expected_dependency.out b/test/python/expected/upgrade_validation/expected_dependency.out index 6093cfc5d6..450602fa4f 100644 --- a/test/python/expected/upgrade_validation/expected_dependency.out +++ b/test/python/expected/upgrade_validation/expected_dependency.out @@ -476,7 +476,6 @@ Function sys.isdate(text) Function sys.isjson(text) Function sys.isnumeric(anyelement) Function sys.isnumeric(text) -Function sys.json_query(text,text) Function sys.language() Function sys.len(sys.bbf_varbinary) Function sys.len(text) From bd24aee34b07cd3fc886383f99e35abf17b6f220 Mon Sep 17 00:00:00 2001 From: Yanjie Xu Date: Fri, 10 Mar 2023 10:40:45 -0800 Subject: [PATCH 006/363] Fix error message when creating views on temporary tables Previously when creating views on temporary tables, Babelfish would throw a general error message which does not explain the reason. This commit corrects the error message and keeps it the same as in SQL Server. Task: BABEL-1645 Signed-off-by: Yanjie Xu --- contrib/babelfishpg_tsql/src/tsqlIface.cpp | 25 ++++++++++++++++++- test/JDBC/expected/BABEL-1645.out | 28 ++++++++++++++++++++++ test/JDBC/input/BABEL-1645.sql | 24 +++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 test/JDBC/expected/BABEL-1645.out create mode 100644 test/JDBC/input/BABEL-1645.sql diff --git a/contrib/babelfishpg_tsql/src/tsqlIface.cpp b/contrib/babelfishpg_tsql/src/tsqlIface.cpp index bceccdcc37..14969447eb 100644 --- a/contrib/babelfishpg_tsql/src/tsqlIface.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlIface.cpp @@ -932,9 +932,21 @@ class tsqlSelectStatementMutator : public TSqlParserBaseListener */ public: PLtsql_expr_query_mutator *mutator; - + bool in_create_or_alter_view = false; public: tsqlSelectStatementMutator() = default; + /* Corner case check. If a view is created on a temporary table, we should throw an exception. + * Here we are setting up flags for later check. + */ + void enterCreate_or_alter_view(TSqlParser::Create_or_alter_viewContext *ctx) + { + in_create_or_alter_view = true; + } + + void exitCreate_or_alter_view(TSqlParser::Create_or_alter_viewContext *ctx) + { + in_create_or_alter_view = false; + } void exitSelect_statement(TSqlParser::Select_statementContext *ctx) override { @@ -948,6 +960,17 @@ class tsqlSelectStatementMutator : public TSqlParserBaseListener process_query_specification(ctx, mutator); } + void exitTable_source_item(TSqlParser::Table_source_itemContext *ctx) override + { + std::string table_name = extractTableName(nullptr, ctx); + + if (in_create_or_alter_view && !table_name.empty() && table_name.at(0)=='#') + { + in_create_or_alter_view = false; + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "Views or functions are not allowed on temporary tables. Table names that begin with '#' denote temporary tables.", 0, 0); + } + } + void exitDml_statement(TSqlParser::Dml_statementContext *ctx) override { process_execsql_remove_unsupported_tokens(ctx, mutator); diff --git a/test/JDBC/expected/BABEL-1645.out b/test/JDBC/expected/BABEL-1645.out new file mode 100644 index 0000000000..fb0f83f25a --- /dev/null +++ b/test/JDBC/expected/BABEL-1645.out @@ -0,0 +1,28 @@ +CREATE TABLE test(c1 int) +go +CREATE VIEW vt +AS +SELECT * FROM test +go + +-- Below should fail +CREATE TABLE #t(c1 int) +go +CREATE VIEW v +AS +SELECT * FROM #t +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Views or functions are not allowed on temporary tables. Table names that begin with '#' denote temporary tables.)~~ + + +-- clean up +DROP VIEW vt +go + +DROP TABLE test +go + +DROP TABLE #t +go diff --git a/test/JDBC/input/BABEL-1645.sql b/test/JDBC/input/BABEL-1645.sql new file mode 100644 index 0000000000..a3224b852c --- /dev/null +++ b/test/JDBC/input/BABEL-1645.sql @@ -0,0 +1,24 @@ +CREATE TABLE test(c1 int) +go +CREATE VIEW vt +AS +SELECT * FROM test +go + +-- Below should fail +CREATE TABLE #t(c1 int) +go +CREATE VIEW v +AS +SELECT * FROM #t +go + +-- clean up +DROP VIEW vt +go + +DROP TABLE test +go + +DROP TABLE #t +go From e0950207bc26127c0da8d63bca96e42f17c656de Mon Sep 17 00:00:00 2001 From: Deepakshi Mittal <78574784+deepakshi-mittal@users.noreply.github.com> Date: Fri, 10 Mar 2023 10:48:17 -0800 Subject: [PATCH 007/363] Fix Create Function cannot contain Commit, Rollback and Execute Currently, Babelfish allows creating function containing a Commit, Rollback, exec and execute. Although eoor occurs on executing such functions. This tasks prevenst such function creation and raises error message for same. Task: BABEL-1591 Signed-off-by: Deepakshi Mittal --- contrib/babelfishpg_tsql/src/tsqlIface.cpp | 33 ++++++++++++ test/JDBC/expected/BABEL-1591.out | 61 ++++++++++++++++++++++ test/JDBC/input/BABEL-1591.sql | 56 ++++++++++++++++++++ 3 files changed, 150 insertions(+) create mode 100644 test/JDBC/expected/BABEL-1591.out create mode 100644 test/JDBC/input/BABEL-1591.sql diff --git a/contrib/babelfishpg_tsql/src/tsqlIface.cpp b/contrib/babelfishpg_tsql/src/tsqlIface.cpp index 14969447eb..050cc6a5d1 100644 --- a/contrib/babelfishpg_tsql/src/tsqlIface.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlIface.cpp @@ -730,6 +730,39 @@ class tsqlCommonMutator : public TSqlParserBaseListener /* see comment above. */ public: explicit tsqlCommonMutator() = default; + bool in_create_or_alter_function = false; + + void enterCreate_or_alter_function(TSqlParser::Create_or_alter_functionContext *ctx) override { + in_create_or_alter_function = true; + } + + void exitCreate_or_alter_function(TSqlParser::Create_or_alter_functionContext *ctx) override { + in_create_or_alter_function = false; + } + + void enterTransaction_statement(TSqlParser::Transaction_statementContext *ctx) override { + if (in_create_or_alter_function && ctx->COMMIT()){ + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "Invalid use of a side-effecting operator 'COMMIT TRANSACTION' within a function.", 0, 0); + } + if (in_create_or_alter_function && ctx->ROLLBACK()){ + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "Invalid use of a side-effecting operator 'ROLLBACK TRANSACTION' within a function.", 0, 0); + } + } + + void enterExecute_statement(TSqlParser::Execute_statementContext *ctx) override { + if (in_create_or_alter_function && (ctx->EXEC() || ctx->EXECUTE())){ + TSqlParser::Execute_bodyContext *body = ctx->execute_body(); + if (body->LR_BRACKET()) + { + std::vector exec_strings = body->execute_var_string(); + if (!exec_strings.empty()) + { + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "Invalid use of a side-effecting operator 'EXECUTE STRING' within a function.", 0, 0); + } + + } + } + } /* Column Name */ void exitSimple_column_name(TSqlParser::Simple_column_nameContext *ctx) override diff --git a/test/JDBC/expected/BABEL-1591.out b/test/JDBC/expected/BABEL-1591.out new file mode 100644 index 0000000000..4b53b59067 --- /dev/null +++ b/test/JDBC/expected/BABEL-1591.out @@ -0,0 +1,61 @@ + +-- Allow normal function creation +CREATE FUNCTION babel1591foo1() RETURNS INT AS BEGIN RETURN 10 END +GO + +SELECT babel1591foo1(); +GO +~~START~~ +int +10 +~~END~~ + + +DROP FUNCTION IF EXISTS babel1591foo1; +GO + +-- Below Create function statements having specific keywords should fail +CREATE FUNCTION foocommittest(@p int) RETURNS int AS BEGIN COMMIT RETURN 0 END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid use of a side-effecting operator 'COMMIT TRANSACTION' within a function.)~~ + + +CREATE FUNCTION foorollbacktest(@p int) RETURNS int AS BEGIN ROLLBACK RETURN 0 END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid use of a side-effecting operator 'ROLLBACK TRANSACTION' within a function.)~~ + + +CREATE FUNCTION fooexecutetest(@p int) RETURNS int AS BEGIN EXECUTE('select 1') RETURN 0 END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid use of a side-effecting operator 'EXECUTE STRING' within a function.)~~ + + +CREATE FUNCTION fooexectest(@p int) RETURNS int AS BEGIN EXEC('select 1') RETURN 0 END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid use of a side-effecting operator 'EXECUTE STRING' within a function.)~~ + + +-- clean up +DROP FUNCTION IF EXISTS foocommittest +GO + +DROP FUNCTION IF EXISTS foorollbacktest +GO + +DROP FUNCTION IF EXISTS fooexecutetest +GO + +DROP FUNCTION IF EXISTS fooexectest +GO + + + + diff --git a/test/JDBC/input/BABEL-1591.sql b/test/JDBC/input/BABEL-1591.sql new file mode 100644 index 0000000000..1b1445f082 --- /dev/null +++ b/test/JDBC/input/BABEL-1591.sql @@ -0,0 +1,56 @@ +-- Allow normal function creation + +CREATE FUNCTION babel1591foo1() RETURNS INT AS BEGIN RETURN 10 END +GO + +SELECT babel1591foo1(); +GO + +DROP FUNCTION IF EXISTS babel1591foo1; +GO + +-- Below Create function statements having specific keywords should fail +CREATE FUNCTION foocommittest(@p int) RETURNS int AS BEGIN COMMIT RETURN 0 END +GO + +CREATE FUNCTION foorollbacktest(@p int) RETURNS int AS BEGIN ROLLBACK RETURN 0 END +GO + +CREATE FUNCTION fooexecutetest(@p int) RETURNS int AS BEGIN EXECUTE('select 1') RETURN 0 END +GO + +CREATE FUNCTION fooexectest(@p int) RETURNS int AS BEGIN EXEC('select 1') RETURN 0 END +GO + +-- clean up +DROP FUNCTION IF EXISTS foocommittest +GO + +DROP FUNCTION IF EXISTS foorollbacktest +GO + +DROP FUNCTION IF EXISTS fooexecutetest +GO + +DROP FUNCTION IF EXISTS fooexectest +GO + +--This needs to be uncommented and tested later when support for alter function is added, +-- and corresponding test cases for transactions should be added + +-- ALTER FUNCTION babel1591foo1() RETURNS INT AS BEGIN RETURN 100; END +-- GO +-- select dbo.babel1591foo1(); +-- GO + + +-- NOT TESTED +-- Below Alter function statements having specific keywords should fail +-- ALTER FUNCTION foocommittest(@p int) RETURNS int AS BEGIN COMMIT RETURN 0 END +-- GO +-- ALTER FUNCTION foorollbacktest(@p int) RETURNS int AS BEGIN ROLLBACK RETURN 0 END +-- GO +-- ALTER FUNCTION fooexecutetest(@p int) RETURNS int AS BEGIN EXECUTE('select 1') RETURN 0 END +-- GO +-- ALTER FUNCTION fooexectest(@p int) RETURNS int AS BEGIN EXEC('select 1') RETURN 0 END +-- GO \ No newline at end of file From b3033e9e75823966dd46172d48f230e78e8a100a Mon Sep 17 00:00:00 2001 From: Yanjie Xu Date: Fri, 10 Mar 2023 16:34:11 -0800 Subject: [PATCH 008/363] Made dbname arg in sp_heapdb case-insensitive Previously sp_helpdb in babelfish treats dbname as case-sensitive whereas tsql treats the dbname argument as case-insensitive. This commit implemented a str_to_lower function for dbname and resol- ved the case-senstive issue. Task: BABEL-3643 Signed-off-by: Yanjie Xu --- contrib/babelfishpg_tsql/src/catalog.c | 19 +++++- .../expected/BABEL-sp_helpdb-vu-verify.out | 61 ++++++++++++++----- test/JDBC/input/BABEL-sp_helpdb-vu-verify.sql | 25 ++++++-- 3 files changed, 82 insertions(+), 23 deletions(-) diff --git a/contrib/babelfishpg_tsql/src/catalog.c b/contrib/babelfishpg_tsql/src/catalog.c index 5354521ee1..0588a58ab4 100644 --- a/contrib/babelfishpg_tsql/src/catalog.c +++ b/contrib/babelfishpg_tsql/src/catalog.c @@ -17,6 +17,7 @@ #include "tcop/utility.h" #include "utils/builtins.h" #include "utils/fmgroids.h" +#include "utils/formatting.h" #include "utils/lsyscache.h" #include "utils/syscache.h" #include "utils/tuplestore.h" @@ -284,6 +285,7 @@ babelfish_helpdb(PG_FUNCTION_ARGS) { ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; char *dbname; + char *dbname_lower; ScanKeyData scanKey; TupleDesc tupdesc; Tuplestorestate *tupstore; @@ -297,7 +299,7 @@ babelfish_helpdb(PG_FUNCTION_ARGS) bool typIsVarlena; Oid datetime_type; Oid sys_nspoid = get_namespace_oid("sys", false); - + int index; /* check to see if caller supports us returning a tuplestore */ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) @@ -344,14 +346,25 @@ babelfish_helpdb(PG_FUNCTION_ARGS) if (PG_NARGS() > 0) { dbname = TextDatumGetCString(PG_GETARG_DATUM(0)); - if (!DbidIsValid(get_db_id(dbname))) + dbname_lower = str_tolower(dbname, strlen(dbname), DEFAULT_COLLATION_OID); + /* Remove trailing spaces at the end of user typed dbname */ + index = -1; + for (int i = 0; dbname_lower[i]!='\0'; i++) + { + if (dbname_lower[i]!=' ') + { + index = i; + } + } + dbname_lower[index + 1] = '\0'; + if (!DbidIsValid(get_db_id(dbname_lower))) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("The database '%s' does not exist. Supply a valid database name. To see available databases, use sys.databases.", dbname))); ScanKeyInit(&scanKey, Anum_sysdatabaese_name, BTEqualStrategyNumber, F_TEXTEQ, - CStringGetTextDatum(dbname)); + CStringGetTextDatum(dbname_lower)); scan = systable_beginscan(rel, sysdatabaese_idx_name_oid, true, NULL, 1, &scanKey); } diff --git a/test/JDBC/expected/BABEL-sp_helpdb-vu-verify.out b/test/JDBC/expected/BABEL-sp_helpdb-vu-verify.out index dbf3f03029..cdc6821c92 100644 --- a/test/JDBC/expected/BABEL-sp_helpdb-vu-verify.out +++ b/test/JDBC/expected/BABEL-sp_helpdb-vu-verify.out @@ -1,42 +1,75 @@ -SELECT name, db_size, owner, status, compatibility_level FROM sys.babelfish_helpdb() WHERE name IN ('master', 'babel_sp_helpdb_db'); +SELECT name, compatibility_level FROM sys.babelfish_helpdb() WHERE name IN ('master', 'babel_sp_helpdb_db'); GO ~~START~~ -varchar#!#varchar#!#varchar#!#varchar#!#smallint -master#!##!#jdbc_user#!##!# -babel_sp_helpdb_db#!##!#jdbc_user#!##!# +varchar#!#smallint +master#!# +babel_sp_helpdb_db#!# ~~END~~ -- Executing sp_helpdb with already existing dbname as an input -SELECT name, db_size, owner, status, compatibility_level FROM sys.babelfish_helpdb('master'); +SELECT name, compatibility_level FROM sys.babelfish_helpdb('master'); GO ~~START~~ -varchar#!#varchar#!#varchar#!#varchar#!#smallint -master#!##!#jdbc_user#!##!# +varchar#!#smallint +master#!# ~~END~~ -SELECT name, db_size, owner, status, compatibility_level FROM sys.babelfish_helpdb('babel_sp_helpdb_db'); +SELECT name, compatibility_level FROM sys.babelfish_helpdb('babel_sp_helpdb_db'); GO ~~START~~ -varchar#!#varchar#!#varchar#!#varchar#!#smallint -babel_sp_helpdb_db#!##!#jdbc_user#!##!# +varchar#!#smallint +babel_sp_helpdb_db#!# ~~END~~ -- Executing sp_helpdb with wrong input -SELECT name, db_size, owner, status, compatibility_level FROM sys.babelfish_helpdb('abc'); +SELECT name, compatibility_level FROM sys.babelfish_helpdb('abc'); GO ~~START~~ -varchar#!#varchar#!#varchar#!#varchar#!#smallint +varchar#!#smallint ~~ERROR (Code: 33557097)~~ ~~ERROR (Message: The database 'abc' does not exist. Supply a valid database name. To see available databases, use sys.databases.)~~ -SELECT name, db_size, owner, status, compatibility_level FROM sys.babelfish_helpdb(' wrongInput'); +SELECT name, compatibility_level FROM sys.babelfish_helpdb(' wrongInput'); GO ~~START~~ -varchar#!#varchar#!#varchar#!#varchar#!#smallint +varchar#!#smallint ~~ERROR (Code: 33557097)~~ ~~ERROR (Message: The database ' wrongInput' does not exist. Supply a valid database name. To see available databases, use sys.databases.)~~ + +-- Executing sp_helpdb with a existing dbname but in mixed upper, lower cases as an input +SELECT name, compatibility_level FROM sys.babelfish_helpdb('MaSteR'); +GO +~~START~~ +varchar#!#smallint +master#!# +~~END~~ + +SELECT name, compatibility_level FROM sys.babelfish_helpdb('bAbeL_sP_helPdb_Db'); +GO +~~START~~ +varchar#!#smallint +babel_sp_helpdb_db#!# +~~END~~ + + +-- Executing sp_helpdb with a existing dbname but end with trailing spaces as an input +SELECT name, compatibility_level FROM sys.babelfish_helpdb('MaSteR '); +GO +~~START~~ +varchar#!#smallint +master#!# +~~END~~ + +SELECT name, compatibility_level FROM sys.babelfish_helpdb('bAbeL_sP_helPdb_Db '); +GO +~~START~~ +varchar#!#smallint +babel_sp_helpdb_db#!# +~~END~~ + + diff --git a/test/JDBC/input/BABEL-sp_helpdb-vu-verify.sql b/test/JDBC/input/BABEL-sp_helpdb-vu-verify.sql index 9f7b62599d..a2a7920c78 100644 --- a/test/JDBC/input/BABEL-sp_helpdb-vu-verify.sql +++ b/test/JDBC/input/BABEL-sp_helpdb-vu-verify.sql @@ -1,14 +1,27 @@ -SELECT name, db_size, owner, status, compatibility_level FROM sys.babelfish_helpdb() WHERE name IN ('master', 'babel_sp_helpdb_db'); +SELECT name, compatibility_level FROM sys.babelfish_helpdb() WHERE name IN ('master', 'babel_sp_helpdb_db'); GO -- Executing sp_helpdb with already existing dbname as an input -SELECT name, db_size, owner, status, compatibility_level FROM sys.babelfish_helpdb('master'); +SELECT name, compatibility_level FROM sys.babelfish_helpdb('master'); GO -SELECT name, db_size, owner, status, compatibility_level FROM sys.babelfish_helpdb('babel_sp_helpdb_db'); +SELECT name, compatibility_level FROM sys.babelfish_helpdb('babel_sp_helpdb_db'); GO -- Executing sp_helpdb with wrong input -SELECT name, db_size, owner, status, compatibility_level FROM sys.babelfish_helpdb('abc'); +SELECT name, compatibility_level FROM sys.babelfish_helpdb('abc'); GO -SELECT name, db_size, owner, status, compatibility_level FROM sys.babelfish_helpdb(' wrongInput'); -GO \ No newline at end of file +SELECT name, compatibility_level FROM sys.babelfish_helpdb(' wrongInput'); +GO + +-- Executing sp_helpdb with a existing dbname but in mixed upper, lower cases as an input +SELECT name, compatibility_level FROM sys.babelfish_helpdb('MaSteR'); +GO +SELECT name, compatibility_level FROM sys.babelfish_helpdb('bAbeL_sP_helPdb_Db'); +GO + +-- Executing sp_helpdb with a existing dbname but end with trailing spaces as an input +SELECT name, compatibility_level FROM sys.babelfish_helpdb('MaSteR '); +GO +SELECT name, compatibility_level FROM sys.babelfish_helpdb('bAbeL_sP_helPdb_Db '); +GO + From f5175c001ef542f5288c1a7c1d93954b222d8be7 Mon Sep 17 00:00:00 2001 From: Jake Owen Date: Mon, 13 Mar 2023 12:56:05 -0400 Subject: [PATCH 009/363] JSON_MODIFY() does not properly handle INT values (#1328) In TSQL, JSON_MODIFY() is explicitly stated to only accept text or nvarchar inputs but in practice it allows certain inputs to be interpreted as non-text types. This pull request adds support to properly handle INT values. Task: BABEL-3697 Signed-off-by: Jake Owen --- .../babelfishpg_tsql/sql/sys_functions.sql | 2 +- .../babelfishpg_tsql--3.1.0--3.2.0.sql | 2 +- .../src/backend_parser/gram-tsql-epilogue.y.c | 24 ++++-- test/JDBC/expected/BABEL-3697-vu-cleanup.out | 26 +++++++ test/JDBC/expected/BABEL-3697-vu-prepare.out | 47 ++++++++++++ test/JDBC/expected/BABEL-3697-vu-verify.out | 73 +++++++++++++++++++ test/JDBC/expected/BABEL-937-vu-cleanup.out | 3 - test/JDBC/expected/BABEL-937-vu-prepare.out | 6 -- test/JDBC/expected/BABEL-937-vu-verify.out | 9 --- .../json_modify/BABEL-3697-vu-cleanup.sql | 26 +++++++ .../json_modify/BABEL-3697-vu-prepare.sql | 47 ++++++++++++ .../json_modify/BABEL-3697-vu-verify.sql | 26 +++++++ .../json_modify/BABEL-937-vu-cleanup.sql | 3 - .../json_modify/BABEL-937-vu-prepare.sql | 6 -- .../input/json_modify/BABEL-937-vu-verify.sql | 4 - test/JDBC/upgrade/latest/schedule | 1 + 16 files changed, 265 insertions(+), 40 deletions(-) create mode 100644 test/JDBC/expected/BABEL-3697-vu-cleanup.out create mode 100644 test/JDBC/expected/BABEL-3697-vu-prepare.out create mode 100644 test/JDBC/expected/BABEL-3697-vu-verify.out create mode 100644 test/JDBC/input/json_modify/BABEL-3697-vu-cleanup.sql create mode 100644 test/JDBC/input/json_modify/BABEL-3697-vu-prepare.sql create mode 100644 test/JDBC/input/json_modify/BABEL-3697-vu-verify.sql diff --git a/contrib/babelfishpg_tsql/sql/sys_functions.sql b/contrib/babelfishpg_tsql/sql/sys_functions.sql index a0bceb77d6..a9889223c5 100644 --- a/contrib/babelfishpg_tsql/sql/sys_functions.sql +++ b/contrib/babelfishpg_tsql/sql/sys_functions.sql @@ -2823,7 +2823,7 @@ AS 'babelfishpg_tsql', 'tsql_json_query' LANGUAGE C IMMUTABLE PARALLEL SAFE; * 2) To convert the input path into the expected jsonb_path. * 3) To implement the main logic of the JSON_MODIFY function by dividing it into 8 different cases. */ -CREATE OR REPLACE FUNCTION sys.json_modify(in expression sys.NVARCHAR,in path_json TEXT, in new_value TEXT, in escape bool) +CREATE OR REPLACE FUNCTION sys.json_modify(in expression sys.NVARCHAR,in path_json TEXT, in new_value ANYELEMENT, in escape bool) RETURNS sys.NVARCHAR AS $BODY$ diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql index e9130216bf..190edbe812 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql @@ -82,7 +82,7 @@ CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'json_modify_deprec * 2) To convert the input path into the expected jsonb_path. * 3) To implement the main logic of the JSON_MODIFY function by dividing it into 8 different cases. */ -CREATE OR REPLACE FUNCTION sys.json_modify(in expression sys.NVARCHAR,in path_json TEXT, in new_value TEXT, in escape bool) +CREATE OR REPLACE FUNCTION sys.json_modify(in expression sys.NVARCHAR,in path_json TEXT, in new_value ANYELEMENT, in escape bool) RETURNS sys.NVARCHAR AS $BODY$ diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c index f16bf47657..c5c0b5a578 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c @@ -599,15 +599,25 @@ Node* TsqlJsonModifyMakeFuncCall(Node* expr, Node* path, Node* newValue) { FuncCall* fc; - List* func_args = list_make3(expr, path, newValue); + FuncCall* fc_newval; + List* func_args = list_make2(expr, path); bool escape = false; - if(IsA(newValue, FuncCall)) + switch(newValue->type) { - FuncCall* fc_newval = (FuncCall*) newValue; - if(is_json_modify(fc_newval->funcname) || is_json_query(fc_newval->funcname)) - { - escape = true; - } + case T_FuncCall: + fc_newval = (FuncCall*) newValue; + if(is_json_modify(fc_newval->funcname) || is_json_query(fc_newval->funcname)) + { + escape = true; + } + func_args = lappend(func_args, newValue); + break; + case T_TypeCast: + case T_A_Expr: + func_args = lappend(func_args, newValue); + break; + default: + func_args = lappend(func_args, makeTypeCast(newValue, makeTypeName("text"), -1)); } func_args = lappend(func_args, makeBoolAConst(escape, -1)); fc = makeFuncCall(TsqlSystemFuncName("json_modify"), func_args, COERCE_EXPLICIT_CALL, -1); diff --git a/test/JDBC/expected/BABEL-3697-vu-cleanup.out b/test/JDBC/expected/BABEL-3697-vu-cleanup.out new file mode 100644 index 0000000000..675aed9a75 --- /dev/null +++ b/test/JDBC/expected/BABEL-3697-vu-cleanup.out @@ -0,0 +1,26 @@ +DROP VIEW babel_3697_1 +GO + +DROP VIEW babel_3697_2 +GO + +DROP VIEW babel_3697_3 +GO + +DROP VIEW babel_3697_4 +GO + +DROP VIEW babel_3697_5 +GO + +DROP PROCEDURE babel_3697_6 +GO + +DROP PROCEDURE babel_3697_7 +GO + +DROP PROCEDURE babel_3697_8 +GO + +DROP VIEW babel_3697_multi_function +GO diff --git a/test/JDBC/expected/BABEL-3697-vu-prepare.out b/test/JDBC/expected/BABEL-3697-vu-prepare.out new file mode 100644 index 0000000000..0a2d219091 --- /dev/null +++ b/test/JDBC/expected/BABEL-3697-vu-prepare.out @@ -0,0 +1,47 @@ +create view babel_3697_1 as +SELECT JSON_MODIFY('{"click_count": 173}', '$.click_count', CAST(JSON_VALUE('{"click_count": 173}','$.click_count') AS INT)+1) +go + +create view babel_3697_2 as +SELECT JSON_MODIFY('{"click_count": 173.12345342}', '$.click_count', CAST(JSON_VALUE('{"click_count": 173.12345342}','$.click_count') AS NUMERIC(7, 3))) +go + +create view babel_3697_3 as +SELECT JSON_MODIFY('{"click_count": 173}', '$.click_count', 25) +go + +create view babel_3697_4 as +SELECT JSON_MODIFY('{"click_count": 1900-01-01}', '$.click_count', CAST('1900-02-02' as DATE)) +go + +create view babel_3697_5 as +SELECT JSON_MODIFY('{"click_count": 04:05:06}', '$.click_count', CAST('04:05:06' as TIME)) +go + + +create procedure babel_3697_6 +as begin +DECLARE @data NVARCHAR(100)='{"click_count": 12345}' +SELECT JSON_MODIFY(@data, '$.click_count', CAST(JSON_VALUE(@data,'$.click_count') AS CHAR(2))) +end; +go + +create procedure babel_3697_7 +as begin +DECLARE @data NVARCHAR(100)='{"click_count": 12345}' +SELECT JSON_MODIFY(@data, '$.click_count', 0) +end; +go + +create procedure babel_3697_8 +as begin +DECLARE @data NVARCHAR(100)='{"click_count": 12345}' +SELECT JSON_MODIFY(@data, '$.click_count', 6 + 235) +end; +go + +-- To check multi function call query +create view babel_3697_multi_function as +SELECT JSON_MODIFY(JSON_MODIFY(JSON_MODIFY('{"name":"John","skills":["C#","SQL"]}','$.name','Mike'),'$.surname','Smith'),'append $.skills','Azure') AS mf_1, + JSON_MODIFY(JSON_MODIFY('{"price":49.99}','$.Price',CAST(JSON_VALUE('{"price":49.99}','$.price') AS NUMERIC(4,2))),'$.price',NULL) AS mf_2; +go diff --git a/test/JDBC/expected/BABEL-3697-vu-verify.out b/test/JDBC/expected/BABEL-3697-vu-verify.out new file mode 100644 index 0000000000..2b03727680 --- /dev/null +++ b/test/JDBC/expected/BABEL-3697-vu-verify.out @@ -0,0 +1,73 @@ +SELECT * FROM babel_3697_1 +GO +~~START~~ +nvarchar +{"click_count": 174} +~~END~~ + + +SELECT * FROM babel_3697_2 +GO +~~START~~ +nvarchar +{"click_count": 173.123} +~~END~~ + + +SELECT * FROM babel_3697_3 +GO +~~START~~ +nvarchar +{"click_count": "25"} +~~END~~ + + +SELECT * FROM babel_3697_4 +GO +~~START~~ +nvarchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type json)~~ + + +SELECT * FROM babel_3697_5 +GO +~~START~~ +nvarchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type json)~~ + + +EXEC babel_3697_6 +GO +~~START~~ +nvarchar +{"click_count": "12"} +~~END~~ + + +EXEC babel_3697_7 +GO +~~START~~ +nvarchar +{"click_count": "0"} +~~END~~ + + +EXEC babel_3697_8 +GO +~~START~~ +nvarchar +{"click_count": 241} +~~END~~ + + +SELECT * FROM babel_3697_multi_function +GO +~~START~~ +nvarchar#!#nvarchar +{"name": "Mike", "skills": ["C#", "SQL", "Azure"], "surname": "Smith"}#!#{"Price": 49.99} +~~END~~ + diff --git a/test/JDBC/expected/BABEL-937-vu-cleanup.out b/test/JDBC/expected/BABEL-937-vu-cleanup.out index 3477da408b..e097c60a32 100644 --- a/test/JDBC/expected/BABEL-937-vu-cleanup.out +++ b/test/JDBC/expected/BABEL-937-vu-cleanup.out @@ -36,8 +36,5 @@ go drop view babel_937_spaces go -drop view babel_937_multi_function -go - drop view babel_937_test_array go diff --git a/test/JDBC/expected/BABEL-937-vu-prepare.out b/test/JDBC/expected/BABEL-937-vu-prepare.out index b8d238380a..5d83bdee38 100644 --- a/test/JDBC/expected/BABEL-937-vu-prepare.out +++ b/test/JDBC/expected/BABEL-937-vu-prepare.out @@ -107,12 +107,6 @@ SELECT JSON_MODIFY('{"id": 1,"tags": [ ]}',' append strict $.friends ',NULL); go --- To check multi function call query -create view babel_937_multi_function as -SELECT JSON_MODIFY(JSON_MODIFY(JSON_MODIFY('{"name":"John","skills":["C#","SQL"]}','$.name','Mike'),'$.surname','Smith'),'append $.skills','Azure') AS mf_1, - JSON_MODIFY(JSON_MODIFY('{"price":49.99}','$.Price',CAST(JSON_VALUE('{"price":49.99}','$.price') AS NUMERIC(4,2))),'$.price',NULL) AS mf_2; -go - -- To check when expression is array type create view babel_937_test_array as SELECT JSON_MODIFY('[{"name":"John","skills":["C#","SQL"]},"b","temp"]','strict $[0].skills[1]',NULL) AS ta_1, diff --git a/test/JDBC/expected/BABEL-937-vu-verify.out b/test/JDBC/expected/BABEL-937-vu-verify.out index 838cf84464..838ed02e63 100644 --- a/test/JDBC/expected/BABEL-937-vu-verify.out +++ b/test/JDBC/expected/BABEL-937-vu-verify.out @@ -128,15 +128,6 @@ nvarchar ~~END~~ --- To check multi function call query -select * from babel_937_multi_function -go -~~START~~ -nvarchar#!#nvarchar -{"name": "Mike", "skills": ["C#", "SQL", "Azure"], "surname": "Smith"}#!#{"Price": "49.99"} -~~END~~ - - -- To check when expression is array type select * from babel_937_test_array go diff --git a/test/JDBC/input/json_modify/BABEL-3697-vu-cleanup.sql b/test/JDBC/input/json_modify/BABEL-3697-vu-cleanup.sql new file mode 100644 index 0000000000..910d4f1ee1 --- /dev/null +++ b/test/JDBC/input/json_modify/BABEL-3697-vu-cleanup.sql @@ -0,0 +1,26 @@ +DROP VIEW babel_3697_1 +GO + +DROP VIEW babel_3697_2 +GO + +DROP VIEW babel_3697_3 +GO + +DROP VIEW babel_3697_4 +GO + +DROP VIEW babel_3697_5 +GO + +DROP PROCEDURE babel_3697_6 +GO + +DROP PROCEDURE babel_3697_7 +GO + +DROP PROCEDURE babel_3697_8 +GO + +DROP VIEW babel_3697_multi_function +GO \ No newline at end of file diff --git a/test/JDBC/input/json_modify/BABEL-3697-vu-prepare.sql b/test/JDBC/input/json_modify/BABEL-3697-vu-prepare.sql new file mode 100644 index 0000000000..0a2d219091 --- /dev/null +++ b/test/JDBC/input/json_modify/BABEL-3697-vu-prepare.sql @@ -0,0 +1,47 @@ +create view babel_3697_1 as +SELECT JSON_MODIFY('{"click_count": 173}', '$.click_count', CAST(JSON_VALUE('{"click_count": 173}','$.click_count') AS INT)+1) +go + +create view babel_3697_2 as +SELECT JSON_MODIFY('{"click_count": 173.12345342}', '$.click_count', CAST(JSON_VALUE('{"click_count": 173.12345342}','$.click_count') AS NUMERIC(7, 3))) +go + +create view babel_3697_3 as +SELECT JSON_MODIFY('{"click_count": 173}', '$.click_count', 25) +go + +create view babel_3697_4 as +SELECT JSON_MODIFY('{"click_count": 1900-01-01}', '$.click_count', CAST('1900-02-02' as DATE)) +go + +create view babel_3697_5 as +SELECT JSON_MODIFY('{"click_count": 04:05:06}', '$.click_count', CAST('04:05:06' as TIME)) +go + + +create procedure babel_3697_6 +as begin +DECLARE @data NVARCHAR(100)='{"click_count": 12345}' +SELECT JSON_MODIFY(@data, '$.click_count', CAST(JSON_VALUE(@data,'$.click_count') AS CHAR(2))) +end; +go + +create procedure babel_3697_7 +as begin +DECLARE @data NVARCHAR(100)='{"click_count": 12345}' +SELECT JSON_MODIFY(@data, '$.click_count', 0) +end; +go + +create procedure babel_3697_8 +as begin +DECLARE @data NVARCHAR(100)='{"click_count": 12345}' +SELECT JSON_MODIFY(@data, '$.click_count', 6 + 235) +end; +go + +-- To check multi function call query +create view babel_3697_multi_function as +SELECT JSON_MODIFY(JSON_MODIFY(JSON_MODIFY('{"name":"John","skills":["C#","SQL"]}','$.name','Mike'),'$.surname','Smith'),'append $.skills','Azure') AS mf_1, + JSON_MODIFY(JSON_MODIFY('{"price":49.99}','$.Price',CAST(JSON_VALUE('{"price":49.99}','$.price') AS NUMERIC(4,2))),'$.price',NULL) AS mf_2; +go diff --git a/test/JDBC/input/json_modify/BABEL-3697-vu-verify.sql b/test/JDBC/input/json_modify/BABEL-3697-vu-verify.sql new file mode 100644 index 0000000000..9210f5ae5e --- /dev/null +++ b/test/JDBC/input/json_modify/BABEL-3697-vu-verify.sql @@ -0,0 +1,26 @@ +SELECT * FROM babel_3697_1 +GO + +SELECT * FROM babel_3697_2 +GO + +SELECT * FROM babel_3697_3 +GO + +SELECT * FROM babel_3697_4 +GO + +SELECT * FROM babel_3697_5 +GO + +EXEC babel_3697_6 +GO + +EXEC babel_3697_7 +GO + +EXEC babel_3697_8 +GO + +SELECT * FROM babel_3697_multi_function +GO \ No newline at end of file diff --git a/test/JDBC/input/json_modify/BABEL-937-vu-cleanup.sql b/test/JDBC/input/json_modify/BABEL-937-vu-cleanup.sql index 3477da408b..e097c60a32 100644 --- a/test/JDBC/input/json_modify/BABEL-937-vu-cleanup.sql +++ b/test/JDBC/input/json_modify/BABEL-937-vu-cleanup.sql @@ -36,8 +36,5 @@ go drop view babel_937_spaces go -drop view babel_937_multi_function -go - drop view babel_937_test_array go diff --git a/test/JDBC/input/json_modify/BABEL-937-vu-prepare.sql b/test/JDBC/input/json_modify/BABEL-937-vu-prepare.sql index b8d238380a..5d83bdee38 100644 --- a/test/JDBC/input/json_modify/BABEL-937-vu-prepare.sql +++ b/test/JDBC/input/json_modify/BABEL-937-vu-prepare.sql @@ -107,12 +107,6 @@ SELECT JSON_MODIFY('{"id": 1,"tags": [ ]}',' append strict $.friends ',NULL); go --- To check multi function call query -create view babel_937_multi_function as -SELECT JSON_MODIFY(JSON_MODIFY(JSON_MODIFY('{"name":"John","skills":["C#","SQL"]}','$.name','Mike'),'$.surname','Smith'),'append $.skills','Azure') AS mf_1, - JSON_MODIFY(JSON_MODIFY('{"price":49.99}','$.Price',CAST(JSON_VALUE('{"price":49.99}','$.price') AS NUMERIC(4,2))),'$.price',NULL) AS mf_2; -go - -- To check when expression is array type create view babel_937_test_array as SELECT JSON_MODIFY('[{"name":"John","skills":["C#","SQL"]},"b","temp"]','strict $[0].skills[1]',NULL) AS ta_1, diff --git a/test/JDBC/input/json_modify/BABEL-937-vu-verify.sql b/test/JDBC/input/json_modify/BABEL-937-vu-verify.sql index c7c768f023..f78e86868e 100644 --- a/test/JDBC/input/json_modify/BABEL-937-vu-verify.sql +++ b/test/JDBC/input/json_modify/BABEL-937-vu-verify.sql @@ -44,10 +44,6 @@ go select * from babel_937_spaces go --- To check multi function call query -select * from babel_937_multi_function -go - -- To check when expression is array type select * from babel_937_test_array go diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index 0eb957a81c..8f976d0aa4 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -400,6 +400,7 @@ sys-systypes openjson BABEL-3702 BABEL-3696 +BABEL-3697 Test-sp_babelfish_volatility BABEL_OBJECT_DEFINITION Test-sp_rename From 7cd2531679982c29f90147ad6a7136158d856192 Mon Sep 17 00:00:00 2001 From: Rishabh Tanwar <33982749+rishabhtanwar29@users.noreply.github.com> Date: Tue, 14 Mar 2023 21:32:40 +0530 Subject: [PATCH 010/363] Support database-level dump/restore (#1304) Engine Added support for dumping a single Babelfish logical database. Changes are summarized in following bullet points: Added a new option --bbf-database-name in both pg_dumpall and pg_dump to let user provide the name of logical database to be dumped. Fetch all the physical schema names corresponding to the given logical database and add all of them into schema_include_patterns list. With this, existing dump logic will make sure to only dump all these schemas as well as all the objects contained by these schemas. Function bbf_selectDumpableTableData takes care of explicitly marking all Babelfish catalog table data to be dumped. We need to selectively dump the Babelfish catalog table data corresponding to given logical database which is being handled by function getCursorForBbfCatalogTableData for COLUMN-INSERT and fixCopyCommand for COPY. These function prepares query using joins and conditions to filter the data. We skip dumping the dbid column as it might conflict with the existing database's dbid so we generate the new dbid during restore. It has been handled for both COLUMN-INSERT and COPY options: a. COPY: Implemented a hook fill_missing_values_in_copyfrom_hook which will use the sequence to generate the new dbid. b. COLUMN-INSERT: Used existing pre_parse_analyze_hook hook to handle this case. Added a new file dumpall_babel_utils.c to implement Babelfish specific logic to selectively dump users. New file is needed since existing dump_babel_utils.c can't be used with pg_dumpall utility. Logins do not belong to a single database so we will not be dumping the logins so it and we will only dump default users of the database (dbo, db_owner and db_guest). Due to this CREATE and INSERT might fail for certain logins but it should be fine. Current implementation does not dump foreign servers and foreign data wrappers as these are global objects and does not belong to a single logical database. Note: A logical database with certain migration mode (single-db/multi-db) can only be restored on the Babelfish server with the same migration mode. Which means a single-db database can be restored only on single-db Babelfish server, same thing applies to multi-db. Although the builtin databases like master can be restored on any kind of server. Extension Modified existing instance dump-restore github action to work with database-level dump-restore as well. We can use configuration file to specify the logical database name. Currently we are testing with master database for which a directory has been in upgrade folder. Implemented fill_missing_values_in_copyfrom_hook to handle the case of generating new dbid for COPY. Handled the same for COLUMN-INSERT in pre_parse_analyze_hook. Signed-off-by: Rishabh Tanwar Co-authored-by: Rishabh Tanwar --- .../dump-restore-util/action.yml | 54 ++- .../run-verify-tests/action.yml | 10 + .../setup-base-version/action.yml | 11 +- .../setup-dump-restore-ca/action.yml | 14 +- .../dump-restore-test-configuration.yml | 18 +- .github/workflows/pg_dump-restore-test.yml | 6 +- contrib/babelfishpg_tsql/src/dbcmds.c | 46 +- contrib/babelfishpg_tsql/src/dbcmds.h | 1 + contrib/babelfishpg_tsql/src/hooks.c | 44 ++ contrib/babelfishpg_tsql/src/pl_handler.c | 68 +++ dev-tools.sh | 33 +- test/JDBC/expected/BABEL-3402-vu-prepare.out | 4 +- .../BABEL-CHECK-CONSTRAINT-vu-cleanup.out | 2 +- .../BABEL-CHECK-CONSTRAINT-vu-prepare.out | 4 +- .../BABEL-CHECK-CONSTRAINT-vu-verify.out | 4 +- .../expected/BABEL_OBJECT_ID-vu-cleanup.out | 6 - .../expected/BABEL_OBJECT_ID-vu-prepare.out | 7 - .../expected/BABEL_OBJECT_ID-vu-verify.out | 34 -- test/JDBC/input/BABEL-3402-vu-prepare.mix | 6 +- .../BABEL-CHECK-CONSTRAINT-vu-cleanup.mix | 4 +- .../BABEL-CHECK-CONSTRAINT-vu-prepare.mix | 6 +- .../BABEL-CHECK-CONSTRAINT-vu-verify.mix | 4 +- .../JDBC/input/BABEL_OBJECT_ID-vu-cleanup.mix | 8 +- .../JDBC/input/BABEL_OBJECT_ID-vu-prepare.mix | 7 - test/JDBC/input/BABEL_OBJECT_ID-vu-verify.mix | 16 +- test/JDBC/upgrade/master/schedule | 414 ++++++++++++++++++ 26 files changed, 701 insertions(+), 130 deletions(-) create mode 100644 test/JDBC/upgrade/master/schedule diff --git a/.github/composite-actions/dump-restore-util/action.yml b/.github/composite-actions/dump-restore-util/action.yml index 53cb5d7f68..395a2b30f9 100644 --- a/.github/composite-actions/dump-restore-util/action.yml +++ b/.github/composite-actions/dump-restore-util/action.yml @@ -18,6 +18,10 @@ inputs: migration_mode: description: "Database migration mode for Babelfish" required: true + logical_database: + description: "Logical Babelfish database to dump and restore" + required: false + default: 'null' runs: using: "composite" @@ -39,24 +43,39 @@ runs: cd ~ mkdir -p upgrade cd upgrade - echo 'Runinng pg_dumpall and pg_dump' - ~/${{ inputs.pg_new_dir }}/bin/pg_dumpall --username jdbc_user --globals-only --quote-all-identifiers --verbose -f pg_dump_globals.sql 2>>error.log - ~/${{ inputs.pg_new_dir }}/bin/pg_dump --username jdbc_user --column-inserts --quote-all-identifiers --verbose --file="pg_dump.sql" --dbname=jdbc_testdb 2>>error.log + if [[ '${{ inputs.logical_database }}' == 'null' ]];then + echo 'Starting to dump whole Babelfish physical database' + ~/${{ inputs.pg_new_dir }}/bin/pg_dumpall --database jdbc_testdb --username jdbc_user --globals-only --quote-all-identifiers --verbose -f pg_dump_globals.sql 2>>error.log + ~/${{ inputs.pg_new_dir }}/bin/pg_dump --create --username jdbc_user --quote-all-identifiers --verbose --file="pg_dump.sql" --dbname=jdbc_testdb 2>>error.log + else + echo "Starting to dump Babelfish logical database ${{ inputs.logical_database }}" + ~/${{ inputs.pg_new_dir }}/bin/pg_dumpall --database jdbc_testdb --username jdbc_user --globals-only --quote-all-identifiers --verbose --bbf-database-name='${{ inputs.logical_database }}' -f pg_dump_globals.sql 2>>error.log + ~/${{ inputs.pg_new_dir }}/bin/pg_dump --username jdbc_user --quote-all-identifiers --verbose --bbf-database-name='${{ inputs.logical_database }}' --file="pg_dump.sql" --dbname=jdbc_testdb 2>>error.log + fi + + # Stop old server and start the new. ~/${{ inputs.pg_old_dir }}/bin/pg_ctl -D ~/${{ inputs.pg_old_dir }}/data stop - echo 'Done dumping the database, proceeding to restore dumped SQL script on new server.' - echo 'Restoring from pg_dumpall' ~/${{ inputs.pg_new_dir }}/bin/pg_ctl -D ~/${{ inputs.pg_new_dir }}/data -l ~/${{ inputs.pg_new_dir }}/data/logfile start - sudo ~/${{ inputs.pg_new_dir }}/bin/psql -d postgres -U runner -f pg_dump_globals.sql 2>>error.log - sudo ~/${{ inputs.pg_new_dir }}/bin/psql -d postgres -U runner -c "CREATE DATABASE jdbc_testdb OWNER jdbc_user;" - echo 'Restoring from pg_dump' - sudo ~/${{ inputs.pg_new_dir }}/bin/psql -d jdbc_testdb -U jdbc_user -f pg_dump.sql 2>>error.log - sudo ~/${{ inputs.pg_new_dir }}/bin/psql -d jdbc_testdb -U jdbc_user -c "GRANT ALL ON SCHEMA sys to jdbc_user;" - sudo ~/${{ inputs.pg_new_dir }}/bin/psql -d jdbc_testdb -U jdbc_user -c "GRANT CREATE, CONNECT, TEMPORARY ON DATABASE jdbc_testdb TO sysadmin WITH GRANT OPTION;" - sudo ~/${{ inputs.pg_new_dir }}/bin/psql -d jdbc_testdb -U jdbc_user -c "ALTER USER jdbc_user CREATEDB;" + cd ~/work/babelfish_extensions/babelfish_extensions/ + echo 'Database dump complete.' + + if [[ '${{ inputs.logical_database }}' == 'null' ]];then + echo 'Restoring from pg_dumpall' + sudo ~/${{ inputs.pg_new_dir }}/bin/psql -d postgres -U runner -f ~/upgrade/pg_dump_globals.sql 2>> ~/upgrade/error.log + echo 'Restoring from pg_dump' + sudo ~/${{ inputs.pg_new_dir }}/bin/psql -d postgres -U jdbc_user -f ~/upgrade/pg_dump.sql 2>> ~/upgrade/error.log + else + # Create and initialise Babelfish extensions in the new server if we are restoring a logical database. + sudo ~/${{ inputs.pg_new_dir }}/bin/psql -d postgres -U runner -v user="jdbc_user" -v db="jdbc_testdb" -v migration_mode=${{inputs.migration_mode}} -f .github/scripts/create_extension.sql + echo 'Restoring from pg_dumpall' + sudo ~/${{ inputs.pg_new_dir }}/bin/psql -d postgres -U runner -f ~/upgrade/pg_dump_globals.sql 2>> ~/upgrade/error.log + echo 'Restoring from pg_dump' + sudo ~/${{ inputs.pg_new_dir }}/bin/psql -d jdbc_testdb -U jdbc_user -f ~/upgrade/pg_dump.sql 2>> ~/upgrade/error.log + fi + sudo ~/${{ inputs.pg_new_dir }}/bin/psql -d jdbc_testdb -U jdbc_user -c "ALTER SYSTEM SET babelfishpg_tsql.database_name = 'jdbc_testdb';" sudo ~/${{ inputs.pg_new_dir }}/bin/psql -d jdbc_testdb -U jdbc_user -c "ALTER SYSTEM SET babelfishpg_tsql.migration_mode = '${{inputs.migration_mode}}';" sudo ~/${{ inputs.pg_new_dir }}/bin/psql -d jdbc_testdb -U jdbc_user -c "SELECT pg_reload_conf();" - cd ~/work/babelfish_extensions/babelfish_extensions/ export PATH=/opt/mssql-tools/bin:$PATH sqlcmd -S localhost -U jdbc_user -P 12345678 -Q "SELECT @@version GO" shell: bash @@ -76,13 +95,15 @@ runs: base_dir="singledb" fi + if [[ '${{ inputs.logical_database }}' != 'null' ]];then + base_dir="${{ inputs.logical_database }}" + fi + # Temporarily disable certain tests until fixed sed -i "/BABEL-3513/d" test/JDBC/upgrade/$base_dir/schedule - sed -i "/BABEL_OBJECT_ID/d" test/JDBC/upgrade/$base_dir/schedule sed -i "/TestNotNull/d" test/JDBC/upgrade/$base_dir/schedule sed -i "/TestSQLVariant/d" test/JDBC/upgrade/$base_dir/schedule sed -i "/babel_datatype_sqlvariant/d" test/JDBC/upgrade/$base_dir/schedule - sed -i "/schema_resolution_proc/d" test/JDBC/upgrade/$base_dir/schedule sed -i "/sp_tablecollations/d" test/JDBC/upgrade/$base_dir/schedule sed -i "/sys-sql_modules/d" test/JDBC/upgrade/$base_dir/schedule sed -i "/sys-system_sql_modules/d" test/JDBC/upgrade/$base_dir/schedule @@ -94,4 +115,5 @@ runs: with: is_final_ver: ${{ inputs.is_final_ver }} pg_new_dir: ${{ inputs.pg_new_dir }} - migration_mode: ${{ inputs.migration_mode }} \ No newline at end of file + migration_mode: ${{ inputs.migration_mode }} + logical_database: ${{ inputs.logical_database }} diff --git a/.github/composite-actions/run-verify-tests/action.yml b/.github/composite-actions/run-verify-tests/action.yml index 484172416b..332c959fc3 100644 --- a/.github/composite-actions/run-verify-tests/action.yml +++ b/.github/composite-actions/run-verify-tests/action.yml @@ -9,6 +9,10 @@ inputs: migration_mode: description: "Database migration mode for Babelfish" required: true + logical_database: + description: "Logical Babelfish database to dump and restore" + required: false + default: 'null' runs: using: "composite" @@ -39,6 +43,12 @@ runs: base_dir="singledb" export inputFilesPath=upgrade/singledb/verification_cleanup fi + + if [[ '${{ inputs.logical_database }}' != 'null' ]];then + base_dir="${{ inputs.logical_database }}" + export inputFilesPath=upgrade/$base_dir/verification_cleanup + fi + mvn test export inputFilesPath=input diff --git a/.github/composite-actions/setup-base-version/action.yml b/.github/composite-actions/setup-base-version/action.yml index f2aa3c9cb4..432d60fcc0 100644 --- a/.github/composite-actions/setup-base-version/action.yml +++ b/.github/composite-actions/setup-base-version/action.yml @@ -12,6 +12,10 @@ inputs: migration_mode: description: "Database migration mode for Babelfish" required: true + logical_database: + description: "Logical Babelfish database to dump and restore" + required: false + default: 'null' runs: using: "composite" @@ -111,6 +115,11 @@ runs: else base_dir="singledb" fi + + if [[ '${{ inputs.logical_database }}' != 'null' ]];then + base_dir="${{ inputs.logical_database }}" + fi + export inputFilesPath=upgrade/$base_dir/preparation mvn test for filename in $(grep -v "^ignore.*\|^#.*\|^cmd.*\|^all.*\|^$" upgrade/$base_dir/schedule); do @@ -130,7 +139,7 @@ runs: - name: Install Python id: install-python - if: ${{ matrix.upgrade-path.path[0] == 'source_latest' && steps.jdbc-upgrade-tests.outcome == 'success' }} + if: ${{ matrix.upgrade-path.path[0] == 'source_latest' && steps.jdbc-upgrade-tests.outcome == 'success' && inputs.logical_database == 'null' }} uses: actions/setup-python@v2 with: python-version: 3.7 diff --git a/.github/composite-actions/setup-dump-restore-ca/action.yml b/.github/composite-actions/setup-dump-restore-ca/action.yml index d02ed07fe6..971f51fad0 100644 --- a/.github/composite-actions/setup-dump-restore-ca/action.yml +++ b/.github/composite-actions/setup-dump-restore-ca/action.yml @@ -23,10 +23,10 @@ runs: echo "ERROR: Dump restore path length less than 2" 1>&2 exit 1 fi - + # Initial installed version is the base version previous_installed_version=${{ inputs.base_version }} - + # For every next dump+restore, below 'For' loop will add a step in dump-restore composite action which will dump the current version and restore it into next version for (( i=1 ; i<$LEN ; i++ )); do @@ -43,7 +43,15 @@ runs: uses_file=./.github/composite-actions/dump-restore-util temp="&& steps.dump-restore-version-$(($i-1)).outcome == 'success'"; [[ i -eq 1 ]] && temp="" - printf " - name: Dump and Restore to version $dump_restore_version\n id: dump-restore-version-$i\n if: always() $temp\n uses: ${uses_file}\n with: \n engine_branch: ${engine_branch}\n extension_branch: ${extension_branch}\n is_final_ver: ${is_final_ver}\n pg_old_dir: ${pg_old_dir}\n pg_new_dir: ${pg_new_dir}\n migration_mode: 'multi-db'\n\n" >> $dump_restore_version_dir_path/action.yml + logical_database_var=".\"dump-restore-version\"[${{ matrix.upgrade-path.id }}][$i].\"logical-database\"" + logical_database=$(yq $logical_database_var ${{ github.workspace }}/.github/configuration/dump-restore-test-configuration.yml) + + if [[ $logical_database == 'null' ]] + then + printf " - name: Dump and Restore to version $dump_restore_version\n id: dump-restore-version-$i\n if: always() $temp\n uses: ${uses_file}\n with: \n engine_branch: ${engine_branch}\n extension_branch: ${extension_branch}\n is_final_ver: ${is_final_ver}\n pg_old_dir: ${pg_old_dir}\n pg_new_dir: ${pg_new_dir}\n migration_mode: 'multi-db'\n\n" >> $dump_restore_version_dir_path/action.yml + else + printf " - name: Dump and Restore to version $dump_restore_version\n id: dump-restore-version-$i\n if: always() $temp\n uses: ${uses_file}\n with: \n engine_branch: ${engine_branch}\n extension_branch: ${extension_branch}\n is_final_ver: ${is_final_ver}\n pg_old_dir: ${pg_old_dir}\n pg_new_dir: ${pg_new_dir}\n migration_mode: 'multi-db'\n logical_database: ${logical_database}\n\n" >> $dump_restore_version_dir_path/action.yml + fi previous_installed_version=$dump_restore_version done diff --git a/.github/configuration/dump-restore-test-configuration.yml b/.github/configuration/dump-restore-test-configuration.yml index ced988327c..6460298876 100644 --- a/.github/configuration/dump-restore-test-configuration.yml +++ b/.github/configuration/dump-restore-test-configuration.yml @@ -1,8 +1,20 @@ dump-restore-version: [[ { - version: source.latest + version: source.latest, + logical-database: null }, - { - version: target.latest + { + version: target.latest, + logical-database: null + } +], +[ + { + version: source.latest, + logical-database: master + }, + { + version: target.latest, + logical-database: master } ]] diff --git a/.github/workflows/pg_dump-restore-test.yml b/.github/workflows/pg_dump-restore-test.yml index 6e9550f349..0584599e1f 100644 --- a/.github/workflows/pg_dump-restore-test.yml +++ b/.github/workflows/pg_dump-restore-test.yml @@ -15,7 +15,7 @@ jobs: run: | config="'$(yq -o=json ${{ github.workspace }}/.github/configuration/dump-restore-test-configuration.yml)'" config=$(echo $config | sed "s/\"/\\\\\"/g") - DUMP_RESTORE_PATH_LIST=$(node -e "let k = JSON.parse($config); let p = k['dump-restore-version'].map((itm, index) => ({ id: index, path: itm.map(i => i.version.toString().replace(/[.]/g, \"_\")), title: itm.map(i => i.version.toString().replace(/[.]/g, \"_\")).join(\"-\"), last_version: itm[itm.length - 1].version.toString().replace(/[.]/g, \"_\") })); console.log(JSON.stringify(p));") + DUMP_RESTORE_PATH_LIST=$(node -e "let k = JSON.parse($config); let p = k['dump-restore-version'].map((itm, index) => ({ id: index, path: itm.map(i => i.version.toString().replace(/[.]/g, \"_\")), title: (itm[itm.length - 1]['logical-database'] == null ? 'Instance-level-' : 'Database-level-') + itm.map(i => i.version.toString().replace(/[.]/g, \"_\")).join(\"-\"), last_version: itm[itm.length - 1].version.toString().replace(/[.]/g, \"_\") })); console.log(JSON.stringify(p));") echo "::set-output name=dump-restore-path-list::$DUMP_RESTORE_PATH_LIST" run-dump-restore-test: @@ -43,6 +43,9 @@ jobs: )" && echo "::set-output name=final-version::$( yq '."dump-restore-version"[${{ matrix.upgrade-path.id }}][-1].version' ${{ github.workspace }}/.github/configuration/dump-restore-test-configuration.yml + )" && + echo "::set-output name=logical-database::$( + yq '."dump-restore-version"[${{ matrix.upgrade-path.id }}][-1].logical-database' ${{ github.workspace }}/.github/configuration/dump-restore-test-configuration.yml )" - name: Find Engine and Extension Branches for Base Version ${{ steps.read-base-and-final-version.outputs.base-version }} @@ -66,6 +69,7 @@ jobs: extension_branch: ${{ steps.find-branch.outputs.base-extension-branch }} install_dir: ${{ steps.find-branch.outputs.base-dir }} migration_mode: 'multi-db' + logical_database: ${{ steps.read-base-and-final-version.outputs.logical-database }} - name: Setup Dump Restore Composite Action id: setup-dump-restore-ca diff --git a/contrib/babelfishpg_tsql/src/dbcmds.c b/contrib/babelfishpg_tsql/src/dbcmds.c index 701869076a..84d184fcb0 100644 --- a/contrib/babelfishpg_tsql/src/dbcmds.c +++ b/contrib/babelfishpg_tsql/src/dbcmds.c @@ -27,6 +27,7 @@ #include "utils/builtins.h" #include "utils/fmgroids.h" #include "utils/lsyscache.h" +#include "utils/regproc.h" #include "utils/rel.h" #include "utils/syscache.h" #include "utils/timestamp.h" @@ -289,7 +290,7 @@ create_bbf_db(ParseState *pstate, const CreatedbStmt *stmt) * If we can't find one after looping the entire range of sequence values * (1 to 32767), we should bail out. */ -static int16 getAvailDbid() { +static int16 getAvailDbid(void) { int16 dbid; int16 start = 0; @@ -304,6 +305,49 @@ static int16 getAvailDbid() { return dbid; } +/* + * Only called while restoring a Babelfish logical database to get new + * dbid for database being restored. The value returned will be used in + * filling missing dbid column values in a tuple being inserted into catalog + * table. + * The function will return either new generated dbid in case we are inserting + * into sys.babelfish_sysdatabases catalog or last used dbid for all other + * catalogs. + */ +int16 +getDbidForLogicalDbRestore(Oid relid) +{ + const char *prev_current_user; + int16 dbid; + + /* Get new DB ID. Need sysadmin to do that. */ + prev_current_user = GetUserNameFromId(GetUserId(), false); + bbf_set_current_user("sysadmin"); + /* For sysdatabases table we need to generate new dbid for the database we are currently restoring. */ + if (relid == sysdatabases_oid) + { + if ((dbid = getAvailDbid()) == InvalidDbid) + ereport(ERROR, + (errcode(ERRCODE_INVALID_DATABASE_DEFINITION), + errmsg("cannot find an available ID for new database."))); + } + /* + * For all the other catalog tables which contain dbid column, get dbid using current value of the + * babelfish_db_seq sequence. It is ok to fetch current value of the sequence here since we already + * have generated new dbid while inserting into sysdatabases catalog. + */ + else + { + RangeVar *sequence = makeRangeVarFromNameList(stringToQualifiedNameList("sys.babelfish_db_seq")); + Oid seqid = RangeVarGetRelid(sequence, NoLock, false); + + dbid = DirectFunctionCall1(currval_oid, seqid); + } + bbf_set_current_user(prev_current_user); + + return dbid; +} + static Oid do_create_bbf_db(const char *dbname, List *options, const char *owner) { diff --git a/contrib/babelfishpg_tsql/src/dbcmds.h b/contrib/babelfishpg_tsql/src/dbcmds.h index c25fb302b3..20cc1d1eeb 100644 --- a/contrib/babelfishpg_tsql/src/dbcmds.h +++ b/contrib/babelfishpg_tsql/src/dbcmds.h @@ -6,5 +6,6 @@ extern Oid create_bbf_db(ParseState *pstate, const CreatedbStmt *stmt); extern void drop_bbf_db(const char *dbname, bool missing_ok, bool force_drop); extern const char *get_owner_of_db(const char *dbname); extern List *grant_guest_to_logins(StringInfoData *query); +extern int16 getDbidForLogicalDbRestore(Oid relid); #endif diff --git a/contrib/babelfishpg_tsql/src/hooks.c b/contrib/babelfishpg_tsql/src/hooks.c index 5571b4240d..00d07acbc5 100644 --- a/contrib/babelfishpg_tsql/src/hooks.c +++ b/contrib/babelfishpg_tsql/src/hooks.c @@ -22,6 +22,7 @@ #include "commands/view.h" #include "common/logging.h" #include "funcapi.h" +#include "miscadmin.h" #include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" #include "optimizer/clauses.h" @@ -58,6 +59,7 @@ #include "pltsql.h" #include "pl_explain.h" #include "catalog.h" +#include "dbcmds.h" #include "rolecmds.h" #include "session.h" #include "multidb.h" @@ -109,6 +111,7 @@ static void modify_RangeTblFunction_tupdesc(char *funcname, Node *expr, TupleDes *****************************************/ static int find_attr_by_name_from_column_def_list(const char *attributeName, List *schema); static void pltsql_drop_func_default_positions(Oid objectId); +static void fill_missing_values_in_copyfrom(Relation rel, Datum *values, bool *nulls); /***************************************** * Utility Hooks @@ -181,6 +184,7 @@ static planner_hook_type prev_planner_hook = NULL; static transform_check_constraint_expr_hook_type prev_transform_check_constraint_expr_hook = NULL; static validate_var_datatype_scale_hook_type prev_validate_var_datatype_scale_hook = NULL; static modify_RangeTblFunction_tupdesc_hook_type prev_modify_RangeTblFunction_tupdesc_hook = NULL; +static fill_missing_values_in_copyfrom_hook_type prev_fill_missing_values_in_copyfrom_hook = NULL; /***************************************** * Install / Uninstall @@ -286,6 +290,9 @@ InstallExtendedHooks(void) prev_modify_RangeTblFunction_tupdesc_hook = modify_RangeTblFunction_tupdesc_hook; modify_RangeTblFunction_tupdesc_hook = modify_RangeTblFunction_tupdesc; + + prev_fill_missing_values_in_copyfrom_hook = fill_missing_values_in_copyfrom_hook; + fill_missing_values_in_copyfrom_hook = fill_missing_values_in_copyfrom; } void @@ -328,6 +335,7 @@ UninstallExtendedHooks(void) transform_check_constraint_expr_hook = prev_transform_check_constraint_expr_hook; validate_var_datatype_scale_hook = prev_validate_var_datatype_scale_hook; modify_RangeTblFunction_tupdesc_hook = prev_modify_RangeTblFunction_tupdesc_hook; + fill_missing_values_in_copyfrom_hook = prev_fill_missing_values_in_copyfrom_hook; } /***************************************** @@ -3403,3 +3411,39 @@ pltsql_set_target_table_alternative(ParseState *pstate, Node *stmt, CmdType comm return setTargetTable(pstate, relation, inh, true, requiredPerms); } + +/* + * Update values and nulls arrays with missing column values if any. + * Mainly used for Babelfish catalog tables during restore. + */ +static void +fill_missing_values_in_copyfrom(Relation rel, Datum *values, bool *nulls) +{ + Oid relid; + + if (!babelfish_dump_restore || IsBinaryUpgrade) + return; + + relid = RelationGetRelid(rel); + /* + * Insert new dbid column value in babelfish catalog if dump did + * not provide it. + */ + if (relid == sysdatabases_oid || + relid == namespace_ext_oid || + relid == bbf_view_def_oid) + { + int16 dbid = 0; + AttrNumber attnum; + + attnum = (AttrNumber) attnameAttNum(rel, "dbid", false); + Assert(attnum != InvalidAttrNumber); + + if (!nulls[attnum - 1]) + return; + + dbid = getDbidForLogicalDbRestore(relid); + values[attnum - 1] = Int16GetDatum(dbid); + nulls[attnum - 1] = false; + } +} diff --git a/contrib/babelfishpg_tsql/src/pl_handler.c b/contrib/babelfishpg_tsql/src/pl_handler.c index d8eccb3337..018666a146 100644 --- a/contrib/babelfishpg_tsql/src/pl_handler.c +++ b/contrib/babelfishpg_tsql/src/pl_handler.c @@ -433,6 +433,74 @@ pltsql_pre_parse_analyze(ParseState *pstate, RawStmt *parseTree) if (prev_pre_parse_analyze_hook) prev_pre_parse_analyze_hook(pstate, parseTree); + switch (parseTree->stmt->type) + { + case T_InsertStmt: + { + InsertStmt *stmt = (InsertStmt *) parseTree->stmt; + SelectStmt *selectStmt = (SelectStmt *) stmt->selectStmt; + A_Const *value; + Oid relid; + ListCell *lc; + + if (!babelfish_dump_restore || IsBinaryUpgrade) + break; + + relid = RangeVarGetRelid(stmt->relation, NoLock, false); + + /* + * Insert new dbid column value in babelfish catalog if dump did + * not provide it. + */ + if (relid == sysdatabases_oid || + relid == namespace_ext_oid || + relid == bbf_view_def_oid) + { + int16 dbid = 0; + ResTarget *dbidCol; + bool found = false; + + /* Skip if dbid column already exists */ + foreach(lc, stmt->cols) + { + ResTarget *col = (ResTarget *) lfirst(lc); + + if (strcasecmp(col->name, "dbid") == 0) + found = true; + } + if (found) + break; + + dbid = getDbidForLogicalDbRestore(relid); + + /* const value node to store into values clause */ + value = makeNode(A_Const); + value->val.ival.type = T_Integer; + value->val.ival.ival = dbid; + value->location = -1; + + /* dbid column to store into InsertStmt's target list */ + dbidCol = makeNode(ResTarget); + dbidCol->name = "dbid"; + dbidCol->name_location = -1; + dbidCol->indirection = NIL; + dbidCol->val = NULL; + dbidCol->location = -1; + stmt->cols = lappend(stmt->cols, dbidCol); + + foreach(lc, selectStmt->valuesLists) + { + List *sublist = (List *) lfirst(lc); + + sublist = lappend(sublist, value); + } + } + break; + } + default: + break; + } + if (sql_dialect != SQL_DIALECT_TSQL) return; diff --git a/dev-tools.sh b/dev-tools.sh index c2dde81767..8bdf35a9a2 100755 --- a/dev-tools.sh +++ b/dev-tools.sh @@ -41,11 +41,13 @@ if [ ! $1 ]; then echo " minor_version_upgrade SOURCE_WS [TARGET_WS]" echo " upgrade minor version using ALTER EXTENSION ... UPDATE" echo "" - echo " pg_dump [TARGET_WS]" + echo " pg_dump [TARGET_WS] LOGICAL_DATBABSE_NAME" echo " dump [TARGET_WS using pg_dump" + echo " LOGICAL_DATBABSE_NAME is optional if provided then only that bbf database will be dumped." echo "" - echo " restore SOURCE_WS [TARGET_WS]" + echo " restore SOURCE_WS [TARGET_WS] LOGICAL_DATBABSE_NAME" echo " restore dump files from SOURCE_WS on [TARGET_WS]" + echo " LOGICAL_DATBABSE_NAME is optional if provided then only that bbf database will be restored." echo "" echo " dumprestore SOURCE_WS [TARGET_WS]" echo " dump SOURCE_WS using pg_dump and restore it on TARGET_WS" @@ -181,8 +183,14 @@ pg_dump() { echo "Runinng pg_dumpall and pg_dump on ($1)" cd $1/postgres rm -f pg_dump_globals.sql pg_dump.sql error.log - $1/postgres/bin/pg_dumpall --username jdbc_user --globals-only --quote-all-identifiers --verbose -f pg_dump_globals.sql 2>error.log - $1/postgres/bin/pg_dump --username jdbc_user --column-inserts --quote-all-identifiers --verbose --file="pg_dump.sql" --dbname=jdbc_testdb 2>>error.log + + if [[ ! $2 ]];then + $1/postgres/bin/pg_dumpall --username jdbc_user --globals-only --quote-all-identifiers --verbose -f pg_dump_globals.sql 2>error.log + $1/postgres/bin/pg_dump --create --username jdbc_user --column-inserts --quote-all-identifiers --verbose --file="pg_dump.sql" --dbname=jdbc_testdb 2>>error.log + else + $1/postgres/bin/pg_dumpall --username jdbc_user --globals-only --quote-all-identifiers --verbose --bbf-database-name=$2 -f pg_dump_globals.sql 2>error.log + $1/postgres/bin/pg_dump --username jdbc_user --column-inserts --quote-all-identifiers --verbose --bbf-database-name=$2 --file="pg_dump.sql" --dbname=jdbc_testdb 2>>error.log + fi stop $1 } @@ -196,12 +204,13 @@ restore() { $2/postgres/bin/psql -d postgres -U $USER -c "CREATE DATABASE jdbc_testdb OWNER jdbc_user;" echo "Restoring from pg_dump" - $2/postgres/bin/psql -d jdbc_testdb -U jdbc_user -f $1/postgres/pg_dump.sql 2>>error.log - $2/postgres/bin/psql -d jdbc_testdb -U jdbc_user -c "GRANT ALL ON SCHEMA sys to jdbc_user;" - $2/postgres/bin/psql -d jdbc_testdb -U jdbc_user -c "GRANT CREATE, CONNECT, TEMPORARY ON DATABASE jdbc_testdb TO sysadmin WITH GRANT OPTION;" - $2/postgres/bin/psql -d jdbc_testdb -U jdbc_user -c "ALTER USER jdbc_user CREATEDB;" - $2/postgres/bin/psql -d jdbc_testdb -U jdbc_user -c "ALTER SYSTEM SET babelfishpg_tsql.database_name = 'jdbc_testdb';" - $2/postgres/bin/psql -d jdbc_testdb -U jdbc_user -c "SELECT pg_reload_conf();" + if [[ ! $3 ]];then + $2/postgres/bin/psql -d postgres -U jdbc_user -f $1/postgres/pg_dump.sql 2>>error.log + $2/postgres/bin/psql -d jdbc_testdb -U jdbc_user -c "ALTER SYSTEM SET babelfishpg_tsql.database_name = 'jdbc_testdb';" + $2/postgres/bin/psql -d jdbc_testdb -U jdbc_user -c "SELECT pg_reload_conf();" + else + $2/postgres/bin/psql -d jdbc_testdb -U jdbc_user -f $1/postgres/pg_dump.sql 2>>error.log + fi } if [ "$1" == "initdb" ]; then @@ -320,14 +329,14 @@ elif [ "$1" == "minor_version_upgrade" ]; then exit 0 elif [ "$1" == "pg_dump" ]; then restart $TARGET_WS || true - pg_dump $TARGET_WS + pg_dump $TARGET_WS $3 exit 0 elif [ "$1" == "restore" ]; then SOURCE_WS=$2 init_db $TARGET_WS echo "Init target workspace ($TARGET_WS) done!" - restore $SOURCE_WS $TARGET_WS + restore $SOURCE_WS $TARGET_WS $4 echo "Restored on target workspace ($TARGET_WS)!" exit 0 elif [ "$1" == "dumprestore" ]; then diff --git a/test/JDBC/expected/BABEL-3402-vu-prepare.out b/test/JDBC/expected/BABEL-3402-vu-prepare.out index f272531276..9cf2a8d5ef 100644 --- a/test/JDBC/expected/BABEL-3402-vu-prepare.out +++ b/test/JDBC/expected/BABEL-3402-vu-prepare.out @@ -54,7 +54,7 @@ varbinary -- psql -CREATE OR REPLACE FUNCTION sys.babel_3402_vu_prepare_f2(IN login SYS._ci_SYSNAME) +CREATE OR REPLACE FUNCTION master_dbo.babel_3402_vu_prepare_f2(IN login SYS._ci_SYSNAME) RETURNS SYS.VARBINARY(85) AS $$ SELECT CAST(CAST(sys.suser_id(login) AS INT) AS SYS.VARBINARY(85)); $$ @@ -68,7 +68,7 @@ go DROP VIEW IF EXISTS babel_3402_vu_prepare_v2; go -create view babel_3402_vu_prepare_v2 as select sys.babel_3402_vu_prepare_f2(-10); +create view babel_3402_vu_prepare_v2 as select babel_3402_vu_prepare_f2(-10); go select * from babel_3402_vu_prepare_v2; diff --git a/test/JDBC/expected/BABEL-CHECK-CONSTRAINT-vu-cleanup.out b/test/JDBC/expected/BABEL-CHECK-CONSTRAINT-vu-cleanup.out index 6fddbdda55..1db62e3647 100644 --- a/test/JDBC/expected/BABEL-CHECK-CONSTRAINT-vu-cleanup.out +++ b/test/JDBC/expected/BABEL-CHECK-CONSTRAINT-vu-cleanup.out @@ -9,5 +9,5 @@ DROP TABLE create_check_constraint GO -- psql -DROP TABLE tbl_creation_should_succeed; +DROP TABLE master_dbo.tbl_creation_should_succeed; GO diff --git a/test/JDBC/expected/BABEL-CHECK-CONSTRAINT-vu-prepare.out b/test/JDBC/expected/BABEL-CHECK-CONSTRAINT-vu-prepare.out index 6a81ccc42f..580b467101 100644 --- a/test/JDBC/expected/BABEL-CHECK-CONSTRAINT-vu-prepare.out +++ b/test/JDBC/expected/BABEL-CHECK-CONSTRAINT-vu-prepare.out @@ -26,7 +26,7 @@ CREATE TABLE create_check_constraint( GO -- psql -CREATE TABLE tbl_creation_should_fail ( +CREATE TABLE master_dbo.tbl_creation_should_fail ( a sys.varchar(20), CONSTRAINT tbl1_a_check CHECK ((NOT (((a)::text ~~* '11%'::text) AND (((a)::text >= '11'::text) @@ -39,7 +39,7 @@ GO Server SQLState: 0A000)~~ -CREATE TABLE tbl_creation_should_succeed ( +CREATE TABLE master_dbo.tbl_creation_should_succeed ( a sys.varchar(20) COLLATE sys.bbf_unicode_cp1_cs_as , CONSTRAINT tbl1_a_check CHECK ((NOT (((a)::text ~~* '11%'::text) AND (((a)::text >= '11'::text) diff --git a/test/JDBC/expected/BABEL-CHECK-CONSTRAINT-vu-verify.out b/test/JDBC/expected/BABEL-CHECK-CONSTRAINT-vu-verify.out index 84bc1d6c8f..dd2ba47ae7 100644 --- a/test/JDBC/expected/BABEL-CHECK-CONSTRAINT-vu-verify.out +++ b/test/JDBC/expected/BABEL-CHECK-CONSTRAINT-vu-verify.out @@ -34,12 +34,12 @@ GO -- psql -INSERT INTO tbl_creation_should_succeed VALUES ('abcd'); +INSERT INTO master_dbo.tbl_creation_should_succeed VALUES ('abcd'); GO ~~ROW COUNT: 1~~ -INSERT INTO tbl_creation_should_succeed VALUES ('11dsjkdnb'); +INSERT INTO master_dbo.tbl_creation_should_succeed VALUES ('11dsjkdnb'); GO ~~ERROR (Code: 0)~~ diff --git a/test/JDBC/expected/BABEL_OBJECT_ID-vu-cleanup.out b/test/JDBC/expected/BABEL_OBJECT_ID-vu-cleanup.out index 78afafc540..ed603c01cf 100644 --- a/test/JDBC/expected/BABEL_OBJECT_ID-vu-cleanup.out +++ b/test/JDBC/expected/BABEL_OBJECT_ID-vu-cleanup.out @@ -33,12 +33,6 @@ GO DROP DATABASE babel_object_id_db; GO -DROP TABLE babel_object_id_schema_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij.babel_object_id_table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij; -GO - -DROP SCHEMA babel_object_id_schema_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij; -GO - DROP TABLE [babel_object_id_schema .with .dot_and_spaces]."babel_object_id_t3 .with .dot_and_spaces"; GO diff --git a/test/JDBC/expected/BABEL_OBJECT_ID-vu-prepare.out b/test/JDBC/expected/BABEL_OBJECT_ID-vu-prepare.out index f12737d579..5c3da143f9 100644 --- a/test/JDBC/expected/BABEL_OBJECT_ID-vu-prepare.out +++ b/test/JDBC/expected/BABEL_OBJECT_ID-vu-prepare.out @@ -46,13 +46,6 @@ GO CREATE TABLE [babel_object_id_schema .with .dot_and_spaces]."babel_object_id_t3 .with .dot_and_spaces" (a int); GO --- To test longer schema name and table name -CREATE SCHEMA babel_object_id_schema_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij; -GO - -CREATE TABLE babel_object_id_schema_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij.babel_object_id_table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij (a int); -GO - -- To test lookup in different database CREATE DATABASE babel_object_id_db; GO diff --git a/test/JDBC/expected/BABEL_OBJECT_ID-vu-verify.out b/test/JDBC/expected/BABEL_OBJECT_ID-vu-verify.out index 0df09a6da6..a3f3be7f27 100644 --- a/test/JDBC/expected/BABEL_OBJECT_ID-vu-verify.out +++ b/test/JDBC/expected/BABEL_OBJECT_ID-vu-verify.out @@ -235,40 +235,6 @@ babel_object_id_t3 .with .dot_and_spaces ~~END~~ --- test longer schema name and table name -SELECT OBJECT_NAME(OBJECT_ID('babel_object_id_schema_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij.babel_object_id_table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij')) -GO -~~START~~ -varchar -babel_object_id_table_longer_th98997f4fc7505f5a0e4e8fa9d333617e -~~END~~ - - --- it can be also accessed with its shortened name -SELECT OBJECT_NAME(OBJECT_ID('babel_object_id_schema_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij.babel_object_id_table_longer_th98997f4fc7505f5a0e4e8fa9d333617e')) -GO -~~START~~ -varchar -babel_object_id_table_longer_th98997f4fc7505f5a0e4e8fa9d333617e -~~END~~ - - -SELECT OBJECT_NAME(OBJECT_ID('babel_object_id_schema_longer_tac6266677f55e340966ca52f80004919.babel_object_id_table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij')) -GO -~~START~~ -varchar -babel_object_id_table_longer_th98997f4fc7505f5a0e4e8fa9d333617e -~~END~~ - - -SELECT OBJECT_NAME(OBJECT_ID('babel_object_id_schema_longer_tac6266677f55e340966ca52f80004919.babel_object_id_table_longer_th98997f4fc7505f5a0e4e8fa9d333617e')) -GO -~~START~~ -varchar -babel_object_id_table_longer_th98997f4fc7505f5a0e4e8fa9d333617e -~~END~~ - - -- To test temp object CREATE TABLE #babel_object_id_temp_t1 (a int); GO diff --git a/test/JDBC/input/BABEL-3402-vu-prepare.mix b/test/JDBC/input/BABEL-3402-vu-prepare.mix index 46bc95f1e0..4d7caf3bf6 100644 --- a/test/JDBC/input/BABEL-3402-vu-prepare.mix +++ b/test/JDBC/input/BABEL-3402-vu-prepare.mix @@ -34,7 +34,7 @@ exec babel_3402_vu_prepare_p1 -10; go -- psql -CREATE OR REPLACE FUNCTION sys.babel_3402_vu_prepare_f2(IN login SYS._ci_SYSNAME) +CREATE OR REPLACE FUNCTION master_dbo.babel_3402_vu_prepare_f2(IN login SYS._ci_SYSNAME) RETURNS SYS.VARBINARY(85) AS $$ SELECT CAST(CAST(sys.suser_id(login) AS INT) AS SYS.VARBINARY(85)); $$ @@ -48,8 +48,8 @@ go DROP VIEW IF EXISTS babel_3402_vu_prepare_v2; go -create view babel_3402_vu_prepare_v2 as select sys.babel_3402_vu_prepare_f2(-10); +create view babel_3402_vu_prepare_v2 as select babel_3402_vu_prepare_f2(-10); go select * from babel_3402_vu_prepare_v2; -go \ No newline at end of file +go diff --git a/test/JDBC/input/BABEL-CHECK-CONSTRAINT-vu-cleanup.mix b/test/JDBC/input/BABEL-CHECK-CONSTRAINT-vu-cleanup.mix index 16379d0999..1db62e3647 100644 --- a/test/JDBC/input/BABEL-CHECK-CONSTRAINT-vu-cleanup.mix +++ b/test/JDBC/input/BABEL-CHECK-CONSTRAINT-vu-cleanup.mix @@ -9,5 +9,5 @@ DROP TABLE create_check_constraint GO -- psql -DROP TABLE tbl_creation_should_succeed; -GO \ No newline at end of file +DROP TABLE master_dbo.tbl_creation_should_succeed; +GO diff --git a/test/JDBC/input/BABEL-CHECK-CONSTRAINT-vu-prepare.mix b/test/JDBC/input/BABEL-CHECK-CONSTRAINT-vu-prepare.mix index 8999585bb6..2ea3d635be 100644 --- a/test/JDBC/input/BABEL-CHECK-CONSTRAINT-vu-prepare.mix +++ b/test/JDBC/input/BABEL-CHECK-CONSTRAINT-vu-prepare.mix @@ -22,7 +22,7 @@ CREATE TABLE create_check_constraint( GO -- psql -CREATE TABLE tbl_creation_should_fail ( +CREATE TABLE master_dbo.tbl_creation_should_fail ( a sys.varchar(20), CONSTRAINT tbl1_a_check CHECK ((NOT (((a)::text ~~* '11%'::text) AND (((a)::text >= '11'::text) @@ -30,10 +30,10 @@ CREATE TABLE tbl_creation_should_fail ( ); GO -CREATE TABLE tbl_creation_should_succeed ( +CREATE TABLE master_dbo.tbl_creation_should_succeed ( a sys.varchar(20) COLLATE sys.bbf_unicode_cp1_cs_as , CONSTRAINT tbl1_a_check CHECK ((NOT (((a)::text ~~* '11%'::text) AND (((a)::text >= '11'::text) AND ((a)::text < ('11'::text || 'ï¿¿'::text COLLATE sys.bbf_unicode_cp1_ci_as)))))) ); -GO \ No newline at end of file +GO diff --git a/test/JDBC/input/BABEL-CHECK-CONSTRAINT-vu-verify.mix b/test/JDBC/input/BABEL-CHECK-CONSTRAINT-vu-verify.mix index 3bcbd5da79..30e3cc1a28 100644 --- a/test/JDBC/input/BABEL-CHECK-CONSTRAINT-vu-verify.mix +++ b/test/JDBC/input/BABEL-CHECK-CONSTRAINT-vu-verify.mix @@ -18,8 +18,8 @@ INSERT INTO create_check_constraint VALUES ('11E') GO -- psql -INSERT INTO tbl_creation_should_succeed VALUES ('abcd'); +INSERT INTO master_dbo.tbl_creation_should_succeed VALUES ('abcd'); GO -INSERT INTO tbl_creation_should_succeed VALUES ('11dsjkdnb'); +INSERT INTO master_dbo.tbl_creation_should_succeed VALUES ('11dsjkdnb'); GO diff --git a/test/JDBC/input/BABEL_OBJECT_ID-vu-cleanup.mix b/test/JDBC/input/BABEL_OBJECT_ID-vu-cleanup.mix index f32e4f48da..ed603c01cf 100644 --- a/test/JDBC/input/BABEL_OBJECT_ID-vu-cleanup.mix +++ b/test/JDBC/input/BABEL_OBJECT_ID-vu-cleanup.mix @@ -33,12 +33,6 @@ GO DROP DATABASE babel_object_id_db; GO -DROP TABLE babel_object_id_schema_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij.babel_object_id_table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij; -GO - -DROP SCHEMA babel_object_id_schema_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij; -GO - DROP TABLE [babel_object_id_schema .with .dot_and_spaces]."babel_object_id_t3 .with .dot_and_spaces"; GO @@ -76,4 +70,4 @@ DROP TRIGGER babel_object_id_trg GO DROP TABLE babel_object_id_t1 -GO \ No newline at end of file +GO diff --git a/test/JDBC/input/BABEL_OBJECT_ID-vu-prepare.mix b/test/JDBC/input/BABEL_OBJECT_ID-vu-prepare.mix index 1bdd20840c..0eae854157 100644 --- a/test/JDBC/input/BABEL_OBJECT_ID-vu-prepare.mix +++ b/test/JDBC/input/BABEL_OBJECT_ID-vu-prepare.mix @@ -46,13 +46,6 @@ GO CREATE TABLE [babel_object_id_schema .with .dot_and_spaces]."babel_object_id_t3 .with .dot_and_spaces" (a int); GO --- To test longer schema name and table name -CREATE SCHEMA babel_object_id_schema_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij; -GO - -CREATE TABLE babel_object_id_schema_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij.babel_object_id_table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij (a int); -GO - -- To test lookup in different database CREATE DATABASE babel_object_id_db; GO diff --git a/test/JDBC/input/BABEL_OBJECT_ID-vu-verify.mix b/test/JDBC/input/BABEL_OBJECT_ID-vu-verify.mix index f22a58a392..994121edc7 100644 --- a/test/JDBC/input/BABEL_OBJECT_ID-vu-verify.mix +++ b/test/JDBC/input/BABEL_OBJECT_ID-vu-verify.mix @@ -94,20 +94,6 @@ GO SELECT OBJECT_NAME(OBJECT_ID('[babel_object_id_schema .with .dot_and_spaces]."babel_object_id_t3 .with .dot_and_spaces"')); GO --- test longer schema name and table name -SELECT OBJECT_NAME(OBJECT_ID('babel_object_id_schema_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij.babel_object_id_table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij')) -GO - --- it can be also accessed with its shortened name -SELECT OBJECT_NAME(OBJECT_ID('babel_object_id_schema_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij.babel_object_id_table_longer_th98997f4fc7505f5a0e4e8fa9d333617e')) -GO - -SELECT OBJECT_NAME(OBJECT_ID('babel_object_id_schema_longer_tac6266677f55e340966ca52f80004919.babel_object_id_table_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij')) -GO - -SELECT OBJECT_NAME(OBJECT_ID('babel_object_id_schema_longer_tac6266677f55e340966ca52f80004919.babel_object_id_table_longer_th98997f4fc7505f5a0e4e8fa9d333617e')) -GO - -- To test temp object CREATE TABLE #babel_object_id_temp_t1 (a int); GO @@ -350,4 +336,4 @@ USE babel_object_id_db; GO DROP TABLE dbo.babel_object_id_table_in_dbo_schema; -GO \ No newline at end of file +GO diff --git a/test/JDBC/upgrade/master/schedule b/test/JDBC/upgrade/master/schedule new file mode 100644 index 0000000000..f51af2f745 --- /dev/null +++ b/test/JDBC/upgrade/master/schedule @@ -0,0 +1,414 @@ +# Schedule File for JDBC Test Framework for local run +# 1. Lines starting with '#' will be treated as comments +# 2. To run a postgres command: cmd#!#postgresql#!# +# 3. To run a T-SQL command: cmd#!#sqlserver#!# +# 4. Keyword "all" is equivalent to running all test files in +# input folder +# 5. To add a test, add test name (without extension, -vu-prepare, -vu-verify and -vu-cleanup. For example if test file name is TestBigInt-vu-prepare.txt write TestBigInt) on a new line + +# This should be the first test to check there are no duplicated object_ids +BABEL-3613 + +babelfish_cast_floor +babel_try_parse +TestBigInt +TestBinary +TestBIT +TestChar +TestDatetime2 +TestDatetime +TestDate +TestDecimal +TestFloat +TestImage +TestInt +TestMoney +TestNumeric +TestReal +TestRowVersion +TestSmallDatetime +TestSmallInt +TestSmallMoney +# TestSQLVariant +TestText +TestTime +TestTinyInt +TestUDD +TestUniqueIdentifier +TestVarChar +TestXML +sys-assembly_types +sys-database_mirroring +# sys-databases +sys-numbered_procedures +BABEL-3121 +# sys-events +sys-suser_sid +# sys-trigger_events +BABEL-328 +# BABEL-3166 +# BABEL-3192 +# BABEL-3221 +# BABEL-3204 +# BABEL-3234 +BABEL-3402 +cast_numeric_types_to_datetime +cast_numeric_types_to_smalldatetime +# routines_definition +# column_domain_usage +# constraint_column_usage +sp_describe_first_result_set +sys-host_name +# SYSTEM_USER +indexproperty +sys-all_parameters +msdb-dbo-syspolicy_configuration +sys-all_views +datepart +sys-server_principals +fulltextserviceproperty +is_srvrolemember +msdb-dbo-fn_syspolicy_is_automation_enabled +# Takes too long, tracking with BABEL-3675 +# objectproperty +objectpropertyex +sys-column-property +sys-configurations +sys-datefirst +sys-lock_timeout +sys-max_connections +sys-original_login +sys-schema-name +# sys-objects +# sys-procedures +# sys-sysdatabases +sys-sysobjects +sys-trigger_nestlevel +# schema_resolution_proc +BABEL-404 +BABEL-493 +BABEL-621 +BABEL-775 +BABEL-1206 +BABEL-1251 +BABEL-1319 +BABEL-1444 +BABEL-1465 +BABEL-1466 +BABEL-1654 +BABEL-1715 +BABEL-2086 +BABEL-3314 +BABEL-TABLEOPTIONS +BABEL-2765 +BABEL-2819 +BABEL-2917 +BABEL-2955 +BABEL-3358 +BABEL-3747 +BABEL-3781 +temp-tables +# table-variable +# TestNotNull +Test-Identity +Test-Computed-Columns +BABEL-1189 +BABEL-1062 +BABEL-1243 +BABEL-1493 +BABEL-1963 +BABEL-2203 +BABEL-2208 +BABEL-2257 +BABEL-2449 +BABEL-2535 +BABEL-2787-2 +BABEL-2787 +BABEL-2805 +BABEL-2812 +BABEL-2845 +BABEL-2884 +BABEL-2944 +BABEL-3116 +# BABEL-3117 +BABEL-3118 +BABEL-3249 +BABEL-3486 +BABEL-3474 +BABEL-3614 +BABEL-3646 +BABEL-383 +BABEL-405 +BABEL-937 +forjson +forjson-subquery +forjson-datatypes +forxml +forxml-subquery +BABEL-PROCID +babel_trigger +insteadoftriggers_with_transaction +insteadof_nested_trigger_inside_proc +insteadof_nested_trigger_with_dml +nested_trigger_inside_proc +nested_trigger_with_dml +triggers_with_transaction +Test-sp_addrole +Test-sp_addrolemember +Test-sp_droprole +Test-sp_droprolemember +Test-sp_helpdbfixedrole +# Test-sp_helpsrvrolemember +# Test-sp_helpuser +Test-sp_set_session_context +Test-sp_set_session_context-dep +TestTableType +# BABEL-CROSS-DB +# BABEL-LOGIN +# BABEL-USER +# BABEL-ROLE +# babelfish_sysdatabases +babelfish_namespace_ext +# babelfish_authid_login_ext +# babelfish_authid_user_ext +babelfish_inconsistent_metadata +babelfish_migration_mode +# schema_resolution_func +BABEL-3147 +collation_tests_arabic +collation_tests_greek +collation_tests_mongolian +collation_tests_polish +collation_tests +babel_datetime +babel_char +BABEL-SQUARE +BABEL-728 +babel_function_string +BABEL-1566 +BABEL-3360 +BABEL-3380 +babel_isnumeric +# HAS_DBACCESS +BABEL-1475 +BABEL-1510 +BABEL-3213 +BABEL-3010 +BABEL-3369 +BABEL-3370 +BABEL-RAND +BABEL-741 +# BABEL-ROLE-MEMBER +tdscollation +BABEL-EXTENDEDPROPERTY +BABEL-EXECUTE_AS_CALLER +sys-filegroups +sys-filetables +sys-fulltext_indexes +sys-hash_indexes +sys-plan_guides +sp_tablecollations +sys-assemblies +# BABEL-LOGIN-USER-EXT +bitwise_not-operator +BABEL-1683 +BABEL-1953 +schema_resolution_trigger +sys_all_objects-dep +sys-columns-dep +# sys-databases-dep +# sys-foreign_key_columns-dep +# sys-foreign_keys-dep +# sys-identity_columns-dep +sys-indexes-dep +# sys-key_constraints-dep +sys-schemas-dep +# sys-sp_tables_view-dep +sys-sysforeignkeys-dep +# sys-tables-dep +# sys-types-dep +sys-views-dep +sys-check_constraints-dep +sys-computed_columns-dep +sys-default_constraints-dep +sys-index_columns-dep +# sys-sp_databases-dep +sys-syscolumns-dep +# sys-dm_exec_connections-dep +# sys-dm_exec_sessions-dep +sys-table_types-dep +sys-all_sql_modules-dep +sys-sql_modules-dep +# sys-system_sql_modules-dep +sys-triggers-dep +sys-proc_param_helper-dep +BABEL-2877 +# sys-sp_pkeys +# sys-sp_statistics +BABEL-APPLOCK +BABEL-1438 +BABEL-SP_DATATYPE_INFO +# BABEL-SPCOLUMNS +# BABEL-SP_TABLES +# BABEL-SP_SPECIAL_COLUMNS +# BABEL-SP_TABLE_PRIVILIGES +# BABEL-SP_FKEYS +# BABEL-SP_STORED_PROCEDURES +# BABEL-SP_SPROC_COLUMNS +# BABEL-3000 +sys-sp_pkeys-dep +sys-sp_statistics-dep +BABEL-SPCOLUMNS-dep +BABEL-SP_COLUMNS_MANAGED-dep +BABEL-SP_SPECIAL_COLUMNS-dep +BABEL-SP_SPECIAL_COLUMNS_100-dep +BABEL-SP_FKEYS-dep +BABEL-SP_STORED_PROCEDURES-dep +BABEL-SP_SPROC_COLUMNS-dep +BABEL-SP_SPROC_COLUMNS_100-dep +BABEL-3000-dep +Test-sp_helprole-dep +Test-sp_helprolemember-dep +format +msdb-dbo-syspolicy_system_health_state +dateadd_internal_df +sys-all_columns +sys-all_columns-dep +# sys-all_sql_modules +sys-assembly_modules +sys-change_tracking_databases +sys-change_tracking_tables +sys-check_constraints +sys-columns +sys-computed_columns +sys-data_spaces +sys-database_files +sys-database_filestream_options +sys-database_recovery_status +sys-default_constraints +# sys-dm_exec_connections +# sys-dm_exec_sessions +sys-dm_hadr_cluster +sys-dm_hadr_database_replica_states +sys-dm_os_host_info +sys-endpoints +sys-extended_properties +sys-filetable_system_defined_objects +# sys-foreign_key_columns +# sys-foreign_keys +sys-fulltext_catalogs +sys-fulltext_index_columns +sys-fulltext_languages +sys-fulltext_stoplists +# sys-identity_columns +# sys-index_columns +# sys-indexes +# sys-key_constraints +sys-master_files +sys-partitions +sys-partitions-dep +sys-registered_search_property_lists +sys-schemas +sys-selective_xml_index_paths +sys-sid_binary +# sys-sp_databases +# sys-sp_tables_view +sys-spatial_index_tessellations +sys-spatial_indexes +sys-stats +sys-synonyms +sys-syscharsets +# sys-syscolumns +# sys-sysforeignkeys +sys-syslanguages +# sys-system_sql_modules +# sys-sql_modules +sys-table_types +# sys-tables +# sys-triggers +# sys-types +# sys-views +sys-xml_indexes +sys-xml_schema_collections +sys_all_objects +sys_babelfish_configurations_view +BABEL-1249 +BABEL-1291 +BABEL-1994-CHAR +BABEL-1994-VARCHAR +BABEL-889 +babel_417 +# babel_datatype_sqlvariant +babel_sqlvariant_cast_compare +BABEL-3347 +BABEL-3144 +sys-all_parameters-dep +BABEL-3556 +BABEL-3588 +BABEL-3268 +# BABEL-3513 +# BABEL_GRANT_CONNECT +# BABEL-sp_helpdb +BABEL-2795 +babelfish_integrity_checker +get_tds_id +BABEL-PG-SYSTEM-FUNCTIONS +# BABEL-3655 +# sys-table_types_internal +sys-table_types_internal-dep +BABEL-CHECK-CONSTRAINT +# BABEL-3640 +# sys-sysindexes +sys-system_objects +# ISC-Views +ISC-Tables +# ISC-Columns +#ISC-Check-Constraints +# ISC-Table_Constraints +# sys_server_principals_dep +# sys_database_principals_dep +TestVariableDataLength +BABEL-3801 +datediff_big +app_name +atn2 +str +# case_insensitive_collation +# linked_servers +# ISC-sequences +# jira-BABEL-3504-upgrade +# test_windows_login +# sys-has_perms_by_name +sys-has_perms_by_name-dep +# BABEL_SCHEMATA +isc-schemata-dep +AVG-Aggregate-common +AVG-Aggregate-Dep +bbf_view_def +# BABEL_OBJECT_ID +BABEL-3802 +datediff_internal_date +# BABEL_OBJECT_NAME +# Test_user_from_win_login +BABEL-3914 +# Babel_domain_mapping_test +# BABEL-3828 +# BABEL-3844 +BABEL-3748 +# test_windows_alter_login +# sys-systypes +openjson +BABEL-3702 +BABEL-3696 +# Test-sp_babelfish_volatility +# BABEL_OBJECT_DEFINITION +Test-sp_rename +Test-sp_rename-dep +# openquery_upgrd +BABEL-3657 +# test_windows_alter_user +# BABEL-733 +BABEL-3938 +BABEL-NEXT-VALUE-FOR +binary-index +# test_windows_sp_helpuser From 23d4663907f662fcdb107a3c23f1dcb72dfec79c Mon Sep 17 00:00:00 2001 From: Deepakshi Mittal <78574784+deepakshi-mittal@users.noreply.github.com> Date: Wed, 15 Mar 2023 10:38:04 -0700 Subject: [PATCH 011/363] Fix: Corrected compatibility level returned by sp_helpdb Added test cases for same Task: BABEL-4029 Signed-off-by: Deepakshi Mittal --- contrib/babelfishpg_tsql/src/catalog.c | 2 +- test/JDBC/expected/BABEL-3549.out | 4 ++-- test/JDBC/expected/BABEL-sp_helpdb-vu-verify.out | 16 ++++++++-------- ...leanup__13_4__sys-databases-dep-vu-verify.out | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/contrib/babelfishpg_tsql/src/catalog.c b/contrib/babelfishpg_tsql/src/catalog.c index 0588a58ab4..139f9b0a91 100644 --- a/contrib/babelfishpg_tsql/src/catalog.c +++ b/contrib/babelfishpg_tsql/src/catalog.c @@ -417,7 +417,7 @@ babelfish_helpdb(PG_FUNCTION_ARGS) values[4] = CStringGetTextDatum(tmstmp_str); nulls[5] = 1; - nulls[6] = 1; + values[6] = UInt8GetDatum(120); tuplestore_putvalues(tupstore, tupdesc, values, nulls); } diff --git a/test/JDBC/expected/BABEL-3549.out b/test/JDBC/expected/BABEL-3549.out index 5fe25d6035..3a7cd9219f 100644 --- a/test/JDBC/expected/BABEL-3549.out +++ b/test/JDBC/expected/BABEL-3549.out @@ -29,8 +29,8 @@ SELECT name, db_size, owner, status, compatibility_level FROM sys.babelfish_help GO ~~START~~ varchar#!#varchar#!#varchar#!#varchar#!#smallint -master#!##!#jdbc_user#!##!# -babel_3549_db1#!##!#babel_3549_login1#!##!# +master#!##!#jdbc_user#!##!#120 +babel_3549_db1#!##!#babel_3549_login1#!##!#120 ~~END~~ diff --git a/test/JDBC/expected/BABEL-sp_helpdb-vu-verify.out b/test/JDBC/expected/BABEL-sp_helpdb-vu-verify.out index cdc6821c92..c5203a3785 100644 --- a/test/JDBC/expected/BABEL-sp_helpdb-vu-verify.out +++ b/test/JDBC/expected/BABEL-sp_helpdb-vu-verify.out @@ -2,8 +2,8 @@ SELECT name, compatibility_level FROM sys.babelfish_helpdb() WHERE name IN ('mas GO ~~START~~ varchar#!#smallint -master#!# -babel_sp_helpdb_db#!# +master#!#120 +babel_sp_helpdb_db#!#120 ~~END~~ @@ -12,14 +12,14 @@ SELECT name, compatibility_level FROM sys.babelfish_helpdb('master'); GO ~~START~~ varchar#!#smallint -master#!# +master#!#120 ~~END~~ SELECT name, compatibility_level FROM sys.babelfish_helpdb('babel_sp_helpdb_db'); GO ~~START~~ varchar#!#smallint -babel_sp_helpdb_db#!# +babel_sp_helpdb_db#!#120 ~~END~~ @@ -46,14 +46,14 @@ SELECT name, compatibility_level FROM sys.babelfish_helpdb('MaSteR'); GO ~~START~~ varchar#!#smallint -master#!# +master#!#120 ~~END~~ SELECT name, compatibility_level FROM sys.babelfish_helpdb('bAbeL_sP_helPdb_Db'); GO ~~START~~ varchar#!#smallint -babel_sp_helpdb_db#!# +babel_sp_helpdb_db#!#120 ~~END~~ @@ -62,14 +62,14 @@ SELECT name, compatibility_level FROM sys.babelfish_helpdb('MaSteR '); GO ~~START~~ varchar#!#smallint -master#!# +master#!#120 ~~END~~ SELECT name, compatibility_level FROM sys.babelfish_helpdb('bAbeL_sP_helPdb_Db '); GO ~~START~~ varchar#!#smallint -babel_sp_helpdb_db#!# +babel_sp_helpdb_db#!#120 ~~END~~ diff --git a/test/JDBC/expected/latest__verification_cleanup__13_4__sys-databases-dep-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__13_4__sys-databases-dep-vu-verify.out index d1edafb304..099e22e824 100644 --- a/test/JDBC/expected/latest__verification_cleanup__13_4__sys-databases-dep-vu-verify.out +++ b/test/JDBC/expected/latest__verification_cleanup__13_4__sys-databases-dep-vu-verify.out @@ -2,7 +2,7 @@ SELECT name, compatibility_level, collation_name FROM sys_databases_view_dep_vu_ GO ~~START~~ text#!#tinyint#!#nvarchar -db_sys_databases_dep_vu_prepare#!##!#bbf_unicode_cp1_ci_as +db_sys_databases_dep_vu_prepare#!#120#!#bbf_unicode_cp1_ci_as ~~END~~ From 04c27f3aaaea4eb37b8c3a29a6accbfafec8e809 Mon Sep 17 00:00:00 2001 From: pratikzode <73869399+pratikzode@users.noreply.github.com> Date: Wed, 15 Mar 2023 10:43:53 -0700 Subject: [PATCH 012/363] Support STDEV(), STDEVP(), VAR(), VARP() statistical T-SQL aggregates STDEV() STDEV function is used in SQL to calculate the standard deviation of a set of values in a given column of a table. STDEV stands for "standard deviation," which is a statistical measure that represents the degree of variation of a set of values from its mean or average STDEVP() STDEVP function is similar to the STDEV function in SQL, but it calculates the standard deviation of an entire population rather than a sample of the population. "STDEVP" stands for "standard deviation of a population". VAR() VAR function is used in SQL to calculate the variance of a set of values in a given column of a table. "VAR" stands for "variance," which is a statistical measure that represents how much a set of values varies from its mean or average. VARP() VARP function is used in SQL to calculate the variance of an entire population rather than a sample of the population. "VARP" stands for "variance of a population" Task: BABEL-745 Signed-off-by: pratikzode --- .../babelfishpg_tsql/sql/sys_functions.sql | 36 ++++ .../babelfishpg_tsql--3.1.0--3.2.0.sql | 36 +++- .../src/tsqlUnsupportedFeatureHandler.cpp | 8 - test/JDBC/expected/BABEL-745-vu-cleanup.out | 26 +++ test/JDBC/expected/BABEL-745-vu-prepare.out | 90 +++++++++ test/JDBC/expected/BABEL-745-vu-verify.out | 183 ++++++++++++++++++ test/JDBC/input/BABEL-745-vu-cleanup.sql | 26 +++ test/JDBC/input/BABEL-745-vu-prepare.sql | 88 +++++++++ test/JDBC/input/BABEL-745-vu-verify.sql | 67 +++++++ test/JDBC/upgrade/14_7/schedule | 1 + test/JDBC/upgrade/latest/schedule | 1 + 11 files changed, 553 insertions(+), 9 deletions(-) create mode 100644 test/JDBC/expected/BABEL-745-vu-cleanup.out create mode 100644 test/JDBC/expected/BABEL-745-vu-prepare.out create mode 100644 test/JDBC/expected/BABEL-745-vu-verify.out create mode 100644 test/JDBC/input/BABEL-745-vu-cleanup.sql create mode 100644 test/JDBC/input/BABEL-745-vu-prepare.sql create mode 100644 test/JDBC/input/BABEL-745-vu-verify.sql diff --git a/contrib/babelfishpg_tsql/sql/sys_functions.sql b/contrib/babelfishpg_tsql/sql/sys_functions.sql index a9889223c5..baea629522 100644 --- a/contrib/babelfishpg_tsql/sql/sys_functions.sql +++ b/contrib/babelfishpg_tsql/sql/sys_functions.sql @@ -1834,6 +1834,42 @@ AS 'babelfishpg_tsql', 'int_ceiling' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; CREATE OR REPLACE FUNCTION sys.ceiling(tinyint) RETURNS TINYINT AS 'babelfishpg_tsql', 'int_ceiling' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +CREATE AGGREGATE sys.STDEV(float8) ( + SFUNC = float8_accum, + FINALFUNC = float8_stddev_samp, + STYPE = float8[], + COMBINEFUNC = float8_combine, + PARALLEL = SAFE, + INITCOND = '{0,0,0}' +); + +CREATE AGGREGATE sys.STDEVP(float8) ( + SFUNC = float8_accum, + FINALFUNC = float8_stddev_pop, + STYPE = float8[], + COMBINEFUNC = float8_combine, + PARALLEL = SAFE, + INITCOND = '{0,0,0}' +); + +CREATE AGGREGATE sys.VAR(float8) ( + SFUNC = float8_accum, + FINALFUNC = float8_var_samp, + STYPE = float8[], + COMBINEFUNC = float8_combine, + PARALLEL = SAFE, + INITCOND = '{0,0,0}' +); + +CREATE AGGREGATE sys.VARP(float8) ( + SFUNC = float8_accum, + FINALFUNC = float8_var_pop, + STYPE = float8[], + COMBINEFUNC = float8_combine, + PARALLEL = SAFE, + INITCOND = '{0,0,0}' +); + CREATE OR REPLACE FUNCTION sys.microsoftversion() RETURNS INTEGER AS $BODY$ diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql index 190edbe812..1b398e26bf 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql @@ -69,6 +69,41 @@ LANGUAGE C VOLATILE; -- Unmark babelfish_configurations as configuration table SELECT sys.pg_extension_config_remove('sys.babelfish_configurations'); +CREATE AGGREGATE sys.STDEV(float8) ( + SFUNC = float8_accum, + FINALFUNC = float8_stddev_samp, + STYPE = float8[], + COMBINEFUNC = float8_combine, + PARALLEL = SAFE, + INITCOND = '{0,0,0}' +); + +CREATE AGGREGATE sys.STDEVP(float8) ( + SFUNC = float8_accum, + FINALFUNC = float8_stddev_pop, + STYPE = float8[], + COMBINEFUNC = float8_combine, + PARALLEL = SAFE, + INITCOND = '{0,0,0}' +); + +CREATE AGGREGATE sys.VAR(float8) ( + SFUNC = float8_accum, + FINALFUNC = float8_var_samp, + STYPE = float8[], + COMBINEFUNC = float8_combine, + PARALLEL = SAFE, + INITCOND = '{0,0,0}' +); + +CREATE AGGREGATE sys.VARP(float8) ( + SFUNC = float8_accum, + FINALFUNC = float8_var_pop, + STYPE = float8[], + COMBINEFUNC = float8_combine, + PARALLEL = SAFE, + INITCOND = '{0,0,0}' +); ALTER FUNCTION sys.json_modify RENAME TO json_modify_deprecated_in_3_2_0; @@ -237,4 +272,3 @@ DROP FUNCTION sys.pg_extension_config_remove(REGCLASS); -- Reset search_path to not affect any subsequent scripts SELECT set_config('search_path', trim(leading 'sys, ' from current_setting('search_path')), false); - diff --git a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp index b74342b373..d391db3e1e 100644 --- a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp @@ -1301,14 +1301,6 @@ antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitFunction_call(TSqlParser:: antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitAggregate_windowed_function(TSqlParser::Aggregate_windowed_functionContext *ctx) { - if (ctx->STDEV()) - handle(INSTR_UNSUPPORTED_TSQL_STDEV_FUNCTION, ctx->STDEV()); - if (ctx->STDEVP()) - handle(INSTR_UNSUPPORTED_TSQL_STDEVP_FUNCTION, ctx->STDEVP()); - if (ctx->VAR()) - handle(INSTR_UNSUPPORTED_TSQL_VAR_FUNCTION, ctx->VAR()); - if (ctx->VARP()) - handle(INSTR_UNSUPPORTED_TSQL_VARP_FUNCTION, ctx->VARP()); if (ctx->CHECKSUM_AGG()) handle(INSTR_UNSUPPORTED_TSQL_CHECKSUM_AGG_FUNCTION, ctx->CHECKSUM_AGG()); if (ctx->GROUPING_ID()) diff --git a/test/JDBC/expected/BABEL-745-vu-cleanup.out b/test/JDBC/expected/BABEL-745-vu-cleanup.out new file mode 100644 index 0000000000..921ca24fc8 --- /dev/null +++ b/test/JDBC/expected/BABEL-745-vu-cleanup.out @@ -0,0 +1,26 @@ +DROP VIEW IF EXISTS v_SalesData; +GO + +DROP VIEW IF EXISTS v1_SalesData; +GO + +DROP VIEW IF EXISTS v2_SalesData; +GO + +DROP VIEW IF EXISTS v3_SalesData; +GO + +DROP TABLE IF EXISTS SalesData; +GO + +DROP PROCEDURE IF EXISTS sp_CalculateStdev; +GO + +DROP PROCEDURE IF EXISTS sp1_CalculateStdev; +GO + +DROP PROCEDURE IF EXISTS sp2_CalculateStdev; +GO + +DROP PROCEDURE IF EXISTS sp3_CalculateStdev; +GO diff --git a/test/JDBC/expected/BABEL-745-vu-prepare.out b/test/JDBC/expected/BABEL-745-vu-prepare.out new file mode 100644 index 0000000000..22416188e7 --- /dev/null +++ b/test/JDBC/expected/BABEL-745-vu-prepare.out @@ -0,0 +1,90 @@ +-- Create SalesData table +CREATE TABLE SalesData ( + Product varchar(50), + SalesAmount float8 +); +-- Insert some sample data +INSERT INTO SalesData (Product, SalesAmount) +VALUES ('Product A', 100.00), ('Product A', 150.00), ('Product A', 200.00), + ('Product B', 50.00), ('Product B', 75.00), ('Product B', 100.00), + ('Product C', 25.00), ('Product C', 50.00), ('Product C', 75.00); +GO +~~ROW COUNT: 9~~ + + +-- Create a view for SalesData +CREATE VIEW v_SalesData AS +SELECT Product, STDEV(SalesAmount) AS SalesAmount +FROM SalesData +GROUP BY Product +ORDER BY Product, SalesAmount; +GO + +CREATE VIEW v1_SalesData AS +SELECT Product, STDEVP(SalesAmount) AS SalesAmount +FROM SalesData +GROUP BY Product +ORDER BY Product, SalesAmount; +GO + +CREATE VIEW v2_SalesData AS +SELECT Product, VAR(SalesAmount) AS SalesAmount +FROM SalesData +GROUP BY Product +ORDER BY Product, SalesAmount; +GO + +CREATE VIEW v3_SalesData AS +SELECT Product, VARP(SalesAmount) AS SalesAmount +FROM SalesData +GROUP BY Product +ORDER BY Product, SalesAmount; +GO + +-- Create a stored procedure for STDEV calculation +CREATE PROCEDURE sp_CalculateStdev + @Product varchar(50) +AS +BEGIN + SELECT STDEV(SalesAmount) AS SalesAmountStdev + FROM SalesData + WHERE Product = @Product + GROUP BY Product; +END; +GO + +-- Create a stored procedure for STDEVP calculation +CREATE PROCEDURE sp1_CalculateStdev + @Product varchar(50) +AS +BEGIN + SELECT STDEVP(SalesAmount) AS SalesAmountStdev + FROM SalesData + WHERE Product = @Product + GROUP BY Product; +END; +GO + +-- Create a stored procedure for VAR calculation +CREATE PROCEDURE sp2_CalculateStdev + @Product varchar(50) +AS +BEGIN + SELECT VAR(SalesAmount) AS SalesAmountStdev + FROM SalesData + WHERE Product = @Product + GROUP BY Product; +END; +GO + +-- Create a stored procedure for VARP calculation +CREATE PROCEDURE sp3_CalculateStdev + @Product varchar(50) +AS +BEGIN + SELECT VARP(SalesAmount) AS SalesAmountStdev + FROM SalesData + WHERE Product = @Product + GROUP BY Product; +END; +GO diff --git a/test/JDBC/expected/BABEL-745-vu-verify.out b/test/JDBC/expected/BABEL-745-vu-verify.out new file mode 100644 index 0000000000..9857baf7ef --- /dev/null +++ b/test/JDBC/expected/BABEL-745-vu-verify.out @@ -0,0 +1,183 @@ +Select * from SalesData +ORDER BY Product, SalesAmount; +GO +~~START~~ +varchar#!#float +Product A#!#100.0 +Product A#!#150.0 +Product A#!#200.0 +Product B#!#50.0 +Product B#!#75.0 +Product B#!#100.0 +Product C#!#25.0 +Product C#!#50.0 +Product C#!#75.0 +~~END~~ + + +SELECT * FROM v_SalesData +GO +~~START~~ +varchar#!#float +Product A#!#50.0 +Product B#!#25.0 +Product C#!#25.0 +~~END~~ + + +SELECT * FROM v1_SalesData +GO +~~START~~ +varchar#!#float +Product A#!#40.824829046386306 +Product B#!#20.412414523193153 +Product C#!#20.412414523193153 +~~END~~ + + +SELECT * FROM v2_SalesData +GO +~~START~~ +varchar#!#float +Product A#!#2500.0 +Product B#!#625.0 +Product C#!#625.0 +~~END~~ + + +SELECT * FROM v3_SalesData +GO +~~START~~ +varchar#!#float +Product A#!#1666.6666666666667 +Product B#!#416.6666666666667 +Product C#!#416.6666666666667 +~~END~~ + + +SELECT STDEV(SalesAmount) AS SalesAmount +FROM SalesData; +GO +~~START~~ +float +54.48623679425842 +~~END~~ + + +-- This should throw an error since STDEV cannot be applied to a non-numeric data type +SELECT STDEV(Product) AS ProductStdev +FROM SalesData; +GO +~~START~~ +float +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type double precision: "Product A")~~ + + +SELECT VAR(SalesAmount) AS SalesAmountStdev +FROM SalesData +GROUP BY Product +ORDER BY Product ASC; +GO +~~START~~ +float +2500.0 +625.0 +625.0 +~~END~~ + + +SELECT VARP(SalesAmount) AS SalesAmountStdev +FROM SalesData +GROUP BY Product +ORDER BY Product ASC; +GO +~~START~~ +float +1666.6666666666667 +416.6666666666667 +416.6666666666667 +~~END~~ + + +EXEC sp_CalculateStdev 'Product A'; +GO +~~START~~ +float +50.0 +~~END~~ + + +EXEC sp1_CalculateStdev 'Product A'; +GO +~~START~~ +float +40.824829046386306 +~~END~~ + + +EXEC sp2_CalculateStdev 'Product A'; +GO +~~START~~ +float +2500.0 +~~END~~ + + +EXEC sp3_CalculateStdev 'Product A'; +GO +~~START~~ +float +1666.6666666666667 +~~END~~ + + +--Float8 +SELECT VARP(CAST(1.0 AS float8)), VAR(CAST(2.0 AS float8)); +GO +~~START~~ +float#!#float +0.0#!# +~~END~~ + + +SELECT STDEVP(CAST(3.0 AS float8)), STDEV(CAST(4.0 AS float8)); +GO +~~START~~ +float#!#float +0.0#!# +~~END~~ + + +SELECT VARP(CAST('inf' AS float8)), VAR(CAST('inf' AS float8)); +GO +~~START~~ +float#!#float +NaN#!# +~~END~~ + + +SELECT STDEVP(CAST('inf' AS float8)), STDEV(CAST('inf' AS float8)); +GO +~~START~~ +float#!#float +NaN#!# +~~END~~ + + +SELECT VARP(CAST('nan' AS float8)), VAR(CAST('nan' AS float8)); +GO +~~START~~ +float#!#float +NaN#!# +~~END~~ + + +SELECT STDEVP(CAST('nan' AS float8)), STDEV(CAST('nan' AS float8)); +GO +~~START~~ +float#!#float +NaN#!# +~~END~~ + diff --git a/test/JDBC/input/BABEL-745-vu-cleanup.sql b/test/JDBC/input/BABEL-745-vu-cleanup.sql new file mode 100644 index 0000000000..921ca24fc8 --- /dev/null +++ b/test/JDBC/input/BABEL-745-vu-cleanup.sql @@ -0,0 +1,26 @@ +DROP VIEW IF EXISTS v_SalesData; +GO + +DROP VIEW IF EXISTS v1_SalesData; +GO + +DROP VIEW IF EXISTS v2_SalesData; +GO + +DROP VIEW IF EXISTS v3_SalesData; +GO + +DROP TABLE IF EXISTS SalesData; +GO + +DROP PROCEDURE IF EXISTS sp_CalculateStdev; +GO + +DROP PROCEDURE IF EXISTS sp1_CalculateStdev; +GO + +DROP PROCEDURE IF EXISTS sp2_CalculateStdev; +GO + +DROP PROCEDURE IF EXISTS sp3_CalculateStdev; +GO diff --git a/test/JDBC/input/BABEL-745-vu-prepare.sql b/test/JDBC/input/BABEL-745-vu-prepare.sql new file mode 100644 index 0000000000..1289c43864 --- /dev/null +++ b/test/JDBC/input/BABEL-745-vu-prepare.sql @@ -0,0 +1,88 @@ +-- Create SalesData table +CREATE TABLE SalesData ( + Product varchar(50), + SalesAmount float8 +); +-- Insert some sample data +INSERT INTO SalesData (Product, SalesAmount) +VALUES ('Product A', 100.00), ('Product A', 150.00), ('Product A', 200.00), + ('Product B', 50.00), ('Product B', 75.00), ('Product B', 100.00), + ('Product C', 25.00), ('Product C', 50.00), ('Product C', 75.00); +GO + +-- Create a view for SalesData +CREATE VIEW v_SalesData AS +SELECT Product, STDEV(SalesAmount) AS SalesAmount +FROM SalesData +GROUP BY Product +ORDER BY Product, SalesAmount; +GO + +CREATE VIEW v1_SalesData AS +SELECT Product, STDEVP(SalesAmount) AS SalesAmount +FROM SalesData +GROUP BY Product +ORDER BY Product, SalesAmount; +GO + +CREATE VIEW v2_SalesData AS +SELECT Product, VAR(SalesAmount) AS SalesAmount +FROM SalesData +GROUP BY Product +ORDER BY Product, SalesAmount; +GO + +CREATE VIEW v3_SalesData AS +SELECT Product, VARP(SalesAmount) AS SalesAmount +FROM SalesData +GROUP BY Product +ORDER BY Product, SalesAmount; +GO + +-- Create a stored procedure for STDEV calculation +CREATE PROCEDURE sp_CalculateStdev + @Product varchar(50) +AS +BEGIN + SELECT STDEV(SalesAmount) AS SalesAmountStdev + FROM SalesData + WHERE Product = @Product + GROUP BY Product; +END; +GO + +-- Create a stored procedure for STDEVP calculation +CREATE PROCEDURE sp1_CalculateStdev + @Product varchar(50) +AS +BEGIN + SELECT STDEVP(SalesAmount) AS SalesAmountStdev + FROM SalesData + WHERE Product = @Product + GROUP BY Product; +END; +GO + +-- Create a stored procedure for VAR calculation +CREATE PROCEDURE sp2_CalculateStdev + @Product varchar(50) +AS +BEGIN + SELECT VAR(SalesAmount) AS SalesAmountStdev + FROM SalesData + WHERE Product = @Product + GROUP BY Product; +END; +GO + +-- Create a stored procedure for VARP calculation +CREATE PROCEDURE sp3_CalculateStdev + @Product varchar(50) +AS +BEGIN + SELECT VARP(SalesAmount) AS SalesAmountStdev + FROM SalesData + WHERE Product = @Product + GROUP BY Product; +END; +GO diff --git a/test/JDBC/input/BABEL-745-vu-verify.sql b/test/JDBC/input/BABEL-745-vu-verify.sql new file mode 100644 index 0000000000..83f3679e73 --- /dev/null +++ b/test/JDBC/input/BABEL-745-vu-verify.sql @@ -0,0 +1,67 @@ +Select * from SalesData +ORDER BY Product, SalesAmount; +GO + +SELECT * FROM v_SalesData +GO + +SELECT * FROM v1_SalesData +GO + +SELECT * FROM v2_SalesData +GO + +SELECT * FROM v3_SalesData +GO + +SELECT STDEV(SalesAmount) AS SalesAmount +FROM SalesData; +GO + +-- This should throw an error since STDEV cannot be applied to a non-numeric data type +SELECT STDEV(Product) AS ProductStdev +FROM SalesData; +GO + +SELECT VAR(SalesAmount) AS SalesAmountStdev +FROM SalesData +GROUP BY Product +ORDER BY Product ASC; +GO + +SELECT VARP(SalesAmount) AS SalesAmountStdev +FROM SalesData +GROUP BY Product +ORDER BY Product ASC; +GO + +EXEC sp_CalculateStdev 'Product A'; +GO + +EXEC sp1_CalculateStdev 'Product A'; +GO + +EXEC sp2_CalculateStdev 'Product A'; +GO + +EXEC sp3_CalculateStdev 'Product A'; +GO + +--Float8 +SELECT VARP(CAST(1.0 AS float8)), VAR(CAST(2.0 AS float8)); +GO + +SELECT STDEVP(CAST(3.0 AS float8)), STDEV(CAST(4.0 AS float8)); +GO + +SELECT VARP(CAST('inf' AS float8)), VAR(CAST('inf' AS float8)); +GO + +SELECT STDEVP(CAST('inf' AS float8)), STDEV(CAST('inf' AS float8)); +GO + +SELECT VARP(CAST('nan' AS float8)), VAR(CAST('nan' AS float8)); +GO + +SELECT STDEVP(CAST('nan' AS float8)), STDEV(CAST('nan' AS float8)); +GO diff --git a/test/JDBC/upgrade/14_7/schedule b/test/JDBC/upgrade/14_7/schedule index b5f1ee979c..30ab4de85a 100644 --- a/test/JDBC/upgrade/14_7/schedule +++ b/test/JDBC/upgrade/14_7/schedule @@ -392,3 +392,4 @@ Test-sp_babelfish_volatility BABEL-733 BABEL-3938 binary-index +BABEL-745 diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index 8f976d0aa4..08746dffb1 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -409,6 +409,7 @@ openquery_upgrd BABEL-3657 test_windows_alter_user BABEL-733 +BABEL-745 BABEL-3938 BABEL-NEXT-VALUE-FOR binary-index From 08e49f139faf63b0064b5e6e10289dd4ead22ce8 Mon Sep 17 00:00:00 2001 From: Deepakshi Mittal <78574784+deepakshi-mittal@users.noreply.github.com> Date: Wed, 15 Mar 2023 14:51:39 -0700 Subject: [PATCH 013/363] Create function cannot contain a SAVE, PRINT, WAITFOR, RAISERROR SAVE TRANSACTION WAITFOR DELAY PRINT RAISERROR Task: BABEL-1591 Signed-off-by: Deepakshi Mittal --- contrib/babelfishpg_tsql/src/tsqlIface.cpp | 26 ++++++++ test/JDBC/expected/BABEL-1591.out | 70 ++++++++++++++++++++++ test/JDBC/input/BABEL-1591.sql | 42 +++++++++++++ 3 files changed, 138 insertions(+) diff --git a/contrib/babelfishpg_tsql/src/tsqlIface.cpp b/contrib/babelfishpg_tsql/src/tsqlIface.cpp index 050cc6a5d1..92a3d5d7b5 100644 --- a/contrib/babelfishpg_tsql/src/tsqlIface.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlIface.cpp @@ -747,6 +747,20 @@ class tsqlCommonMutator : public TSqlParserBaseListener if (in_create_or_alter_function && ctx->ROLLBACK()){ throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "Invalid use of a side-effecting operator 'ROLLBACK TRANSACTION' within a function.", 0, 0); } + if (in_create_or_alter_function && ctx->SAVE()){ + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "Invalid use of a side-effecting operator 'SAVEPOINT' within a function.", 0, 0); + } + } + + void enterPrint_statement(TSqlParser::Print_statementContext *ctx) override { + if (in_create_or_alter_function && ctx->PRINT()){ + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "Invalid use of a side-effecting operator 'PRINT' within a function.", 0, 0); + } + } + void enterRaiseerror_statement(TSqlParser::Raiseerror_statementContext * ctx) override { + if (in_create_or_alter_function && ctx->RAISERROR()){ + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "Invalid use of a side-effecting operator 'RAISERROR' within a function.", 0, 0); + } } void enterExecute_statement(TSqlParser::Execute_statementContext *ctx) override { @@ -764,6 +778,18 @@ class tsqlCommonMutator : public TSqlParserBaseListener } } + void enterWaitfor_statement(TSqlParser::Waitfor_statementContext *ctx) override { + if (in_create_or_alter_function && ctx->WAITFOR()){ + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "Invalid use of a side-effecting operator 'WAITFOR' within a function.", 0, 0); + } + } + + void enterWaitfor_receive_statement(TSqlParser::Waitfor_receive_statementContext * ctx) override { + if (in_create_or_alter_function && ctx->WAITFOR()){ + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "Invalid use of a side-effecting operator 'WAITFOR' within a function.", 0, 0); + } + } + /* Column Name */ void exitSimple_column_name(TSqlParser::Simple_column_nameContext *ctx) override { diff --git a/test/JDBC/expected/BABEL-1591.out b/test/JDBC/expected/BABEL-1591.out index 4b53b59067..c522c33999 100644 --- a/test/JDBC/expected/BABEL-1591.out +++ b/test/JDBC/expected/BABEL-1591.out @@ -43,6 +43,55 @@ GO ~~ERROR (Message: Invalid use of a side-effecting operator 'EXECUTE STRING' within a function.)~~ +CREATE FUNCTION fooexectestV(@p int) RETURNS int AS BEGIN EXEC(@@trancount) RETURN 0 END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid use of a side-effecting operator 'EXECUTE STRING' within a function.)~~ + + +CREATE FUNCTION fsavetrantest(@p int) RETURNS int AS BEGIN SAVE TRAN sp1 RETURN 0 END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid use of a side-effecting operator 'SAVEPOINT' within a function.)~~ + + +CREATE FUNCTION fsavetransactiontest(@p int) RETURNS int AS BEGIN SAVE TRANSACTION sp2 RETURN 0 END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid use of a side-effecting operator 'SAVEPOINT' within a function.)~~ + + +CREATE FUNCTION fwaitfordelay(@p int) RETURNS int AS BEGIN WAITFOR DELAY '00:00:20' RETURN 0 END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'WAITFOR' is not currently supported in Babelfish)~~ + + +CREATE FUNCTION fwaitfortime(@p int) RETURNS int AS BEGIN WAITFOR TIME '00:00:20' RETURN 0 END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'WAITFOR' is not currently supported in Babelfish)~~ + + +CREATE FUNCTION fprinttest (@p int) RETURNS int AS BEGIN PRINT 'hello there' RETURN 0 END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid use of a side-effecting operator 'PRINT' within a function.)~~ + + +CREATE FUNCTION fraiserrortest (@p int) RETURNS int AS BEGIN RAISERROR(5005, 10, 1, N'ErrorMessage') RETURN 0 END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid use of a side-effecting operator 'RAISERROR' within a function.)~~ + + -- clean up DROP FUNCTION IF EXISTS foocommittest GO @@ -56,6 +105,27 @@ GO DROP FUNCTION IF EXISTS fooexectest GO +DROP FUNCTION IF EXISTS fooexectestV +GO + +DROP FUNCTION IF EXISTS fsavetrantest +GO + +DROP FUNCTION IF EXISTS fsavetransactiontest +GO + +DROP FUNCTION IF EXISTS fwaitfordelay +GO + +DROP FUNCTION IF EXISTS fwaitfortime +GO + +DROP FUNCTION IF EXISTS fprinttest +GO + +DROP FUNCTION IF EXISTS fraiserrortest +GO + diff --git a/test/JDBC/input/BABEL-1591.sql b/test/JDBC/input/BABEL-1591.sql index 1b1445f082..6d3921553b 100644 --- a/test/JDBC/input/BABEL-1591.sql +++ b/test/JDBC/input/BABEL-1591.sql @@ -22,6 +22,27 @@ GO CREATE FUNCTION fooexectest(@p int) RETURNS int AS BEGIN EXEC('select 1') RETURN 0 END GO +CREATE FUNCTION fooexectestV(@p int) RETURNS int AS BEGIN EXEC(@@trancount) RETURN 0 END +GO + +CREATE FUNCTION fsavetrantest(@p int) RETURNS int AS BEGIN SAVE TRAN sp1 RETURN 0 END +GO + +CREATE FUNCTION fsavetransactiontest(@p int) RETURNS int AS BEGIN SAVE TRANSACTION sp2 RETURN 0 END +GO + +CREATE FUNCTION fwaitfordelay(@p int) RETURNS int AS BEGIN WAITFOR DELAY '00:00:20' RETURN 0 END +GO + +CREATE FUNCTION fwaitfortime(@p int) RETURNS int AS BEGIN WAITFOR TIME '00:00:20' RETURN 0 END +GO + +CREATE FUNCTION fprinttest (@p int) RETURNS int AS BEGIN PRINT 'hello there' RETURN 0 END +GO + +CREATE FUNCTION fraiserrortest (@p int) RETURNS int AS BEGIN RAISERROR(5005, 10, 1, N'ErrorMessage') RETURN 0 END +GO + -- clean up DROP FUNCTION IF EXISTS foocommittest GO @@ -35,6 +56,27 @@ GO DROP FUNCTION IF EXISTS fooexectest GO +DROP FUNCTION IF EXISTS fooexectestV +GO + +DROP FUNCTION IF EXISTS fsavetrantest +GO + +DROP FUNCTION IF EXISTS fsavetransactiontest +GO + +DROP FUNCTION IF EXISTS fwaitfordelay +GO + +DROP FUNCTION IF EXISTS fwaitfortime +GO + +DROP FUNCTION IF EXISTS fprinttest +GO + +DROP FUNCTION IF EXISTS fraiserrortest +GO + --This needs to be uncommented and tested later when support for alter function is added, -- and corresponding test cases for transactions should be added From b6d50fa2b5789546595e49f0463c998187c929fd Mon Sep 17 00:00:00 2001 From: Aditya Verma <45755382+aadityavermaa@users.noreply.github.com> Date: Thu, 16 Mar 2023 09:03:03 +0530 Subject: [PATCH 014/363] Fix test failures in sp_tablecollations_100 and sys.sql_modules after restore (#1332) * BABEL-4016, BABEL-4017 The datatype of column 'name' in the output of sp_tablecollations_100 procedure changed from sys.sysname to text after performing dump/restore on latest->latest path. Further, cache looked failed error was observed when sys.sql_modules was called after dump/restore on the same upgrade path. Both these issues led to failures in tests, which this PR aims to resolve. Signed-off-by: Aditya Verma --------- Signed-off-by: Aditya Verma Co-authored-by: Aditya Verma --- .../composite-actions/dump-restore-util/action.yml | 3 --- contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql | 4 ++-- contrib/babelfishpg_tsql/src/pltsql_utils.c | 14 +++++++------- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/.github/composite-actions/dump-restore-util/action.yml b/.github/composite-actions/dump-restore-util/action.yml index 395a2b30f9..3ca6101734 100644 --- a/.github/composite-actions/dump-restore-util/action.yml +++ b/.github/composite-actions/dump-restore-util/action.yml @@ -104,9 +104,6 @@ runs: sed -i "/TestNotNull/d" test/JDBC/upgrade/$base_dir/schedule sed -i "/TestSQLVariant/d" test/JDBC/upgrade/$base_dir/schedule sed -i "/babel_datatype_sqlvariant/d" test/JDBC/upgrade/$base_dir/schedule - sed -i "/sp_tablecollations/d" test/JDBC/upgrade/$base_dir/schedule - sed -i "/sys-sql_modules/d" test/JDBC/upgrade/$base_dir/schedule - sed -i "/sys-system_sql_modules/d" test/JDBC/upgrade/$base_dir/schedule shell: bash - name: Run Verify Tests diff --git a/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql index fd9a2799a9..1e8b93a46e 100644 --- a/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql +++ b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql @@ -708,8 +708,8 @@ CREATE OR REPLACE VIEW sys.spt_tablecollations_view AS o.object_id AS object_id, o.schema_id AS schema_id, c.column_id AS colid, - CASE WHEN p.attoptions[1] LIKE 'bbf_original_name=%' THEN split_part(p.attoptions[1], '=', 2) - ELSE c.name COLLATE sys.database_default END AS name, + CASE WHEN p.attoptions[1] LIKE 'bbf_original_name=%' THEN CAST(split_part(p.attoptions[1], '=', 2) AS sys.SYSNAME) + ELSE c.name COLLATE sys.database_default END AS name, CAST(CollationProperty(c.collation_name,'tdscollation') AS binary(5)) AS tds_collation_28, CAST(CollationProperty(c.collation_name,'tdscollation') AS binary(5)) AS tds_collation_90, CAST(CollationProperty(c.collation_name,'tdscollation') AS binary(5)) AS tds_collation_100, diff --git a/contrib/babelfishpg_tsql/src/pltsql_utils.c b/contrib/babelfishpg_tsql/src/pltsql_utils.c index dc80e0b768..5f0ee47912 100644 --- a/contrib/babelfishpg_tsql/src/pltsql_utils.c +++ b/contrib/babelfishpg_tsql/src/pltsql_utils.c @@ -893,16 +893,16 @@ get_pltsql_function_signature(PG_FUNCTION_ARGS) const char *func_signature; proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid)); - if (!HeapTupleIsValid(proctup)) - elog(ERROR, "cache lookup failed for function %u", funcoid); - form_proctup = (Form_pg_proc) GETSTRUCT(proctup); - - func_signature = (char *) get_pltsql_function_signature_internal(NameStr(form_proctup->proname), + if (HeapTupleIsValid(proctup)){ + form_proctup = (Form_pg_proc) GETSTRUCT(proctup); + func_signature = (char *) get_pltsql_function_signature_internal(NameStr(form_proctup->proname), form_proctup->pronargs, form_proctup->proargtypes.values); - ReleaseSysCache(proctup); - PG_RETURN_TEXT_P(cstring_to_text(func_signature)); + ReleaseSysCache(proctup); + PG_RETURN_TEXT_P(cstring_to_text(func_signature)); + } + PG_RETURN_NULL(); } void From 4cd571f7eda05135c6859edbc51232f776041466 Mon Sep 17 00:00:00 2001 From: Dipesh Dhameliya Date: Thu, 16 Mar 2023 13:11:02 +0530 Subject: [PATCH 015/363] Fix sp_database test cases (#1342) Previously, we were having test cases for sp_databases which also test the database size. But database size is subject to change, it will cause the test failure. So this commit updates the test cases to not check the database size. Task: None Signed-off-by: Dipesh Dhameliya --- test/JDBC/expected/BABEL-SP_DATABASES.out | 12 ++++++------ .../expected/sys-sp_databases-dep-vu-prepare.out | 4 ++-- .../JDBC/expected/sys-sp_databases-dep-vu-verify.out | 8 ++++---- test/JDBC/expected/sys-sp_databases-vu-verify.out | 6 +++--- test/JDBC/input/BABEL-SP_DATABASES.sql | 4 ++-- .../input/views/sys-sp_databases-dep-vu-prepare.sql | 4 ++-- test/JDBC/input/views/sys-sp_databases-vu-verify.sql | 2 +- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/test/JDBC/expected/BABEL-SP_DATABASES.out b/test/JDBC/expected/BABEL-SP_DATABASES.out index 6e274e4e2f..516ec89772 100644 --- a/test/JDBC/expected/BABEL-SP_DATABASES.out +++ b/test/JDBC/expected/BABEL-SP_DATABASES.out @@ -21,19 +21,19 @@ go ~~ROW COUNT: 1~~ -select * from sys.sp_databases_view where database_name='db1'; +select database_name, remarks from sys.sp_databases_view where database_name='db1'; go ~~START~~ -varchar#!#int#!#varchar -db1#!#8#!# +varchar#!#varchar +db1#!# ~~END~~ -select * from sys.sp_databases_view where database_name='DB1'; +select database_name, remarks from sys.sp_databases_view where database_name='DB1'; go ~~START~~ -varchar#!#int#!#varchar -db1#!#8#!# +varchar#!#varchar +db1#!# ~~END~~ diff --git a/test/JDBC/expected/sys-sp_databases-dep-vu-prepare.out b/test/JDBC/expected/sys-sp_databases-dep-vu-prepare.out index 5e03dac51c..6e3741e990 100644 --- a/test/JDBC/expected/sys-sp_databases-dep-vu-prepare.out +++ b/test/JDBC/expected/sys-sp_databases-dep-vu-prepare.out @@ -10,7 +10,7 @@ go create procedure sys_sp_databases_dep_vu_prepare_p1 as - select * from sys.sp_databases_view where database_name='sys_sp_databases_dep_vu_prepare_db1' + select database_name, remarks from sys.sp_databases_view where database_name='sys_sp_databases_dep_vu_prepare_db1' go create function sys_sp_databases_dep_vu_prepare_f1() @@ -22,5 +22,5 @@ end go create view sys_sp_databases_dep_vu_prepare_v1 as - select * from sys.sp_databases_view where database_name='sys_sp_databases_dep_vu_prepare_db1' + select database_name, remarks from sys.sp_databases_view where database_name='sys_sp_databases_dep_vu_prepare_db1' go diff --git a/test/JDBC/expected/sys-sp_databases-dep-vu-verify.out b/test/JDBC/expected/sys-sp_databases-dep-vu-verify.out index 6c588f9228..7582eaa1c0 100644 --- a/test/JDBC/expected/sys-sp_databases-dep-vu-verify.out +++ b/test/JDBC/expected/sys-sp_databases-dep-vu-verify.out @@ -4,8 +4,8 @@ go exec sys_sp_databases_dep_vu_prepare_p1 go ~~START~~ -varchar#!#int#!#varchar -sys_sp_databases_dep_vu_prepare_db1#!#8#!# +varchar#!#varchar +sys_sp_databases_dep_vu_prepare_db1#!# ~~END~~ @@ -20,7 +20,7 @@ int select * from sys_sp_databases_dep_vu_prepare_v1 go ~~START~~ -varchar#!#int#!#varchar -sys_sp_databases_dep_vu_prepare_db1#!#8#!# +varchar#!#varchar +sys_sp_databases_dep_vu_prepare_db1#!# ~~END~~ diff --git a/test/JDBC/expected/sys-sp_databases-vu-verify.out b/test/JDBC/expected/sys-sp_databases-vu-verify.out index f7d1aa74d5..4a937aeea4 100644 --- a/test/JDBC/expected/sys-sp_databases-vu-verify.out +++ b/test/JDBC/expected/sys-sp_databases-vu-verify.out @@ -1,10 +1,10 @@ use sys_sp_databases_vu_prepare_db1; go -select * from sys.sp_databases_view where database_name='sys_sp_databases_vu_prepare_db1'; +select database_name, remarks from sys.sp_databases_view where database_name='sys_sp_databases_vu_prepare_db1'; go ~~START~~ -varchar#!#int#!#varchar -sys_sp_databases_vu_prepare_db1#!#8#!# +varchar#!#varchar +sys_sp_databases_vu_prepare_db1#!# ~~END~~ diff --git a/test/JDBC/input/BABEL-SP_DATABASES.sql b/test/JDBC/input/BABEL-SP_DATABASES.sql index df6fbbf5cf..f204f68784 100644 --- a/test/JDBC/input/BABEL-SP_DATABASES.sql +++ b/test/JDBC/input/BABEL-SP_DATABASES.sql @@ -13,10 +13,10 @@ go insert into t_spdatabases(a) values(10); go -select * from sys.sp_databases_view where database_name='db1'; +select database_name, remarks from sys.sp_databases_view where database_name='db1'; go -select * from sys.sp_databases_view where database_name='DB1'; +select database_name, remarks from sys.sp_databases_view where database_name='DB1'; go EXEC sp_databases; diff --git a/test/JDBC/input/views/sys-sp_databases-dep-vu-prepare.sql b/test/JDBC/input/views/sys-sp_databases-dep-vu-prepare.sql index 36bd908321..3a256c6269 100644 --- a/test/JDBC/input/views/sys-sp_databases-dep-vu-prepare.sql +++ b/test/JDBC/input/views/sys-sp_databases-dep-vu-prepare.sql @@ -8,7 +8,7 @@ insert into sys_sp_databases_dep_vu_prepare_t1(a) values(10); go create procedure sys_sp_databases_dep_vu_prepare_p1 as - select * from sys.sp_databases_view where database_name='sys_sp_databases_dep_vu_prepare_db1' + select database_name, remarks from sys.sp_databases_view where database_name='sys_sp_databases_dep_vu_prepare_db1' go create function sys_sp_databases_dep_vu_prepare_f1() @@ -20,5 +20,5 @@ end go create view sys_sp_databases_dep_vu_prepare_v1 as - select * from sys.sp_databases_view where database_name='sys_sp_databases_dep_vu_prepare_db1' + select database_name, remarks from sys.sp_databases_view where database_name='sys_sp_databases_dep_vu_prepare_db1' go diff --git a/test/JDBC/input/views/sys-sp_databases-vu-verify.sql b/test/JDBC/input/views/sys-sp_databases-vu-verify.sql index d92d538f04..7cafbf05cb 100644 --- a/test/JDBC/input/views/sys-sp_databases-vu-verify.sql +++ b/test/JDBC/input/views/sys-sp_databases-vu-verify.sql @@ -1,5 +1,5 @@ use sys_sp_databases_vu_prepare_db1; go -select * from sys.sp_databases_view where database_name='sys_sp_databases_vu_prepare_db1'; +select database_name, remarks from sys.sp_databases_view where database_name='sys_sp_databases_vu_prepare_db1'; go From a311cb0da9a80e23c6934a69a7e2337041af5c95 Mon Sep 17 00:00:00 2001 From: Rui Zhao Date: Thu, 16 Mar 2023 23:18:30 +0800 Subject: [PATCH 016/363] Implement CONTEXT_INFO() and SET CONTEXT_INFO (#1288) Description =========== CONTEXT_INFO is a session local parameter of type varbinary(128). It can be set by 'SET CONTEXT_INFO 0x123456' and can be get by 'SELECT CONTEXT_INFO()'. It can also be get with sys.sysprocesses, sys.dm_exec_requests, sys.dm_exec_sessions views. Solution ======== CONTEXT_INFO is similar to HOST_NAME/LANGUAGE, all of them are session local. The difference is that CONTEXT_INFO supports int/numeric/float parameter and dose implicit type casts. We add a procedure bbf_set_context_info(IN context_info sys.VARBINARY(128)) and rewrite 'SET CONTEXT_INFO 0x123456' to 'CALL bbf_set_context_info(convert(varbinary(128), 0x123456))'. Limitation ========== Some type casts are not supported in Babelfish, such as type cast from numeric to varbinary. Some type casts have their own rules, e.g. integer constant greater than 2,147,483,647 is converted to decimal instead of bigint. They are not the issue of CONTEXT_INFO, so are not solved in this patch. --- contrib/babelfishpg_tds/src/backend/tds/tds.c | 84 +++- .../babelfishpg_tds/src/backend/tds/tds_srv.c | 2 + contrib/babelfishpg_tds/src/include/tds_int.h | 3 + contrib/babelfishpg_tsql/runtime/functions.c | 146 ++++++- .../babelfishpg_tsql/sql/sys_functions.sql | 6 +- .../babelfishpg_tsql/sql/sys_procedures.sql | 3 + contrib/babelfishpg_tsql/sql/sys_views.sql | 4 +- .../babelfishpg_tsql--3.1.0--3.2.0.sql | 319 +++++++++++++++ contrib/babelfishpg_tsql/src/pltsql.h | 2 + contrib/babelfishpg_tsql/src/pltsql_instr.h | 1 - contrib/babelfishpg_tsql/src/tsqlIface.cpp | 28 +- .../src/tsqlUnsupportedFeatureHandler.cpp | 2 - test/JDBC/expected/BABEL-UNSUPPORTED.out | 9 - .../babel_context_info-vu-cleanup.out | 8 + .../babel_context_info-vu-prepare.out | 18 + .../expected/babel_context_info-vu-verify.out | 368 ++++++++++++++++++ test/JDBC/input/BABEL-UNSUPPORTED.sql | 5 - .../input/babel_context_info-vu-cleanup.sql | 8 + .../input/babel_context_info-vu-prepare.sql | 18 + .../input/babel_context_info-vu-verify.sql | 178 +++++++++ test/JDBC/upgrade/14_7/schedule | 1 + test/JDBC/upgrade/latest/schedule | 1 + 22 files changed, 1187 insertions(+), 27 deletions(-) create mode 100644 test/JDBC/expected/babel_context_info-vu-cleanup.out create mode 100644 test/JDBC/expected/babel_context_info-vu-prepare.out create mode 100644 test/JDBC/expected/babel_context_info-vu-verify.out create mode 100644 test/JDBC/input/babel_context_info-vu-cleanup.sql create mode 100644 test/JDBC/input/babel_context_info-vu-prepare.sql create mode 100644 test/JDBC/input/babel_context_info-vu-verify.sql diff --git a/contrib/babelfishpg_tds/src/backend/tds/tds.c b/contrib/babelfishpg_tds/src/backend/tds/tds.c index a5e0343bd6..9caca362a0 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tds.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tds.c @@ -60,6 +60,7 @@ #define LANGDATALEN 128 #define HOSTDATALEN 128 #define XACT_SNAPSHOT 5 +#define CONTEXTINFOLEN 128 PG_MODULE_MAGIC; @@ -106,6 +107,7 @@ typedef struct TdsStatus char *st_library_name; /* Library */ char *st_host_name; /* Hostname */ char *st_language; /* Language */ + char *st_context_info; /* CONTEXT_INFO */ uint32_t client_pid; @@ -148,12 +150,14 @@ uint32_t MyTdsClientVersion = 0; uint32_t MyTdsClientPid = -1; char *MyTdsLibraryName = NULL; char *MyTdsHostName = NULL; +char *MyTdsContextInfo = NULL; uint32_t MyTdsProtocolVersion = TDS_DEFAULT_VERSION; uint32_t MyTdsPacketSize = 0; int MyTdsEncryptOption = TDS_ENCRYPT_OFF; static char *TdsLibraryNameBuffer = NULL; static char *TdsHostNameBuffer = NULL; static char *TdsLanguageBuffer = NULL; +static char *TdsContextInfoBuffer = NULL; static int localNumBackends = 0; static bool isLocalStatusTableValid = false; @@ -265,6 +269,12 @@ TdsLanguageBufferSize() return mul_size(LANGDATALEN, NumBackendStatSlots); } +static Size +TdsContextInfoBufferSize() +{ + return mul_size(CONTEXTINFOLEN, NumBackendStatSlots); +} + static Size tds_memsize() { @@ -274,6 +284,7 @@ tds_memsize() size = add_size(size, TdsLibraryNameBufferSize()); size = add_size(size, TdsHostNameBufferSize()); size = add_size(size, TdsLanguageBufferSize()); + size = add_size(size, TdsContextInfoBufferSize()); return size; } @@ -376,6 +387,25 @@ tds_status_shmem_startup(void) } } + /* Create or attach to the shared TDS context info buffer */ + TdsContextInfoBuffer = (char *) + ShmemInitStruct("TDS context info buffer", TdsContextInfoBufferSize(), &found); + + if (!found) + { + int i; + + MemSet(TdsContextInfoBuffer, 0, TdsContextInfoBufferSize()); + + /* Initialize st_context_info pointers. */ + buffer = TdsContextInfoBuffer; + for (i = 0; i < MaxBackends; i++) + { + TdsStatusArray[i].st_context_info = buffer; + buffer += CONTEXTINFOLEN; + } + } + LWLockRelease(AddinShmemInitLock); /* If we're in the postmaster (or a standalone backend...), set up a shmem @@ -510,6 +540,8 @@ tdsstat_bestart(void) ltdsentry.st_host_name[len] = '\0'; } + memset(ltdsentry.st_context_info, 0, CONTEXTINFOLEN); + ltdsentry.encrypt_option = MyTdsEncryptOption; ltdsentry.database_id = 0; @@ -613,6 +645,9 @@ tdsstat_read_current_status(void) if (tdsentry->st_language) localentry->tdsStatus.st_language = tdsentry->st_language; + if (tdsentry->st_context_info) + localentry->tdsStatus.st_context_info = tdsentry->st_context_info; + if (tdsentry->quoted_identifier) localentry->tdsStatus.quoted_identifier = tdsentry->quoted_identifier; @@ -797,10 +832,21 @@ tds_stat_get_activity(Datum *values, bool *nulls, int len, int pid, int curr_bac values[23] = Int16GetDatum(tdsentry->database_id); /* Host name must be valid */ - if(tdsentry->st_host_name) - values[24] = CStringGetTextDatum(tdsentry->st_host_name); - else - nulls[24] = true; + if (len > 24) + { + if(tdsentry->st_host_name) + values[24] = CStringGetTextDatum(tdsentry->st_host_name); + else + nulls[24] = true; + } + + if (len > 25) + { + if(tdsentry->st_context_info) + values[25] = PointerGetDatum(cstring_to_text_with_len(tdsentry->st_context_info, CONTEXTINFOLEN)); + else + nulls[25] = true; + } return true; } @@ -921,3 +967,33 @@ get_tds_host_name(void) { return MyTdsHostName; } + +Datum +get_tds_context_info(void) +{ + if (MyTdsContextInfo) + PG_RETURN_TEXT_P(cstring_to_text_with_len(MyTdsContextInfo, CONTEXTINFOLEN)); + else + PG_RETURN_VOID(); +} + +void +set_tds_context_info(bytea* context_info) +{ + int32 len; + char* data; + + volatile TdsStatus *vtdsentry = MyTdsStatusEntry; + + PGSTAT_BEGIN_WRITE_ACTIVITY(vtdsentry); + + len = VARSIZE(context_info) - VARHDRSZ; + data = VARDATA(context_info); + memset(vtdsentry->st_context_info, 0, CONTEXTINFOLEN); + memcpy(vtdsentry->st_context_info, data, len); + + PGSTAT_END_WRITE_ACTIVITY(vtdsentry); + + if (!MyTdsContextInfo) + MyTdsContextInfo = vtdsentry->st_context_info; +} diff --git a/contrib/babelfishpg_tds/src/backend/tds/tds_srv.c b/contrib/babelfishpg_tds/src/backend/tds/tds_srv.c index 34e19f8c6c..25da2ae2ea 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tds_srv.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tds_srv.c @@ -196,6 +196,8 @@ pe_tds_init(void) pltsql_plugin_handler_ptr->get_stat_values = &tds_stat_get_activity; pltsql_plugin_handler_ptr->invalidate_stat_view = &invalidate_stat_table; pltsql_plugin_handler_ptr->get_host_name = &get_tds_host_name; + pltsql_plugin_handler_ptr->get_context_info = &get_tds_context_info; + pltsql_plugin_handler_ptr->set_context_info = &set_tds_context_info; pltsql_plugin_handler_ptr->get_datum_from_byte_ptr = &TdsBytePtrToDatum; pltsql_plugin_handler_ptr->get_datum_from_date_time_struct = &TdsDateTimeTypeToDatum; diff --git a/contrib/babelfishpg_tds/src/include/tds_int.h b/contrib/babelfishpg_tds/src/include/tds_int.h index 56a29aa61f..2187d443ef 100644 --- a/contrib/babelfishpg_tds/src/include/tds_int.h +++ b/contrib/babelfishpg_tds/src/include/tds_int.h @@ -204,6 +204,7 @@ typedef TdsParamNameData *TdsParamName; extern PGDLLIMPORT uint32_t MyTdsClientVersion; extern PGDLLIMPORT char* MyTdsLibraryName; extern PGDLLIMPORT char* MyTdsHostName; +extern PGDLLIMPORT char* MyTdsContextInfo; extern PGDLLIMPORT uint32_t MyTdsClientPid; extern PGDLLIMPORT uint32_t MyTdsProtocolVersion; extern PGDLLIMPORT uint32_t MyTdsPacketSize; @@ -330,6 +331,8 @@ extern void TdsSetDatabaseStatVariable(int16 db_id); extern bool tds_stat_get_activity(Datum *values, bool *nulls, int len, int pid, int curr_backend); extern void invalidate_stat_table(void); extern char* get_tds_host_name(void); +extern Datum get_tds_context_info(void); +extern void set_tds_context_info(bytea* context_info); /* Functions in backend/tds/tdspostgres.c */ extern void TDSPostgresMain(int argc, char *argv[], diff --git a/contrib/babelfishpg_tsql/runtime/functions.c b/contrib/babelfishpg_tsql/runtime/functions.c index 9adcfbbaef..d6640c8a70 100644 --- a/contrib/babelfishpg_tsql/runtime/functions.c +++ b/contrib/babelfishpg_tsql/runtime/functions.c @@ -49,7 +49,7 @@ #include "catalog/pg_trigger.h" #include "catalog/pg_constraint.h" -#define TSQL_STAT_GET_ACTIVITY_COLS 25 +#define TSQL_STAT_GET_ACTIVITY_COLS 26 #define SP_DATATYPE_INFO_HELPER_COLS 23 PG_FUNCTION_INFO_V1(trancount); @@ -75,6 +75,7 @@ PG_FUNCTION_INFO_V1(default_domain); PG_FUNCTION_INFO_V1(tsql_exp); PG_FUNCTION_INFO_V1(host_os); PG_FUNCTION_INFO_V1(tsql_stat_get_activity_deprecated_in_2_2_0); +PG_FUNCTION_INFO_V1(tsql_stat_get_activity_deprecated_in_3_2_0); PG_FUNCTION_INFO_V1(tsql_stat_get_activity); PG_FUNCTION_INFO_V1(get_current_full_xact_id); PG_FUNCTION_INFO_V1(checksum); @@ -84,6 +85,8 @@ PG_FUNCTION_INFO_V1(object_name); PG_FUNCTION_INFO_V1(sp_datatype_info_helper); PG_FUNCTION_INFO_V1(language); PG_FUNCTION_INFO_V1(host_name); +PG_FUNCTION_INFO_V1(context_info); +PG_FUNCTION_INFO_V1(bbf_set_context_info); PG_FUNCTION_INFO_V1(procid); PG_FUNCTION_INFO_V1(babelfish_integrity_checker); PG_FUNCTION_INFO_V1(bigint_degrees); @@ -730,6 +733,120 @@ tsql_stat_get_activity_deprecated_in_2_2_0(PG_FUNCTION_ARGS) errmsg("The user does not have permission to perform this action"))); } + /* check to see if caller supports us returning a tuplestore */ + if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("set-valued function called in context that cannot accept a set"))); + + if (!(rsinfo->allowedModes & SFRM_Materialize)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("materialize mode required, but it is not allowed in this context"))); + + /* Build tupdesc for result tuples. */ + tupdesc = CreateTemplateTupleDesc(TSQL_STAT_GET_ACTIVITY_COLS - 2); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "procid", INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "client_version", INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "library_name", VARCHAROID, 32, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 4, "language", VARCHAROID, 128, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 5, "quoted_identifier", BOOLOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 6, "arithabort", BOOLOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 7, "ansi_null_dflt_on", BOOLOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 8, "ansi_defaults", BOOLOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 9, "ansi_warnings", BOOLOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 10, "ansi_padding", BOOLOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 11, "ansi_nulls", BOOLOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 12, "concat_null_yields_null", BOOLOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 13, "textsize", INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 14, "datefirst", INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 15, "lock_timeout", INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 16, "transaction_isolation", INT2OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 17, "client_pid", INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 18, "row_count", INT8OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 19, "prev_error", INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 20, "trancount", INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 21, "protocol_version", INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 22, "packet_size", INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 23, "encrypt_option", VARCHAROID, 40, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 24, "database_id", INT2OID, -1, 0); + tupdesc = BlessTupleDesc(tupdesc); + + per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; + oldcontext = MemoryContextSwitchTo(per_query_ctx); + + tupstore = tuplestore_begin_heap(true, false, work_mem); + rsinfo->returnMode = SFRM_Materialize; + rsinfo->setResult = tupstore; + rsinfo->setDesc = tupdesc; + + MemoryContextSwitchTo(oldcontext); + + /* 1-based index */ + for (curr_backend = 1; curr_backend <= num_backends; curr_backend++) + { + /* for each row */ + Datum values[TSQL_STAT_GET_ACTIVITY_COLS - 2]; + bool nulls[TSQL_STAT_GET_ACTIVITY_COLS - 2]; + + if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->get_stat_values && + (*pltsql_protocol_plugin_ptr)->get_stat_values(values, nulls, TSQL_STAT_GET_ACTIVITY_COLS - 2, pid, curr_backend)) + tuplestore_putvalues(tupstore, tupdesc, values, nulls); + else continue; + + /* If only a single backend was requested, and we found it, break. */ + if (pid != -1) + break; + } + + /* clean up and return the tuplestore */ + tuplestore_donestoring(tupstore); + + if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->invalidate_stat_view) + (*pltsql_protocol_plugin_ptr)->invalidate_stat_view(); + + return (Datum) 0; +} + +Datum +tsql_stat_get_activity_deprecated_in_3_2_0(PG_FUNCTION_ARGS) +{ + Oid sysadmin_oid = get_role_oid("sysadmin", false); + int num_backends = pgstat_fetch_stat_numbackends(); + int curr_backend; + char* view_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); + int pid = -1; + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + TupleDesc tupdesc; + Tuplestorestate *tupstore; + MemoryContext per_query_ctx; + MemoryContext oldcontext; + + /* For sys.dm_exec_sessions view: + * - If user is sysadmin, we show info of all the sessions + * - If user is not sysadmin, we only show info of current session + * For sys.dm_exec_connections view: + * - If user is sysadmin, we show info of all the connections + * - If user is not sysadmin, we throw an error since user does not + * have the required permissions to query this view + */ + if (strcmp(view_name, "sessions") == 0) + { + if (has_privs_of_role(GetSessionUserId(), sysadmin_oid)) + pid = -1; + else + pid = MyProcPid; + } + else if (strcmp(view_name, "connections") == 0) + { + if (has_privs_of_role(GetSessionUserId(), sysadmin_oid)) + pid = -1; + else + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("The user does not have permission to perform this action"))); + } + /* check to see if caller supports us returning a tuplestore */ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) ereport(ERROR, @@ -767,6 +884,7 @@ tsql_stat_get_activity_deprecated_in_2_2_0(PG_FUNCTION_ARGS) TupleDescInitEntry(tupdesc, (AttrNumber) 22, "packet_size", INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 23, "encrypt_option", VARCHAROID, 40, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 24, "database_id", INT2OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 25, "host_name", VARCHAROID, 128, 0); tupdesc = BlessTupleDesc(tupdesc); per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; @@ -787,7 +905,7 @@ tsql_stat_get_activity_deprecated_in_2_2_0(PG_FUNCTION_ARGS) bool nulls[TSQL_STAT_GET_ACTIVITY_COLS - 1]; if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->get_stat_values && - (*pltsql_protocol_plugin_ptr)->get_stat_values(values, nulls, TSQL_STAT_GET_ACTIVITY_COLS, pid, curr_backend)) + (*pltsql_protocol_plugin_ptr)->get_stat_values(values, nulls, TSQL_STAT_GET_ACTIVITY_COLS - 1, pid, curr_backend)) tuplestore_putvalues(tupstore, tupdesc, values, nulls); else continue; @@ -882,6 +1000,7 @@ tsql_stat_get_activity(PG_FUNCTION_ARGS) TupleDescInitEntry(tupdesc, (AttrNumber) 23, "encrypt_option", VARCHAROID, 40, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 24, "database_id", INT2OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 25, "host_name", VARCHAROID, 128, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 26, "context_info", BYTEAOID, 128, 0); tupdesc = BlessTupleDesc(tupdesc); per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; @@ -1649,6 +1768,29 @@ host_name(PG_FUNCTION_ARGS) PG_RETURN_NULL(); } +Datum +context_info(PG_FUNCTION_ARGS) +{ + Datum context_info; + + if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->get_context_info) + context_info = (*pltsql_protocol_plugin_ptr)->get_context_info(); + + if (DatumGetPointer(context_info)) + PG_RETURN_DATUM(context_info); + else + PG_RETURN_NULL(); +} + +Datum +bbf_set_context_info(PG_FUNCTION_ARGS) +{ + if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->set_context_info) + (*pltsql_protocol_plugin_ptr)->set_context_info(PG_GETARG_BYTEA_P(0)); + + PG_RETURN_VOID(); +} + /* * Execute various integrity checks. * Returns true if all the checks pass otherwise diff --git a/contrib/babelfishpg_tsql/sql/sys_functions.sql b/contrib/babelfishpg_tsql/sql/sys_functions.sql index baea629522..e8ff54d0ed 100644 --- a/contrib/babelfishpg_tsql/sql/sys_functions.sql +++ b/contrib/babelfishpg_tsql/sql/sys_functions.sql @@ -2812,7 +2812,8 @@ CREATE OR REPLACE FUNCTION sys.tsql_stat_get_activity( OUT packet_size int, OUT encrypyt_option VARCHAR(40), OUT database_id int2, - OUT host_name varchar(128)) + OUT host_name varchar(128), + OUT context_info bytea) RETURNS SETOF RECORD AS 'babelfishpg_tsql', 'tsql_stat_get_activity' LANGUAGE C VOLATILE STRICT; @@ -3316,6 +3317,9 @@ RETURNS sys.NVARCHAR(128) AS 'babelfishpg_tsql' LANGUAGE C STABLE; CREATE OR REPLACE FUNCTION sys.host_name() RETURNS sys.NVARCHAR(128) AS 'babelfishpg_tsql' LANGUAGE C IMMUTABLE PARALLEL SAFE; +CREATE OR REPLACE FUNCTION sys.context_info() +RETURNS sys.VARBINARY(128) AS 'babelfishpg_tsql' LANGUAGE C STABLE; + CREATE OR REPLACE FUNCTION sys.degrees(IN arg1 BIGINT) RETURNS bigint AS 'babelfishpg_tsql','bigint_degrees' LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE; GRANT EXECUTE ON FUNCTION sys.degrees(BIGINT) TO PUBLIC; diff --git a/contrib/babelfishpg_tsql/sql/sys_procedures.sql b/contrib/babelfishpg_tsql/sql/sys_procedures.sql index 8bfe552131..bef881fc08 100644 --- a/contrib/babelfishpg_tsql/sql/sys_procedures.sql +++ b/contrib/babelfishpg_tsql/sql/sys_procedures.sql @@ -257,3 +257,6 @@ TO PUBLIC; CREATE OR REPLACE PROCEDURE sys.sp_babelfish_volatility(IN "@function_name" sys.varchar DEFAULT NULL, IN "@volatility" sys.varchar DEFAULT NULL) AS 'babelfishpg_tsql', 'sp_babelfish_volatility' LANGUAGE C; GRANT EXECUTE on PROCEDURE sys.sp_babelfish_volatility(IN sys.varchar, IN sys.varchar) TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.bbf_set_context_info(IN context_info sys.VARBINARY(128)) +AS 'babelfishpg_tsql' LANGUAGE C; diff --git a/contrib/babelfishpg_tsql/sql/sys_views.sql b/contrib/babelfishpg_tsql/sql/sys_views.sql index f664b33ed6..6b04525557 100644 --- a/contrib/babelfishpg_tsql/sql/sys_views.sql +++ b/contrib/babelfishpg_tsql/sql/sys_views.sql @@ -1029,7 +1029,7 @@ select , null::varchar(12) as net_address , null::varchar(12) as net_library , a.usename as loginname - , null::bytea as context_info + , t.context_info::bytea as context_info , null::bytea as sql_handle , 0 as stmt_start , 0 as stmt_end @@ -2096,7 +2096,7 @@ create or replace view sys.dm_exec_sessions , (select sys.default_domain())::sys.nvarchar(128) as nt_domain , null::sys.nvarchar(128) as nt_user_name , a.state::sys.nvarchar(30) as status - , null::sys.nvarchar(128) as context_info + , d.context_info::sys.varbinary(128) as context_info , null::integer as cpu_time , null::integer as memory_usage , null::integer as total_scheduled_time diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql index 1b398e26bf..4c161516b8 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql @@ -105,6 +105,325 @@ CREATE AGGREGATE sys.VARP(float8) ( INITCOND = '{0,0,0}' ); +ALTER FUNCTION sys.tsql_stat_get_activity(text) RENAME TO tsql_stat_get_activity_deprecated_in_3_2_0; +CREATE OR REPLACE FUNCTION sys.tsql_stat_get_activity_deprecated_in_3_2_0( + IN view_name text, + OUT procid int, + OUT client_version int, + OUT library_name VARCHAR(32), + OUT language VARCHAR(128), + OUT quoted_identifier bool, + OUT arithabort bool, + OUT ansi_null_dflt_on bool, + OUT ansi_defaults bool, + OUT ansi_warnings bool, + OUT ansi_padding bool, + OUT ansi_nulls bool, + OUT concat_null_yields_null bool, + OUT textsize int, + OUT datefirst int, + OUT lock_timeout int, + OUT transaction_isolation int2, + OUT client_pid int, + OUT row_count bigint, + OUT error int, + OUT trancount int, + OUT protocol_version int, + OUT packet_size int, + OUT encrypyt_option VARCHAR(40), + OUT database_id int2, + OUT host_name varchar(128)) +RETURNS SETOF RECORD +AS 'babelfishpg_tsql', 'tsql_stat_get_activity_deprecated_in_3_2_0' +LANGUAGE C VOLATILE STRICT; +CREATE OR REPLACE FUNCTION sys.tsql_stat_get_activity( + IN view_name text, + OUT procid int, + OUT client_version int, + OUT library_name VARCHAR(32), + OUT language VARCHAR(128), + OUT quoted_identifier bool, + OUT arithabort bool, + OUT ansi_null_dflt_on bool, + OUT ansi_defaults bool, + OUT ansi_warnings bool, + OUT ansi_padding bool, + OUT ansi_nulls bool, + OUT concat_null_yields_null bool, + OUT textsize int, + OUT datefirst int, + OUT lock_timeout int, + OUT transaction_isolation int2, + OUT client_pid int, + OUT row_count bigint, + OUT error int, + OUT trancount int, + OUT protocol_version int, + OUT packet_size int, + OUT encrypyt_option VARCHAR(40), + OUT database_id int2, + OUT host_name varchar(128), + OUT context_info bytea) +RETURNS SETOF RECORD +AS 'babelfishpg_tsql', 'tsql_stat_get_activity' +LANGUAGE C VOLATILE STRICT; + +ALTER VIEW sys.sysprocesses RENAME TO sysprocesses_deprecated_in_3_2_0; +create or replace view sys.sysprocesses_deprecated_in_3_2_0 as +select + a.pid as spid + , null::integer as kpid + , coalesce(blocking_activity.pid, 0) as blocked + , null::bytea as waittype + , 0 as waittime + , a.wait_event_type as lastwaittype + , null::text as waitresource + , coalesce(t.database_id, 0)::oid as dbid + , a.usesysid as uid + , 0 as cpu + , 0 as physical_io + , 0 as memusage + , a.backend_start as login_time + , a.query_start as last_batch + , 0 as ecid + , 0 as open_tran + , a.state as status + , null::bytea as sid + , CAST(t.host_name AS sys.nchar(128)) as hostname + , a.application_name as program_name + , null::varchar(10) as hostprocess + , a.query as cmd + , null::varchar(128) as nt_domain + , null::varchar(128) as nt_username + , null::varchar(12) as net_address + , null::varchar(12) as net_library + , a.usename as loginname + , null::bytea as context_info + , null::bytea as sql_handle + , 0 as stmt_start + , 0 as stmt_end + , 0 as request_id +from pg_stat_activity a +left join sys.tsql_stat_get_activity_deprecated_in_3_2_0('sessions') as t on a.pid = t.procid +left join pg_catalog.pg_locks as blocked_locks on a.pid = blocked_locks.pid +left join pg_catalog.pg_locks blocking_locks + ON blocking_locks.locktype = blocked_locks.locktype + AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE + AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation + AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page + AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple + AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid + AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid + AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid + AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid + AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid + AND blocking_locks.pid != blocked_locks.pid + left join pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid + where a.datname = current_database(); /* current physical database will always be babelfish database */ +GRANT SELECT ON sys.sysprocesses_deprecated_in_3_2_0 TO PUBLIC; +create or replace view sys.sysprocesses as +select + a.pid as spid + , null::integer as kpid + , coalesce(blocking_activity.pid, 0) as blocked + , null::bytea as waittype + , 0 as waittime + , a.wait_event_type as lastwaittype + , null::text as waitresource + , coalesce(t.database_id, 0)::oid as dbid + , a.usesysid as uid + , 0 as cpu + , 0 as physical_io + , 0 as memusage + , a.backend_start as login_time + , a.query_start as last_batch + , 0 as ecid + , 0 as open_tran + , a.state as status + , null::bytea as sid + , CAST(t.host_name AS sys.nchar(128)) as hostname + , a.application_name as program_name + , null::varchar(10) as hostprocess + , a.query as cmd + , null::varchar(128) as nt_domain + , null::varchar(128) as nt_username + , null::varchar(12) as net_address + , null::varchar(12) as net_library + , a.usename as loginname + , t.context_info::bytea as context_info + , null::bytea as sql_handle + , 0 as stmt_start + , 0 as stmt_end + , 0 as request_id +from pg_stat_activity a +left join sys.tsql_stat_get_activity('sessions') as t on a.pid = t.procid +left join pg_catalog.pg_locks as blocked_locks on a.pid = blocked_locks.pid +left join pg_catalog.pg_locks blocking_locks + ON blocking_locks.locktype = blocked_locks.locktype + AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE + AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation + AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page + AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple + AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid + AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid + AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid + AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid + AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid + AND blocking_locks.pid != blocked_locks.pid + left join pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid + where a.datname = current_database(); /* current physical database will always be babelfish database */ +GRANT SELECT ON sys.sysprocesses TO PUBLIC; + +ALTER VIEW sys.dm_exec_sessions RENAME TO dm_exec_sessions_deprecated_in_3_2_0; +create or replace view sys.dm_exec_sessions_deprecated_in_3_2_0 + as + select a.pid as session_id + , a.backend_start::sys.datetime as login_time + , d.host_name::sys.nvarchar(128) as host_name + , a.application_name::sys.nvarchar(128) as program_name + , d.client_pid as host_process_id + , d.client_version as client_version + , d.library_name::sys.nvarchar(32) as client_interface_name + , null::sys.varbinary(85) as security_id + , a.usename::sys.nvarchar(128) as login_name + , (select sys.default_domain())::sys.nvarchar(128) as nt_domain + , null::sys.nvarchar(128) as nt_user_name + , a.state::sys.nvarchar(30) as status + , null::sys.nvarchar(128) as context_info + , null::integer as cpu_time + , null::integer as memory_usage + , null::integer as total_scheduled_time + , null::integer as total_elapsed_time + , a.client_port as endpoint_id + , a.query_start::sys.datetime as last_request_start_time + , a.state_change::sys.datetime as last_request_end_time + , null::bigint as "reads" + , null::bigint as "writes" + , null::bigint as logical_reads + , case when a.client_port > 0 then 1::sys.bit else 0::sys.bit end as is_user_process + , d.textsize as text_size + , d.language::sys.nvarchar(128) as language + , 'ymd'::sys.nvarchar(3) as date_format-- Bld 173 lacks support for SET DATEFORMAT and always expects ymd + , d.datefirst::smallint as date_first -- Bld 173 lacks support for SET DATEFIRST and always returns 7 + , CAST(CAST(d.quoted_identifier as integer) as sys.bit) as quoted_identifier + , CAST(CAST(d.arithabort as integer) as sys.bit) as arithabort + , CAST(CAST(d.ansi_null_dflt_on as integer) as sys.bit) as ansi_null_dflt_on + , CAST(CAST(d.ansi_defaults as integer) as sys.bit) as ansi_defaults + , CAST(CAST(d.ansi_warnings as integer) as sys.bit) as ansi_warnings + , CAST(CAST(d.ansi_padding as integer) as sys.bit) as ansi_padding + , CAST(CAST(d.ansi_nulls as integer) as sys.bit) as ansi_nulls + , CAST(CAST(d.concat_null_yields_null as integer) as sys.bit) as concat_null_yields_null + , d.transaction_isolation::smallint as transaction_isolation_level + , d.lock_timeout as lock_timeout + , 0 as deadlock_priority + , d.row_count as row_count + , d.error as prev_error + , null::sys.varbinary(85) as original_security_id + , a.usename::sys.nvarchar(128) as original_login_name + , null::sys.datetime as last_successful_logon + , null::sys.datetime as last_unsuccessful_logon + , null::bigint as unsuccessful_logons + , null::int as group_id + , d.database_id::smallint as database_id + , 0 as authenticating_database_id + , d.trancount as open_transaction_count + from pg_catalog.pg_stat_activity AS a + RIGHT JOIN sys.tsql_stat_get_activity_deprecated_in_3_2_0('sessions') AS d ON (a.pid = d.procid); +GRANT SELECT ON sys.dm_exec_sessions_deprecated_in_3_2_0 TO PUBLIC; +create or replace view sys.dm_exec_sessions + as + select a.pid as session_id + , a.backend_start::sys.datetime as login_time + , d.host_name::sys.nvarchar(128) as host_name + , a.application_name::sys.nvarchar(128) as program_name + , d.client_pid as host_process_id + , d.client_version as client_version + , d.library_name::sys.nvarchar(32) as client_interface_name + , null::sys.varbinary(85) as security_id + , a.usename::sys.nvarchar(128) as login_name + , (select sys.default_domain())::sys.nvarchar(128) as nt_domain + , null::sys.nvarchar(128) as nt_user_name + , a.state::sys.nvarchar(30) as status + , d.context_info::sys.varbinary(128) as context_info + , null::integer as cpu_time + , null::integer as memory_usage + , null::integer as total_scheduled_time + , null::integer as total_elapsed_time + , a.client_port as endpoint_id + , a.query_start::sys.datetime as last_request_start_time + , a.state_change::sys.datetime as last_request_end_time + , null::bigint as "reads" + , null::bigint as "writes" + , null::bigint as logical_reads + , case when a.client_port > 0 then 1::sys.bit else 0::sys.bit end as is_user_process + , d.textsize as text_size + , d.language::sys.nvarchar(128) as language + , 'ymd'::sys.nvarchar(3) as date_format-- Bld 173 lacks support for SET DATEFORMAT and always expects ymd + , d.datefirst::smallint as date_first -- Bld 173 lacks support for SET DATEFIRST and always returns 7 + , CAST(CAST(d.quoted_identifier as integer) as sys.bit) as quoted_identifier + , CAST(CAST(d.arithabort as integer) as sys.bit) as arithabort + , CAST(CAST(d.ansi_null_dflt_on as integer) as sys.bit) as ansi_null_dflt_on + , CAST(CAST(d.ansi_defaults as integer) as sys.bit) as ansi_defaults + , CAST(CAST(d.ansi_warnings as integer) as sys.bit) as ansi_warnings + , CAST(CAST(d.ansi_padding as integer) as sys.bit) as ansi_padding + , CAST(CAST(d.ansi_nulls as integer) as sys.bit) as ansi_nulls + , CAST(CAST(d.concat_null_yields_null as integer) as sys.bit) as concat_null_yields_null + , d.transaction_isolation::smallint as transaction_isolation_level + , d.lock_timeout as lock_timeout + , 0 as deadlock_priority + , d.row_count as row_count + , d.error as prev_error + , null::sys.varbinary(85) as original_security_id + , a.usename::sys.nvarchar(128) as original_login_name + , null::sys.datetime as last_successful_logon + , null::sys.datetime as last_unsuccessful_logon + , null::bigint as unsuccessful_logons + , null::int as group_id + , d.database_id::smallint as database_id + , 0 as authenticating_database_id + , d.trancount as open_transaction_count + from pg_catalog.pg_stat_activity AS a + RIGHT JOIN sys.tsql_stat_get_activity('sessions') AS d ON (a.pid = d.procid); +GRANT SELECT ON sys.dm_exec_sessions TO PUBLIC; + +create or replace view sys.dm_exec_connections + as + select a.pid as session_id + , a.pid as most_recent_session_id + , a.backend_start::sys.datetime as connect_time + , 'TCP'::sys.nvarchar(40) as net_transport + , 'TSQL'::sys.nvarchar(40) as protocol_type + , d.protocol_version as protocol_version + , 4 as endpoint_id + , d.encrypyt_option::sys.nvarchar(40) as encrypt_option + , null::sys.nvarchar(40) as auth_scheme + , null::smallint as node_affinity + , null::int as num_reads + , null::int as num_writes + , null::sys.datetime as last_read + , null::sys.datetime as last_write + , d.packet_size as net_packet_size + , a.client_addr::varchar(48) as client_net_address + , a.client_port as client_tcp_port + , null::varchar(48) as local_net_address + , null::int as local_tcp_port + , null::sys.uniqueidentifier as connection_id + , null::sys.uniqueidentifier as parent_connection_id + , a.pid::sys.varbinary(64) as most_recent_sql_handle + from pg_catalog.pg_stat_activity AS a + RIGHT JOIN sys.tsql_stat_get_activity('connections') AS d ON (a.pid = d.procid); +GRANT SELECT ON sys.dm_exec_connections TO PUBLIC; + +CALL sys.babelfish_drop_deprecated_object('view', 'sys', 'sysprocesses_deprecated_in_3_2_0'); +CALL sys.babelfish_drop_deprecated_object('view', 'sys', 'dm_exec_sessions_deprecated_in_3_2_0'); +CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'tsql_stat_get_activity_deprecated_in_3_2_0'); + +CREATE OR REPLACE FUNCTION sys.context_info() +RETURNS sys.VARBINARY(128) AS 'babelfishpg_tsql' LANGUAGE C STABLE; + +CREATE OR REPLACE PROCEDURE sys.bbf_set_context_info(IN context_info sys.VARBINARY(128)) +AS 'babelfishpg_tsql' LANGUAGE C; + ALTER FUNCTION sys.json_modify RENAME TO json_modify_deprecated_in_3_2_0; CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'json_modify_deprecated_in_3_2_0'); diff --git a/contrib/babelfishpg_tsql/src/pltsql.h b/contrib/babelfishpg_tsql/src/pltsql.h index 15a81909c7..3384361979 100644 --- a/contrib/babelfishpg_tsql/src/pltsql.h +++ b/contrib/babelfishpg_tsql/src/pltsql.h @@ -1556,6 +1556,8 @@ typedef struct PLtsql_protocol_plugin char* (*get_host_name) (void); Datum (*get_datum_from_byte_ptr) (StringInfo buf, int datatype, int scale); Datum (*get_datum_from_date_time_struct) (uint64 time, int32 date, int datatype, int optional_attr); + Datum (*get_context_info) (void); + void (*set_context_info) (bytea* context_info); /* Function pointers set by PL/tsql itself */ Datum (*sql_batch_callback) (PG_FUNCTION_ARGS); diff --git a/contrib/babelfishpg_tsql/src/pltsql_instr.h b/contrib/babelfishpg_tsql/src/pltsql_instr.h index d7e20d921d..9bd99421dc 100644 --- a/contrib/babelfishpg_tsql/src/pltsql_instr.h +++ b/contrib/babelfishpg_tsql/src/pltsql_instr.h @@ -247,7 +247,6 @@ typedef enum PgTsqlInstrMetricType { INSTR_UNSUPPORTED_TSQL_OPTION_STATISTICS, INSTR_UNSUPPORTED_TSQL_OPTION_DATEFORMAT, INSTR_UNSUPPORTED_TSQL_OPTION_DEADLOCK_PRIORITY, - INSTR_UNSUPPORTED_TSQL_OPTION_CONTEXT_INFO, INSTR_UNSUPPORTED_TSQL_OPTION_QUERY_GOVERNOR_COST_LIMIT, INSTR_UNSUPPORTED_TSQL_OPTION_XML_METHOD, diff --git a/contrib/babelfishpg_tsql/src/tsqlIface.cpp b/contrib/babelfishpg_tsql/src/tsqlIface.cpp index 92a3d5d7b5..974a37d0e7 100644 --- a/contrib/babelfishpg_tsql/src/tsqlIface.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlIface.cpp @@ -4393,7 +4393,33 @@ makeSetStatement(TSqlParser::Set_statementContext *ctx, tsqlBuilder &builder) { throw PGErrorWrapperException(ERROR, ERRCODE_SYNTAX_ERROR, format_errmsg("unrecognized configuration parameter: %s", val.c_str()), getLineAndPos(set_special_ctx->id().front())); } - return makeSQL(ctx); + if (pg_strcasecmp("CONTEXT_INFO", val.c_str()) == 0) + { + std::string param = getFullText(set_special_ctx->constant_LOCAL_ID()); + if (pg_strncasecmp(param.c_str(), "NULL", 4) == 0 || param.length() == 0 || (pg_strncasecmp(param.c_str(), "0x", 2) == 0 && param.length() - 2 > 256)) + throw PGErrorWrapperException(ERROR, ERRCODE_INVALID_PARAMETER_VALUE, "SET CONTEXT_INFO option requires varbinary (128) NOT NULL parameter.", getLineAndPos(set_special_ctx->constant_LOCAL_ID())); + + PLtsql_stmt_execsql *stmt = (PLtsql_stmt_execsql *) palloc0(sizeof(PLtsql_stmt_execsql)); + std::string query; + query += "CALL bbf_set_context_info(convert(varbinary(128), "; + query += param; + query += "));"; + + stmt->cmd_type = PLTSQL_STMT_EXECSQL; + stmt->lineno = getLineNo(ctx); + stmt->sqlstmt = makeTsqlExpr(query, false); + stmt->into = false; + stmt->strict = false; + stmt->target = NULL; + stmt->need_to_push_result = false; + stmt->is_tsql_select_assign_stmt = false; + stmt->insert_exec = false; + + attachPLtsql_fragment(ctx, (PLtsql_stmt *) stmt); + return (PLtsql_stmt *) stmt; + } + else + return makeSQL(ctx); } else if (set_special_ctx->OFFSETS()) return nullptr; diff --git a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp index d391db3e1e..1c36f5ec21 100644 --- a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp @@ -1154,8 +1154,6 @@ antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitSet_statement(TSqlParser:: handle(INSTR_UNSUPPORTED_TSQL_OPTION_DATEFORMAT, "DATEFORMAT", &st_escape_hatch_session_settings, getLineAndPos(sctx)); if (pg_strcasecmp("DEADLOCK_PRIORITY", val.c_str()) == 0) handle(INSTR_UNSUPPORTED_TSQL_OPTION_DEADLOCK_PRIORITY, "DEADLOCK_PRIORITY", &st_escape_hatch_session_settings, getLineAndPos(sctx)); - if (pg_strcasecmp("CONTEXT_INFO", val.c_str()) == 0) - handle(INSTR_UNSUPPORTED_TSQL_OPTION_CONTEXT_INFO, "CONTEXT_INFO", &st_escape_hatch_session_settings, getLineAndPos(sctx)); if (pg_strcasecmp("QUERY_GOVERNOR_COST_LIMIT", val.c_str()) == 0) handle(INSTR_UNSUPPORTED_TSQL_OPTION_QUERY_GOVERNOR_COST_LIMIT, "QUERY_GOVERNOR_COST_LIMIT", &st_escape_hatch_session_settings, getLineAndPos(sctx)); diff --git a/test/JDBC/expected/BABEL-UNSUPPORTED.out b/test/JDBC/expected/BABEL-UNSUPPORTED.out index fa731230d3..5d833af09c 100644 --- a/test/JDBC/expected/BABEL-UNSUPPORTED.out +++ b/test/JDBC/expected/BABEL-UNSUPPORTED.out @@ -95,13 +95,6 @@ GO ~~ERROR (Message: 'DEADLOCK_PRIORITY' is not currently supported in Babelfish. please use babelfishpg_tsql.escape_hatch_session_settings to ignore)~~ -SET CONTEXT_INFO 0; -GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: 'CONTEXT_INFO' is not currently supported in Babelfish. please use babelfishpg_tsql.escape_hatch_session_settings to ignore)~~ - - SET LANGUAGE 'english' GO ~~ERROR (Code: 33557097)~~ @@ -262,8 +255,6 @@ SET DATEFORMAT dmy; GO SET DEADLOCK_PRIORITY 0; GO -SET CONTEXT_INFO 0; -GO SET LANGUAGE 'english'; GO diff --git a/test/JDBC/expected/babel_context_info-vu-cleanup.out b/test/JDBC/expected/babel_context_info-vu-cleanup.out new file mode 100644 index 0000000000..872ec2b27f --- /dev/null +++ b/test/JDBC/expected/babel_context_info-vu-cleanup.out @@ -0,0 +1,8 @@ +DROP PROCEDURE BABEL_SET_CONTEXT_INFO +GO + +DROP PROCEDURE BABEL_GET_CONTEXT_INFO +GO + +DROP VIEW BABEL_CONTEXT_INFO_VIEW +GO diff --git a/test/JDBC/expected/babel_context_info-vu-prepare.out b/test/JDBC/expected/babel_context_info-vu-prepare.out new file mode 100644 index 0000000000..62db0ea452 --- /dev/null +++ b/test/JDBC/expected/babel_context_info-vu-prepare.out @@ -0,0 +1,18 @@ +CREATE PROCEDURE BABEL_SET_CONTEXT_INFO + @context_info varbinary(128) +AS +BEGIN + EXEC sys.bbf_set_context_info @context_info +END; +GO + +CREATE PROCEDURE BABEL_GET_CONTEXT_INFO +AS +BEGIN + SELECT CONTEXT_INFO() +END; +GO + +CREATE VIEW BABEL_CONTEXT_INFO_VIEW AS + SELECT CONTEXT_INFO() +GO diff --git a/test/JDBC/expected/babel_context_info-vu-verify.out b/test/JDBC/expected/babel_context_info-vu-verify.out new file mode 100644 index 0000000000..d7fdbfd7b1 --- /dev/null +++ b/test/JDBC/expected/babel_context_info-vu-verify.out @@ -0,0 +1,368 @@ +-- upgrade test +SELECT CONTEXT_INFO() +GO +~~START~~ +varbinary + +~~END~~ + + +EXEC BABEL_GET_CONTEXT_INFO +GO +~~START~~ +varbinary + +~~END~~ + + +SELECT * FROM BABEL_CONTEXT_INFO_VIEW +GO +~~START~~ +varbinary + +~~END~~ + + +SELECT DISTINCT db_name(dbid), context_info FROM sys.sysprocesses WHERE spid = @@SPID +GO +~~START~~ +nvarchar#!#varbinary +master#!#0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + +SELECT context_info FROM sys.dm_exec_sessions WHERE session_id = @@SPID +GO +~~START~~ +varbinary +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + +EXEC BABEL_SET_CONTEXT_INFO 0x1234567812345678 +GO + +EXEC BABEL_GET_CONTEXT_INFO +GO +~~START~~ +varbinary +1234567812345678000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + +SELECT * FROM BABEL_CONTEXT_INFO_VIEW +GO +~~START~~ +varbinary +1234567812345678000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + +SELECT DISTINCT db_name(dbid), context_info FROM sys.sysprocesses WHERE spid = @@SPID +GO +~~START~~ +nvarchar#!#varbinary +master#!#1234567812345678000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + +SELECT context_info FROM sys.dm_exec_sessions WHERE session_id = @@SPID +GO +~~START~~ +varbinary +1234567812345678000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + + +-- test all data type +-- set date/datetime/xml, which should not be supported +DECLARE @context date = '2006-01-02' +SET CONTEXT_INFO @context +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type date to varbinary)~~ + + +SELECT CONTEXT_INFO() +GO +~~START~~ +varbinary +1234567812345678000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + +DECLARE @context datetime = '2006-01-02 15:04:05' +SET CONTEXT_INFO @context +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type datetime to varbinary)~~ + + +SELECT CONTEXT_INFO() +GO +~~START~~ +varbinary +1234567812345678000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + +DECLARE @context xml = '' +SET CONTEXT_INFO @context +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type xml to varbinary)~~ + + +SELECT CONTEXT_INFO() +GO +~~START~~ +varbinary +1234567812345678000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + +-- set bit/decimal/numeric/money, which is supported in SQL Server but is not supported in Babelfish for now. +DECLARE @context bit = 1 +SET CONTEXT_INFO @context +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type "bit" to varbinary)~~ + + +SELECT CONTEXT_INFO() +GO +~~START~~ +varbinary +1234567812345678000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + +DECLARE @context decimal(38, 6) = 12345678123456781234567812345678.123456 +SET CONTEXT_INFO @context +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type "decimal" to varbinary)~~ + + +SELECT CONTEXT_INFO() +GO +~~START~~ +varbinary +1234567812345678000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + +DECLARE @context decimal(38, 6) = 12345678123456781234567812345678.123456 +SET CONTEXT_INFO @context +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type "decimal" to varbinary)~~ + + +SELECT CONTEXT_INFO() +GO +~~START~~ +varbinary +1234567812345678000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + +DECLARE @context money = 12345678.12345678 +SET CONTEXT_INFO @context +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type money to varbinary)~~ + + +SELECT CONTEXT_INFO() +GO +~~START~~ +varbinary +1234567812345678000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + +-- set char/varchar directly, which should not be supported. +SET CONTEXT_INFO abc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: SET CONTEXT_INFO option requires varbinary (128) NOT NULL parameter.)~~ + + +SELECT CONTEXT_INFO() +GO +~~START~~ +varbinary +1234567812345678000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + +-- NB: set char/varchar by declared parameter, which is not supported in SQL Server but is supported in Babelfish. +DECLARE @context varchar(10) = 'abc' +SET CONTEXT_INFO @context +GO + +SELECT CONTEXT_INFO() +GO +~~START~~ +varbinary +6162630000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + +-- set int/bigint/smallint/tinyint +DECLARE @context int = 2147483647 +SET CONTEXT_INFO @context +GO + +SELECT CONTEXT_INFO() +GO +~~START~~ +varbinary +7FFFFFFF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + +DECLARE @context bigint = -9223372036854775808 +SET CONTEXT_INFO @context +GO + +SELECT CONTEXT_INFO() +GO +~~START~~ +varbinary +8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + +DECLARE @context smallint = -32768 +SET CONTEXT_INFO @context +GO + +SELECT CONTEXT_INFO() +GO +~~START~~ +varbinary +8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + +-- NB: set tinyint, which is ff0000000000000000 in SQL Server but is 00ff00000000000000 in Babelfish. +DECLARE @context tinyint = 255 +SET CONTEXT_INFO @context +GO + +SELECT CONTEXT_INFO() +GO +~~START~~ +varbinary +00FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + +-- set float/real +DECLARE @context float(53) = 12345678123456781234567812345678.123456 +SET CONTEXT_INFO @context +GO + +SELECT CONTEXT_INFO() +GO +~~START~~ +varbinary +46637A6132F61DC6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + +DECLARE @context real = 12345678123456781234567812345678.123456 +SET CONTEXT_INFO @context +GO + +SELECT CONTEXT_INFO() +GO +~~START~~ +varbinary +731BD30A00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + +-- set 0 +SET CONTEXT_INFO 0 +go + +SELECT CONTEXT_INFO() +GO +~~START~~ +varbinary +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + +-- set NULL +SET CONTEXT_INFO NULL +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: SET CONTEXT_INFO option requires varbinary (128) NOT NULL parameter.)~~ + + +SELECT CONTEXT_INFO() +GO +~~START~~ +varbinary +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + +-- set more than 128-byte hex constant +SET CONTEXT_INFO 0x123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567890 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: SET CONTEXT_INFO option requires varbinary (128) NOT NULL parameter.)~~ + + +SELECT CONTEXT_INFO() +GO +~~START~~ +varbinary +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + +-- set 128-byte hex constant +SET CONTEXT_INFO 0x1234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678 +GO + +SELECT CONTEXT_INFO() +GO +~~START~~ +varbinary +1234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678 +~~END~~ + + +SELECT DISTINCT db_name(dbid), context_info FROM sys.sysprocesses WHERE spid = @@SPID +GO +~~START~~ +nvarchar#!#varbinary +master#!#1234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678 +~~END~~ + + +SELECT context_info FROM sys.dm_exec_sessions WHERE session_id = @@SPID +GO +~~START~~ +varbinary +1234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678 +~~END~~ + + diff --git a/test/JDBC/input/BABEL-UNSUPPORTED.sql b/test/JDBC/input/BABEL-UNSUPPORTED.sql index 5810b4b377..6175ea471b 100644 --- a/test/JDBC/input/BABEL-UNSUPPORTED.sql +++ b/test/JDBC/input/BABEL-UNSUPPORTED.sql @@ -43,9 +43,6 @@ GO SET DEADLOCK_PRIORITY 0; GO -SET CONTEXT_INFO 0; -GO - SET LANGUAGE 'english' GO @@ -130,8 +127,6 @@ SET DATEFORMAT dmy; GO SET DEADLOCK_PRIORITY 0; GO -SET CONTEXT_INFO 0; -GO SET LANGUAGE 'english'; GO diff --git a/test/JDBC/input/babel_context_info-vu-cleanup.sql b/test/JDBC/input/babel_context_info-vu-cleanup.sql new file mode 100644 index 0000000000..872ec2b27f --- /dev/null +++ b/test/JDBC/input/babel_context_info-vu-cleanup.sql @@ -0,0 +1,8 @@ +DROP PROCEDURE BABEL_SET_CONTEXT_INFO +GO + +DROP PROCEDURE BABEL_GET_CONTEXT_INFO +GO + +DROP VIEW BABEL_CONTEXT_INFO_VIEW +GO diff --git a/test/JDBC/input/babel_context_info-vu-prepare.sql b/test/JDBC/input/babel_context_info-vu-prepare.sql new file mode 100644 index 0000000000..62db0ea452 --- /dev/null +++ b/test/JDBC/input/babel_context_info-vu-prepare.sql @@ -0,0 +1,18 @@ +CREATE PROCEDURE BABEL_SET_CONTEXT_INFO + @context_info varbinary(128) +AS +BEGIN + EXEC sys.bbf_set_context_info @context_info +END; +GO + +CREATE PROCEDURE BABEL_GET_CONTEXT_INFO +AS +BEGIN + SELECT CONTEXT_INFO() +END; +GO + +CREATE VIEW BABEL_CONTEXT_INFO_VIEW AS + SELECT CONTEXT_INFO() +GO diff --git a/test/JDBC/input/babel_context_info-vu-verify.sql b/test/JDBC/input/babel_context_info-vu-verify.sql new file mode 100644 index 0000000000..cd5ebb11b0 --- /dev/null +++ b/test/JDBC/input/babel_context_info-vu-verify.sql @@ -0,0 +1,178 @@ +-- upgrade test +SELECT CONTEXT_INFO() +GO + +EXEC BABEL_GET_CONTEXT_INFO +GO + +SELECT * FROM BABEL_CONTEXT_INFO_VIEW +GO + +SELECT DISTINCT db_name(dbid), context_info FROM sys.sysprocesses WHERE spid = @@SPID +GO + +SELECT context_info FROM sys.dm_exec_sessions WHERE session_id = @@SPID +GO + +EXEC BABEL_SET_CONTEXT_INFO 0x1234567812345678 +GO + +EXEC BABEL_GET_CONTEXT_INFO +GO + +SELECT * FROM BABEL_CONTEXT_INFO_VIEW +GO + +SELECT DISTINCT db_name(dbid), context_info FROM sys.sysprocesses WHERE spid = @@SPID +GO + +SELECT context_info FROM sys.dm_exec_sessions WHERE session_id = @@SPID +GO + +-- test all data type + +-- set date/datetime/xml, which should not be supported +DECLARE @context date = '2006-01-02' +SET CONTEXT_INFO @context +GO + +SELECT CONTEXT_INFO() +GO + +DECLARE @context datetime = '2006-01-02 15:04:05' +SET CONTEXT_INFO @context +GO + +SELECT CONTEXT_INFO() +GO + +DECLARE @context xml = '' +SET CONTEXT_INFO @context +GO + +SELECT CONTEXT_INFO() +GO + +-- set bit/decimal/numeric/money, which is supported in SQL Server but is not supported in Babelfish for now. +DECLARE @context bit = 1 +SET CONTEXT_INFO @context +GO + +SELECT CONTEXT_INFO() +GO + +DECLARE @context decimal(38, 6) = 12345678123456781234567812345678.123456 +SET CONTEXT_INFO @context +GO + +SELECT CONTEXT_INFO() +GO + +DECLARE @context decimal(38, 6) = 12345678123456781234567812345678.123456 +SET CONTEXT_INFO @context +GO + +SELECT CONTEXT_INFO() +GO + +DECLARE @context money = 12345678.12345678 +SET CONTEXT_INFO @context +GO + +SELECT CONTEXT_INFO() +GO + +-- set char/varchar directly, which should not be supported. +SET CONTEXT_INFO abc +GO + +SELECT CONTEXT_INFO() +GO + +-- NB: set char/varchar by declared parameter, which is not supported in SQL Server but is supported in Babelfish. +DECLARE @context varchar(10) = 'abc' +SET CONTEXT_INFO @context +GO + +SELECT CONTEXT_INFO() +GO + +-- set int/bigint/smallint/tinyint +DECLARE @context int = 2147483647 +SET CONTEXT_INFO @context +GO + +SELECT CONTEXT_INFO() +GO + +DECLARE @context bigint = -9223372036854775808 +SET CONTEXT_INFO @context +GO + +SELECT CONTEXT_INFO() +GO + +DECLARE @context smallint = -32768 +SET CONTEXT_INFO @context +GO + +SELECT CONTEXT_INFO() +GO + +-- NB: set tinyint, which is ff0000000000000000 in SQL Server but is 00ff00000000000000 in Babelfish. +DECLARE @context tinyint = 255 +SET CONTEXT_INFO @context +GO + +SELECT CONTEXT_INFO() +GO + +-- set float/real +DECLARE @context float(53) = 12345678123456781234567812345678.123456 +SET CONTEXT_INFO @context +GO + +SELECT CONTEXT_INFO() +GO + +DECLARE @context real = 12345678123456781234567812345678.123456 +SET CONTEXT_INFO @context +GO + +SELECT CONTEXT_INFO() +GO + +-- set 0 +SET CONTEXT_INFO 0 +go + +SELECT CONTEXT_INFO() +GO + +-- set NULL +SET CONTEXT_INFO NULL +GO + +SELECT CONTEXT_INFO() +GO + +-- set more than 128-byte hex constant +SET CONTEXT_INFO 0x123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567890 +GO + +SELECT CONTEXT_INFO() +GO + +-- set 128-byte hex constant +SET CONTEXT_INFO 0x1234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678 +GO + +SELECT CONTEXT_INFO() +GO + +SELECT DISTINCT db_name(dbid), context_info FROM sys.sysprocesses WHERE spid = @@SPID +GO + +SELECT context_info FROM sys.dm_exec_sessions WHERE session_id = @@SPID +GO + diff --git a/test/JDBC/upgrade/14_7/schedule b/test/JDBC/upgrade/14_7/schedule index 30ab4de85a..502ede5163 100644 --- a/test/JDBC/upgrade/14_7/schedule +++ b/test/JDBC/upgrade/14_7/schedule @@ -391,5 +391,6 @@ BABEL-3657 Test-sp_babelfish_volatility BABEL-733 BABEL-3938 +babel_context_info binary-index BABEL-745 diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index 08746dffb1..0dd1e0eee6 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -412,5 +412,6 @@ BABEL-733 BABEL-745 BABEL-3938 BABEL-NEXT-VALUE-FOR +babel_context_info binary-index test_windows_sp_helpuser From 5909c15ed4d6501072d260562bca6a96a010b773 Mon Sep 17 00:00:00 2001 From: Zhibai Date: Thu, 16 Mar 2023 11:15:27 -0700 Subject: [PATCH 017/363] Add support for rowcount in execution (#1331) * Add support for rowcount in execution previously we don't allow set rowcount other than 0 in this commit, we'll support rowcount > 0 for SELECT/UPDATE/INSERT/DELETE Signed-off-by: Zhibai Song Co-authored-by: Zhibai Song --- contrib/babelfishpg_tsql/src/guc.c | 19 +------ contrib/babelfishpg_tsql/src/hooks.c | 14 +++++ test/JDBC/expected/BABEL-1975.out | 14 ++++- test/JDBC/expected/rowcount-vu-cleanup.out | 14 +++++ test/JDBC/expected/rowcount-vu-prepare.out | 46 ++++++++++++++++ test/JDBC/expected/rowcount-vu-verify.out | 64 ++++++++++++++++++++++ test/JDBC/input/BABEL-1975.sql | 4 ++ test/JDBC/input/rowcount-vu-cleanup.sql | 14 +++++ test/JDBC/input/rowcount-vu-prepare.sql | 46 ++++++++++++++++ test/JDBC/input/rowcount-vu-verify.sql | 14 +++++ test/JDBC/upgrade/13_4/schedule | 1 + test/JDBC/upgrade/13_5/schedule | 1 + test/JDBC/upgrade/13_6/schedule | 1 + test/JDBC/upgrade/13_7/schedule | 1 + test/JDBC/upgrade/13_8/schedule | 1 + test/JDBC/upgrade/13_9/schedule | 1 + test/JDBC/upgrade/14_3/schedule | 1 + test/JDBC/upgrade/14_5/schedule | 1 + test/JDBC/upgrade/14_6/schedule | 1 + test/JDBC/upgrade/14_7/schedule | 1 + test/JDBC/upgrade/14_8/schedule | 1 + test/JDBC/upgrade/15_1/schedule | 1 + test/JDBC/upgrade/15_2/schedule | 1 + test/JDBC/upgrade/latest/schedule | 1 + 24 files changed, 243 insertions(+), 20 deletions(-) create mode 100644 test/JDBC/expected/rowcount-vu-cleanup.out create mode 100644 test/JDBC/expected/rowcount-vu-prepare.out create mode 100644 test/JDBC/expected/rowcount-vu-verify.out create mode 100644 test/JDBC/input/rowcount-vu-cleanup.sql create mode 100644 test/JDBC/input/rowcount-vu-prepare.sql create mode 100644 test/JDBC/input/rowcount-vu-verify.sql diff --git a/contrib/babelfishpg_tsql/src/guc.c b/contrib/babelfishpg_tsql/src/guc.c index a64203e482..5bdd89be1a 100644 --- a/contrib/babelfishpg_tsql/src/guc.c +++ b/contrib/babelfishpg_tsql/src/guc.c @@ -94,7 +94,6 @@ static bool check_arithabort (bool *newval, void **extra, GucSource source); static bool check_babelfish_dump_restore_min_oid (char **newval, void **extra, GucSource source); static bool check_numeric_roundabort (bool *newval, void **extra, GucSource source); static bool check_cursor_close_on_commit (bool *newval, void **extra, GucSource source); -static bool check_rowcount (int *newval, void **extra, GucSource source); static bool check_language (char **newval, void **extra, GucSource source); static bool check_noexec (bool *newval, void **extra, GucSource source); static bool check_showplan_all (bool *newval, void **extra, GucSource source); @@ -263,22 +262,6 @@ static bool check_cursor_close_on_commit (bool *newval, void **extra, GucSource return true; } -static bool check_rowcount (int *newval, void **extra, GucSource source) -{ - if (*newval != 0 && *newval != INT_MAX && escape_hatch_session_settings != EH_IGNORE) - { - TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_OPTION_ROWCOUNT); - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Settings other than 0 are not allowed for option ROWCOUNT. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); - } - else if (escape_hatch_session_settings == EH_IGNORE) - { - *newval = 0; /* overwrite to a default value. This would change the value if it was set to INT_MAX before. but, it would not cause a pratical problem */ - } - return true; -} - static bool check_language (char **newval, void **extra, GucSource source) { /* We will only allow "us_english" for now */ @@ -762,7 +745,7 @@ define_custom_variables(void) 0, 0, INT_MAX, PGC_USERSET, GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - check_rowcount, NULL, NULL); + NULL, NULL, NULL); DefineCustomIntVariable("babelfishpg_tsql.lock_timeout", gettext_noop("Specifies the number of milliseconds a statement waits for a lock to be released."), diff --git a/contrib/babelfishpg_tsql/src/hooks.c b/contrib/babelfishpg_tsql/src/hooks.c index 00d07acbc5..87b82f7c26 100644 --- a/contrib/babelfishpg_tsql/src/hooks.c +++ b/contrib/babelfishpg_tsql/src/hooks.c @@ -136,6 +136,7 @@ static void pltsql_ExecutorFinish(QueryDesc *queryDesc); static void pltsql_ExecutorEnd(QueryDesc *queryDesc); static bool plsql_TriggerRecursiveCheck(ResultRelInfo *resultRelInfo); +static bool bbf_check_rowcount_hook(int es_processed); /***************************************** * Replication Hooks @@ -185,6 +186,7 @@ static transform_check_constraint_expr_hook_type prev_transform_check_constraint static validate_var_datatype_scale_hook_type prev_validate_var_datatype_scale_hook = NULL; static modify_RangeTblFunction_tupdesc_hook_type prev_modify_RangeTblFunction_tupdesc_hook = NULL; static fill_missing_values_in_copyfrom_hook_type prev_fill_missing_values_in_copyfrom_hook = NULL; +static check_rowcount_hook_type prev_check_rowcount_hook = NULL; /***************************************** * Install / Uninstall @@ -293,6 +295,8 @@ InstallExtendedHooks(void) prev_fill_missing_values_in_copyfrom_hook = fill_missing_values_in_copyfrom_hook; fill_missing_values_in_copyfrom_hook = fill_missing_values_in_copyfrom; + prev_check_rowcount_hook = check_rowcount_hook; + check_rowcount_hook = bbf_check_rowcount_hook; } void @@ -336,6 +340,7 @@ UninstallExtendedHooks(void) validate_var_datatype_scale_hook = prev_validate_var_datatype_scale_hook; modify_RangeTblFunction_tupdesc_hook = prev_modify_RangeTblFunction_tupdesc_hook; fill_missing_values_in_copyfrom_hook = prev_fill_missing_values_in_copyfrom_hook; + check_rowcount_hook = prev_check_rowcount_hook; } /***************************************** @@ -434,6 +439,9 @@ pltsql_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, return; } + if ((count == 0 || count > pltsql_rowcount) && queryDesc->operation == CMD_SELECT) + count = pltsql_rowcount; + if (prev_ExecutorRun) prev_ExecutorRun(queryDesc, direction, count, execute_once); else @@ -3447,3 +3455,9 @@ fill_missing_values_in_copyfrom(Relation rel, Datum *values, bool *nulls) nulls[attnum - 1] = false; } } + +static bool bbf_check_rowcount_hook(int es_processed){ + if (pltsql_rowcount == es_processed && es_processed > 0) + return true; + else return false; +} diff --git a/test/JDBC/expected/BABEL-1975.out b/test/JDBC/expected/BABEL-1975.out index c23531734b..8c05db9e85 100644 --- a/test/JDBC/expected/BABEL-1975.out +++ b/test/JDBC/expected/BABEL-1975.out @@ -59,9 +59,19 @@ int SET ROWCOUNT 1; SELECT @@rowcount; GO -~~ERROR (Code: 33557097)~~ +~~START~~ +int +0 +~~END~~ + -~~ERROR (Message: Settings other than 0 are not allowed for option ROWCOUNT. please use babelfishpg_tsql.escape_hatch_session_settings to ignore)~~ +set ROWCOUNT 0; +SELECT @@rowcount; +GO +~~START~~ +int +0 +~~END~~ -- clean up diff --git a/test/JDBC/expected/rowcount-vu-cleanup.out b/test/JDBC/expected/rowcount-vu-cleanup.out new file mode 100644 index 0000000000..033916fde1 --- /dev/null +++ b/test/JDBC/expected/rowcount-vu-cleanup.out @@ -0,0 +1,14 @@ +drop procedure rowcountinsert; +GO + +drop procedure rowcountselect; +GO + +drop procedure rowcountupdate; +GO + +drop procedure rowcountdelete; +GO + +drop table testing1 +GO diff --git a/test/JDBC/expected/rowcount-vu-prepare.out b/test/JDBC/expected/rowcount-vu-prepare.out new file mode 100644 index 0000000000..b2c10edcd9 --- /dev/null +++ b/test/JDBC/expected/rowcount-vu-prepare.out @@ -0,0 +1,46 @@ +create table testing1 (a int); +GO + +create procedure rowcountinsert as +begin + set rowcount 1; + insert into testing1 values (1); + insert into testing1 values (1); + insert into testing1 select a + 1 from testing1; + insert into testing1 select a + 1 from testing1; + set rowcount 0; + set rowcount 5; + insert into testing1 select a from testing1; + insert into testing1 select a from testing1; + set rowcount 0; +end +GO + +create procedure rowcountselect as +begin + set rowcount 1; + select count(*) from testing1; + select * from testing1; + set rowcount 0; +end +GO + +create procedure rowcountupdate as +begin + set rowcount 1; + select count(*) from testing1; + update testing1 set a = 10; + select count(*) from testing1 where a = 10; + set rowcount 0; +end +GO + +create procedure rowcountdelete as +begin + set rowcount 1; + select count(*) from testing1 where a = 1; + delete from testing1 where a = 1; + select count(*) from testing1 where a = 1; + set rowcount 0; +end +GO diff --git a/test/JDBC/expected/rowcount-vu-verify.out b/test/JDBC/expected/rowcount-vu-verify.out new file mode 100644 index 0000000000..f11938df4d --- /dev/null +++ b/test/JDBC/expected/rowcount-vu-verify.out @@ -0,0 +1,64 @@ +exec rowcountinsert; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 4~~ + +~~ROW COUNT: 5~~ + + +exec rowcountselect; +GO +~~START~~ +int +13 +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +exec rowcountupdate; +GO +~~START~~ +int +13 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + + +exec rowcountdelete; +GO +~~START~~ +int +6 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +5 +~~END~~ + + +set rowcount -1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: -1 is outside the valid range for parameter "babelfishpg_tsql.rowcount" (0 .. 2147483647))~~ + diff --git a/test/JDBC/input/BABEL-1975.sql b/test/JDBC/input/BABEL-1975.sql index e1c29f861a..aa7e6f6748 100644 --- a/test/JDBC/input/BABEL-1975.sql +++ b/test/JDBC/input/BABEL-1975.sql @@ -25,6 +25,10 @@ SET ROWCOUNT 1; SELECT @@rowcount; GO +set ROWCOUNT 0; +SELECT @@rowcount; +GO + -- clean up DROP TABLE t1; GO diff --git a/test/JDBC/input/rowcount-vu-cleanup.sql b/test/JDBC/input/rowcount-vu-cleanup.sql new file mode 100644 index 0000000000..15ba153f3a --- /dev/null +++ b/test/JDBC/input/rowcount-vu-cleanup.sql @@ -0,0 +1,14 @@ +drop procedure rowcountinsert; +GO + +drop procedure rowcountselect; +GO + +drop procedure rowcountupdate; +GO + +drop procedure rowcountdelete; +GO + +drop table testing1 +GO \ No newline at end of file diff --git a/test/JDBC/input/rowcount-vu-prepare.sql b/test/JDBC/input/rowcount-vu-prepare.sql new file mode 100644 index 0000000000..b2c10edcd9 --- /dev/null +++ b/test/JDBC/input/rowcount-vu-prepare.sql @@ -0,0 +1,46 @@ +create table testing1 (a int); +GO + +create procedure rowcountinsert as +begin + set rowcount 1; + insert into testing1 values (1); + insert into testing1 values (1); + insert into testing1 select a + 1 from testing1; + insert into testing1 select a + 1 from testing1; + set rowcount 0; + set rowcount 5; + insert into testing1 select a from testing1; + insert into testing1 select a from testing1; + set rowcount 0; +end +GO + +create procedure rowcountselect as +begin + set rowcount 1; + select count(*) from testing1; + select * from testing1; + set rowcount 0; +end +GO + +create procedure rowcountupdate as +begin + set rowcount 1; + select count(*) from testing1; + update testing1 set a = 10; + select count(*) from testing1 where a = 10; + set rowcount 0; +end +GO + +create procedure rowcountdelete as +begin + set rowcount 1; + select count(*) from testing1 where a = 1; + delete from testing1 where a = 1; + select count(*) from testing1 where a = 1; + set rowcount 0; +end +GO diff --git a/test/JDBC/input/rowcount-vu-verify.sql b/test/JDBC/input/rowcount-vu-verify.sql new file mode 100644 index 0000000000..7efc6f7d5f --- /dev/null +++ b/test/JDBC/input/rowcount-vu-verify.sql @@ -0,0 +1,14 @@ +exec rowcountinsert; +GO + +exec rowcountselect; +GO + +exec rowcountupdate; +GO + +exec rowcountdelete; +GO + +set rowcount -1 +GO diff --git a/test/JDBC/upgrade/13_4/schedule b/test/JDBC/upgrade/13_4/schedule index fceac9be2d..b1390a5f38 100644 --- a/test/JDBC/upgrade/13_4/schedule +++ b/test/JDBC/upgrade/13_4/schedule @@ -198,3 +198,4 @@ case_insensitive_collation-before-13-5 test_windows_login_before_15_2 BABEL-3657 BABEL-3938 +rowcount diff --git a/test/JDBC/upgrade/13_5/schedule b/test/JDBC/upgrade/13_5/schedule index 3af95b2df5..0f6f9202d7 100644 --- a/test/JDBC/upgrade/13_5/schedule +++ b/test/JDBC/upgrade/13_5/schedule @@ -249,3 +249,4 @@ case_insensitive_collation-before-13-5 test_windows_login_before_15_2 BABEL-3657 BABEL-3938 +rowcount diff --git a/test/JDBC/upgrade/13_6/schedule b/test/JDBC/upgrade/13_6/schedule index 638c2da521..7e2f8a88f0 100644 --- a/test/JDBC/upgrade/13_6/schedule +++ b/test/JDBC/upgrade/13_6/schedule @@ -309,3 +309,4 @@ BABEL_OBJECT_NAME Test-sp_babelfish_volatility BABEL-3657 BABEL-3938 +rowcount diff --git a/test/JDBC/upgrade/13_7/schedule b/test/JDBC/upgrade/13_7/schedule index d82cb16d0a..cb6950ec2c 100644 --- a/test/JDBC/upgrade/13_7/schedule +++ b/test/JDBC/upgrade/13_7/schedule @@ -304,3 +304,4 @@ Test-sp_babelfish_volatility BABEL_SCHEMATA BABEL-3657 BABEL-3938 +rowcount diff --git a/test/JDBC/upgrade/13_8/schedule b/test/JDBC/upgrade/13_8/schedule index d82cb16d0a..cb6950ec2c 100644 --- a/test/JDBC/upgrade/13_8/schedule +++ b/test/JDBC/upgrade/13_8/schedule @@ -304,3 +304,4 @@ Test-sp_babelfish_volatility BABEL_SCHEMATA BABEL-3657 BABEL-3938 +rowcount diff --git a/test/JDBC/upgrade/13_9/schedule b/test/JDBC/upgrade/13_9/schedule index 2f6d57b59c..67b03c1082 100644 --- a/test/JDBC/upgrade/13_9/schedule +++ b/test/JDBC/upgrade/13_9/schedule @@ -307,3 +307,4 @@ BABEL_OBJECT_NAME Test-sp_babelfish_volatility BABEL-3657 BABEL-3938 +rowcount diff --git a/test/JDBC/upgrade/14_3/schedule b/test/JDBC/upgrade/14_3/schedule index 61f4883d35..b8ca6b0d60 100644 --- a/test/JDBC/upgrade/14_3/schedule +++ b/test/JDBC/upgrade/14_3/schedule @@ -322,3 +322,4 @@ Test-sp_babelfish_volatility BABEL-3657 BABEL-3938 binary-index +rowcount diff --git a/test/JDBC/upgrade/14_5/schedule b/test/JDBC/upgrade/14_5/schedule index 0eeabab8e2..611dfcbe1f 100644 --- a/test/JDBC/upgrade/14_5/schedule +++ b/test/JDBC/upgrade/14_5/schedule @@ -336,3 +336,4 @@ Test-sp_babelfish_volatility BABEL-3657 BABEL-3938 binary-index +rowcount diff --git a/test/JDBC/upgrade/14_6/schedule b/test/JDBC/upgrade/14_6/schedule index a888d2d3b1..a5bd4445f7 100644 --- a/test/JDBC/upgrade/14_6/schedule +++ b/test/JDBC/upgrade/14_6/schedule @@ -363,3 +363,4 @@ BABEL_SCHEMATA BABEL-3657 BABEL-3938 binary-index +rowcount diff --git a/test/JDBC/upgrade/14_7/schedule b/test/JDBC/upgrade/14_7/schedule index 502ede5163..612c4a0d43 100644 --- a/test/JDBC/upgrade/14_7/schedule +++ b/test/JDBC/upgrade/14_7/schedule @@ -394,3 +394,4 @@ BABEL-3938 babel_context_info binary-index BABEL-745 +rowcount diff --git a/test/JDBC/upgrade/14_8/schedule b/test/JDBC/upgrade/14_8/schedule index b5f1ee979c..0f901ee95f 100644 --- a/test/JDBC/upgrade/14_8/schedule +++ b/test/JDBC/upgrade/14_8/schedule @@ -392,3 +392,4 @@ Test-sp_babelfish_volatility BABEL-733 BABEL-3938 binary-index +rowcount diff --git a/test/JDBC/upgrade/15_1/schedule b/test/JDBC/upgrade/15_1/schedule index 2d2cb13ef9..a92fde4491 100644 --- a/test/JDBC/upgrade/15_1/schedule +++ b/test/JDBC/upgrade/15_1/schedule @@ -372,3 +372,4 @@ BABEL_OBJECT_NAME BABEL-3657 BABEL-3938 binary-index +rowcount diff --git a/test/JDBC/upgrade/15_2/schedule b/test/JDBC/upgrade/15_2/schedule index ad1ca99fc7..9341c416ce 100644 --- a/test/JDBC/upgrade/15_2/schedule +++ b/test/JDBC/upgrade/15_2/schedule @@ -409,4 +409,5 @@ BABEL-733 BABEL-3938 BABEL-NEXT-VALUE-FOR binary-index +rowcount # test_windows_sp_helpuser diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index 0dd1e0eee6..279b65dee7 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -415,3 +415,4 @@ BABEL-NEXT-VALUE-FOR babel_context_info binary-index test_windows_sp_helpuser +rowcount From de9b4ab4d9d15ef002c5a9506370557ae9dd9117 Mon Sep 17 00:00:00 2001 From: pratikzode <73869399+pratikzode@users.noreply.github.com> Date: Thu, 16 Mar 2023 15:33:19 -0700 Subject: [PATCH 018/363] BABEL-3478 Support the ROWCOUNT_BIG() function. (#1343) * BABEL-3478 Support the ROWCOUNT_BIG() function. We have implemented function rowcount_big() Task: BABEL-3802 Signed-off-by: pratikzode --- .../babelfishpg_tsql/sql/sys_functions.sql | 3 + .../babelfishpg_tsql--3.1.0--3.2.0.sql | 3 + contrib/babelfishpg_tsql/src/pl_funcs-2.c | 8 ++ test/JDBC/expected/BABEL-3478-vu-cleanup.out | 17 +++ test/JDBC/expected/BABEL-3478-vu-prepare.out | 63 +++++++++++ test/JDBC/expected/BABEL-3478-vu-verify.out | 100 ++++++++++++++++++ test/JDBC/input/BABEL-3478-vu-cleanup.sql | 17 +++ test/JDBC/input/BABEL-3478-vu-prepare.sql | 61 +++++++++++ test/JDBC/input/BABEL-3478-vu-verify.sql | 35 ++++++ test/JDBC/upgrade/latest/schedule | 1 + 10 files changed, 308 insertions(+) create mode 100644 test/JDBC/expected/BABEL-3478-vu-cleanup.out create mode 100644 test/JDBC/expected/BABEL-3478-vu-prepare.out create mode 100644 test/JDBC/expected/BABEL-3478-vu-verify.out create mode 100644 test/JDBC/input/BABEL-3478-vu-cleanup.sql create mode 100644 test/JDBC/input/BABEL-3478-vu-prepare.sql create mode 100644 test/JDBC/input/BABEL-3478-vu-verify.sql diff --git a/contrib/babelfishpg_tsql/sql/sys_functions.sql b/contrib/babelfishpg_tsql/sql/sys_functions.sql index e8ff54d0ed..1a57c6e90f 100644 --- a/contrib/babelfishpg_tsql/sql/sys_functions.sql +++ b/contrib/babelfishpg_tsql/sql/sys_functions.sql @@ -1707,6 +1707,9 @@ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; CREATE OR REPLACE FUNCTION sys.rowcount() RETURNS INT AS 'babelfishpg_tsql' LANGUAGE C STABLE; +CREATE OR REPLACE FUNCTION sys.rowcount_big() +RETURNS BIGINT AS 'babelfishpg_tsql' LANGUAGE C STABLE; + CREATE OR REPLACE FUNCTION sys.error() RETURNS INT AS 'babelfishpg_tsql' LANGUAGE C STABLE; diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql index 4c161516b8..ec6ee7a571 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql @@ -105,6 +105,9 @@ CREATE AGGREGATE sys.VARP(float8) ( INITCOND = '{0,0,0}' ); +CREATE OR REPLACE FUNCTION sys.rowcount_big() +RETURNS BIGINT AS 'babelfishpg_tsql' LANGUAGE C STABLE; + ALTER FUNCTION sys.tsql_stat_get_activity(text) RENAME TO tsql_stat_get_activity_deprecated_in_3_2_0; CREATE OR REPLACE FUNCTION sys.tsql_stat_get_activity_deprecated_in_3_2_0( IN view_name text, diff --git a/contrib/babelfishpg_tsql/src/pl_funcs-2.c b/contrib/babelfishpg_tsql/src/pl_funcs-2.c index 0ee473f33e..ceeafb18c3 100644 --- a/contrib/babelfishpg_tsql/src/pl_funcs-2.c +++ b/contrib/babelfishpg_tsql/src/pl_funcs-2.c @@ -99,6 +99,14 @@ rowcount(PG_FUNCTION_ARGS) PG_RETURN_INT32(rowcount_var); } +PG_FUNCTION_INFO_V1(rowcount_big); + +Datum +rowcount_big(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(rowcount_var); +} + PG_FUNCTION_INFO_V1(fetch_status); Datum diff --git a/test/JDBC/expected/BABEL-3478-vu-cleanup.out b/test/JDBC/expected/BABEL-3478-vu-cleanup.out new file mode 100644 index 0000000000..68d85ff999 --- /dev/null +++ b/test/JDBC/expected/BABEL-3478-vu-cleanup.out @@ -0,0 +1,17 @@ +DROP VIEW BABEL_3478_t1_InfoView +GO + +DROP PROCEDURE Insert_BABEL_3478_p1; +GO + +DROP VIEW Updated_BABEL_3478_InfoView; +GO + +DROP PROCEDURE Update_BABEL_3478_Salary; +GO + +DROP PROCEDURE Delete_BABEL_3478_p2; +GO + +DROP TABLE BABEL_3478_t1; +GO diff --git a/test/JDBC/expected/BABEL-3478-vu-prepare.out b/test/JDBC/expected/BABEL-3478-vu-prepare.out new file mode 100644 index 0000000000..9ddfa52079 --- /dev/null +++ b/test/JDBC/expected/BABEL-3478-vu-prepare.out @@ -0,0 +1,63 @@ +CREATE TABLE BABEL_3478_t1 ( + ID INT PRIMARY KEY IDENTITY(1,1), + FirstName VARCHAR(50), + LastName VARCHAR(50), + Salary MONEY +); +GO +-- Inserting data into the BABEL_3478_t1 table +INSERT INTO BABEL_3478_t1 (FirstName, LastName, Salary) +VALUES ('John', 'Doe', 50000), + ('Jane', 'Doe', 60000), + ('Jim', 'Smith', 55000), + ('Sarah', 'Johnson', 65000), + ('David', 'Lee', 70000), + ('Jennifer', 'Garcia', 55000); +GO +~~ROW COUNT: 6~~ + + + +CREATE VIEW BABEL_3478_t1_InfoView AS +SELECT ROWCOUNT_BIG() +FROM BABEL_3478_t1; +GO + +CREATE PROCEDURE Insert_BABEL_3478_p1 +AS +BEGIN + -- Inserting data into the BABEL_3478_t1 table + INSERT INTO BABEL_3478_t1 (FirstName, LastName, Salary) + VALUES ('Dwayne', 'Johnson', 90000000), ('Chris', 'Jericho', 4000000), ('Jhon', 'Chena', 55000); + SELECT ROWCOUNT_BIG() +END; +GO + + +CREATE VIEW Updated_BABEL_3478_InfoView AS +SELECT ROWCOUNT_BIG() +FROM BABEL_3478_t1 +WHERE LastName = 'Doe'; +GO + +CREATE PROCEDURE Update_BABEL_3478_Salary + @LastName VARCHAR(50), + @NewSalary MONEY +AS +BEGIN + UPDATE BABEL_3478_t1 + SET Salary = @NewSalary + WHERE LastName = @LastName; + SELECT ROWCOUNT_BIG() +END +GO + + +CREATE PROCEDURE Delete_BABEL_3478_p2 + @LastName VARCHAR(50) +AS +BEGIN + DELETE FROM BABEL_3478_t1 WHERE LastName = @LastName; + SELECT ROWCOUNT_BIG() +END; +GO diff --git a/test/JDBC/expected/BABEL-3478-vu-verify.out b/test/JDBC/expected/BABEL-3478-vu-verify.out new file mode 100644 index 0000000000..4b23ae409b --- /dev/null +++ b/test/JDBC/expected/BABEL-3478-vu-verify.out @@ -0,0 +1,100 @@ +SELECT * FROM BABEL_3478_t1 +ORDER BY FirstName, LastName; +SELECT ROWCOUNT_BIG(); +GO +~~START~~ +int#!#varchar#!#varchar#!#money +5#!#David#!#Lee#!#70000.0000 +2#!#Jane#!#Doe#!#60000.0000 +6#!#Jennifer#!#Garcia#!#55000.0000 +3#!#Jim#!#Smith#!#55000.0000 +1#!#John#!#Doe#!#50000.0000 +4#!#Sarah#!#Johnson#!#65000.0000 +~~END~~ + +~~START~~ +bigint +6 +~~END~~ + + + +-- Updating the salary of BABEL_3478_t1 with last name 'Doe' +UPDATE BABEL_3478_t1 SET Salary = 65000 WHERE LastName = 'Doe'; +SELECT ROWCOUNT_BIG(); +GO +~~ROW COUNT: 2~~ + +~~START~~ +bigint +2 +~~END~~ + + + +-- Deleting BABEL_3478_t1 with last name 'Smith' +DELETE FROM BABEL_3478_t1 WHERE LastName = 'Smith'; +SELECT ROWCOUNT_BIG(); +GO +~~ROW COUNT: 1~~ + +~~START~~ +bigint +1 +~~END~~ + + + +SELECT * FROM BABEL_3478_t1_InfoView; +GO +~~START~~ +bigint +1 +1 +1 +1 +1 +~~END~~ + + + +EXEC Insert_BABEL_3478_p1; +GO +~~ROW COUNT: 3~~ + +~~START~~ +bigint +3 +~~END~~ + + + + +SELECT * FROM Updated_BABEL_3478_InfoView; +GO +~~START~~ +bigint +1 +1 +~~END~~ + + +EXEC Update_BABEL_3478_Salary 'Doe', 700000; +GO +~~ROW COUNT: 2~~ + +~~START~~ +bigint +2 +~~END~~ + + +EXEC Delete_BABEL_3478_p2 'Doe'; +GO +~~ROW COUNT: 2~~ + +~~START~~ +bigint +2 +~~END~~ + diff --git a/test/JDBC/input/BABEL-3478-vu-cleanup.sql b/test/JDBC/input/BABEL-3478-vu-cleanup.sql new file mode 100644 index 0000000000..68d85ff999 --- /dev/null +++ b/test/JDBC/input/BABEL-3478-vu-cleanup.sql @@ -0,0 +1,17 @@ +DROP VIEW BABEL_3478_t1_InfoView +GO + +DROP PROCEDURE Insert_BABEL_3478_p1; +GO + +DROP VIEW Updated_BABEL_3478_InfoView; +GO + +DROP PROCEDURE Update_BABEL_3478_Salary; +GO + +DROP PROCEDURE Delete_BABEL_3478_p2; +GO + +DROP TABLE BABEL_3478_t1; +GO diff --git a/test/JDBC/input/BABEL-3478-vu-prepare.sql b/test/JDBC/input/BABEL-3478-vu-prepare.sql new file mode 100644 index 0000000000..2572b77917 --- /dev/null +++ b/test/JDBC/input/BABEL-3478-vu-prepare.sql @@ -0,0 +1,61 @@ +CREATE TABLE BABEL_3478_t1 ( + ID INT PRIMARY KEY IDENTITY(1,1), + FirstName VARCHAR(50), + LastName VARCHAR(50), + Salary MONEY +); +GO +-- Inserting data into the BABEL_3478_t1 table +INSERT INTO BABEL_3478_t1 (FirstName, LastName, Salary) +VALUES ('John', 'Doe', 50000), + ('Jane', 'Doe', 60000), + ('Jim', 'Smith', 55000), + ('Sarah', 'Johnson', 65000), + ('David', 'Lee', 70000), + ('Jennifer', 'Garcia', 55000); +GO + + +CREATE VIEW BABEL_3478_t1_InfoView AS +SELECT ROWCOUNT_BIG() +FROM BABEL_3478_t1; +GO + +CREATE PROCEDURE Insert_BABEL_3478_p1 +AS +BEGIN + -- Inserting data into the BABEL_3478_t1 table + INSERT INTO BABEL_3478_t1 (FirstName, LastName, Salary) + VALUES ('Dwayne', 'Johnson', 90000000), ('Chris', 'Jericho', 4000000), ('Jhon', 'Chena', 55000); + SELECT ROWCOUNT_BIG() +END; +GO + + +CREATE VIEW Updated_BABEL_3478_InfoView AS +SELECT ROWCOUNT_BIG() +FROM BABEL_3478_t1 +WHERE LastName = 'Doe'; +GO + +CREATE PROCEDURE Update_BABEL_3478_Salary + @LastName VARCHAR(50), + @NewSalary MONEY +AS +BEGIN + UPDATE BABEL_3478_t1 + SET Salary = @NewSalary + WHERE LastName = @LastName; + SELECT ROWCOUNT_BIG() +END +GO + + +CREATE PROCEDURE Delete_BABEL_3478_p2 + @LastName VARCHAR(50) +AS +BEGIN + DELETE FROM BABEL_3478_t1 WHERE LastName = @LastName; + SELECT ROWCOUNT_BIG() +END; +GO diff --git a/test/JDBC/input/BABEL-3478-vu-verify.sql b/test/JDBC/input/BABEL-3478-vu-verify.sql new file mode 100644 index 0000000000..0c2e802d71 --- /dev/null +++ b/test/JDBC/input/BABEL-3478-vu-verify.sql @@ -0,0 +1,35 @@ +SELECT * FROM BABEL_3478_t1 +ORDER BY FirstName, LastName; +SELECT ROWCOUNT_BIG(); +GO + + +-- Updating the salary of BABEL_3478_t1 with last name 'Doe' +UPDATE BABEL_3478_t1 SET Salary = 65000 WHERE LastName = 'Doe'; +SELECT ROWCOUNT_BIG(); +GO + + +-- Deleting BABEL_3478_t1 with last name 'Smith' +DELETE FROM BABEL_3478_t1 WHERE LastName = 'Smith'; +SELECT ROWCOUNT_BIG(); +GO + + +SELECT * FROM BABEL_3478_t1_InfoView; +GO + + +EXEC Insert_BABEL_3478_p1; +GO + + + +SELECT * FROM Updated_BABEL_3478_InfoView; +GO + +EXEC Update_BABEL_3478_Salary 'Doe', 700000; +GO + +EXEC Delete_BABEL_3478_p2 'Doe'; +GO diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index 279b65dee7..69c210a6ff 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -415,4 +415,5 @@ BABEL-NEXT-VALUE-FOR babel_context_info binary-index test_windows_sp_helpuser +BABEL-3478 rowcount From 91a345435fbfda59bbba3582089d111914eb2b13 Mon Sep 17 00:00:00 2001 From: Kushaal Shroff <51415286+KushaalShroff@users.noreply.github.com> Date: Fri, 17 Mar 2023 16:36:45 +0530 Subject: [PATCH 019/363] Long TVP PARAMETER names in RPC throw error (#1346) ISSUE: We create a unique temp-table-name by adding the following suffix: "{}TDSTVP_TEMP_TABLE{_}%d", (int)rand() Now if we create a temp table with this unique temp-table-name (however long), it gets created. But we have a tvp_lookup_list which maintains the list of tvps the TSQL Extension has to read. For that list we have inserted a modified and truncated TVP name. Rather than storing tableName we store finalTableName, which CAN be different from what was created. Although the though behind it seems logical but it(truncation) should have been done for the temp-table which got created. FIX: So to fix this we had to truncate the actual tvp name along with its schema name, if provided. We also had to move the logic to fetch tvp type oid from ReadParameter - fetch phase to Recv Function - process phase because we required the truncated names to do so. NOTE: We cannot do truncation in Fetch phase because we require 1. A transaction 2. MessageMemoryContext which are both available during Process phase Signed-off-by: Kushaal Shroff kushaal@amazon.com --- .../babelfishpg_tds/src/backend/tds/tdsrpc.c | 32 +---- .../src/backend/tds/tdstypeio.c | 119 ++++++++++++++++-- .../babelfishpg_tds/src/include/tds_request.h | 16 +-- .../babelfishpg_tds/src/include/tds_typeio.h | 1 + test/dotnet/ExpectedOutput/TestTvp.out | 22 ++++ test/dotnet/input/Datatypes/TestTvp.txt | 22 ++++ 6 files changed, 157 insertions(+), 55 deletions(-) diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdsrpc.c b/contrib/babelfishpg_tds/src/backend/tds/tdsrpc.c index c990c63349..b881d043ef 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tdsrpc.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tdsrpc.c @@ -1027,6 +1027,7 @@ SPCustomType(TDSRequestSP req) bool *nulls; char *activity; + tvp_lookup_list = NIL; TdsErrorContext->err_text = "Processing SP_CUSTOMTYPE Request"; if ((req->nTotalParams) > PREPARE_STMT_MAX_ARGS) ereport(ERROR, @@ -1134,6 +1135,7 @@ SPCustomType(TDSRequestSP req) */ TDSLogDuration(req->name.data); pfree(codeblock); + tvp_lookup_list = NIL; } static void @@ -1754,37 +1756,7 @@ ReadParameters(TDSRequestSP request, uint64_t offset, StringInfo message, int *p */ SetParamMetadataCommonInfo(&(temp->paramMeta), tempFuncInfo); - /* Explicity retrieve the oid for TVP type and map it. */ - if (temp->paramMeta.pgTypeOid == InvalidOid && tdsType == TDS_TYPE_TABLE) - { - int rc; - HeapTuple row; - bool isnull; - TupleDesc tupdesc; - char * query; - - StartTransactionCommand(); - PushActiveSnapshot(GetTransactionSnapshot()); - if ((rc = SPI_connect()) < 0) - elog(ERROR, "SPI_connect() failed in TDS Listener " - "with return code %d", rc); - - query = psprintf("SELECT '%s'::regtype::oid", temp->tvpInfo->tvpTypeName); - rc = SPI_execute(query, false, 1); - if(rc != SPI_OK_SELECT) - elog(ERROR, "Failed to insert in the underlying table for table-valued parameter: %d", rc); - - tupdesc = SPI_tuptable->tupdesc; - row = SPI_tuptable->vals[0]; - - temp->paramMeta.pgTypeOid = DatumGetObjectId(SPI_getbinval(row, tupdesc, - 1, &isnull)); - - SPI_finish(); - PopActiveSnapshot(); - CommitTransactionCommand(); - } temp->next = NULL; if (prev == NULL) diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdstypeio.c b/contrib/babelfishpg_tds/src/backend/tds/tdstypeio.c index f84e7144ff..731249ae75 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tdstypeio.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tdstypeio.c @@ -120,6 +120,8 @@ Datum TdsTypeXMLToDatum(StringInfo buf); Datum TdsTypeUIDToDatum(StringInfo buf); Datum TdsTypeSqlVariantToDatum(StringInfo buf); +static void FetchTvpTypeOid(const ParameterToken token, char *tvpName); + /* Local structures for the Function Cache by TDS Type ID */ typedef struct FunctionCacheByTdsIdKey { @@ -1983,6 +1985,53 @@ TdsRecvTypeNumeric(const char *message, const ParameterToken token) PG_RETURN_NUMERIC(res); } +/* + * FetchTvpTypeOid - Fetches the table type to store in + * ParameterToken->TdsColumnMetaData which is later used to declare + * the bind varaibles. + * The caller should be in a Transaction and in PSQL dialect. + */ +static void +FetchTvpTypeOid(const ParameterToken token, char *tvpName) +{ + int rc; + HeapTuple row; + bool isnull; + TupleDesc tupdesc; + char *query; + + if ((rc = SPI_connect()) < 0) + { + /* Reset dialect. */ + set_config_option("babelfishpg_tsql.sql_dialect", "tsql", + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + elog(ERROR, "SPI_connect() failed in TDS Listener " + "with return code %d", rc); + } + + query = psprintf("SELECT '%s'::regtype::oid", tvpName); + + rc = SPI_execute(query, false, 1); + if(rc != SPI_OK_SELECT) + { + /* Reset dialect. */ + set_config_option("babelfishpg_tsql.sql_dialect", "tsql", + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + elog(ERROR, "Failed to insert in the underlying table for table-valued parameter: %d", rc); + } + tupdesc = SPI_tuptable->tupdesc; + row = SPI_tuptable->vals[0]; + + token->paramMeta.pgTypeOid = DatumGetObjectId(SPI_getbinval(row, tupdesc, + 1, &isnull)); + + pfree(query); + SPI_finish(); +} + + /* -------------------------------- * TdsRecvTypeTable - creates a temp-table from the data being recevied on the wire * and sends this temp-table's name to the engine. @@ -1991,22 +2040,54 @@ TdsRecvTypeNumeric(const char *message, const ParameterToken token) Datum TdsRecvTypeTable(const char *message, const ParameterToken token) { - char * tableName; - char * query; + char *tableName; + char *query; StringInfo temp; int rc; TvpRowData *row = token->tvpInfo->rowData; TvpColMetaData *colMetaData = token->tvpInfo->colMetaData; bool xactStarted = IsTransactionOrTransactionBlock(); char *finalTableName; + char *tvpTypeName; TvpLookupItem *item; temp = palloc(sizeof(StringInfoData)); initStringInfo(temp); TDSInstrumentation(INSTR_TDS_DATATYPE_TABLE_VALUED_PARAMETER); + tvpTypeName = downcase_truncate_identifier(token->tvpInfo->tvpTypeName, + strlen(token->tvpInfo->tvpTypeName), true); + + /* + * If schema is provided we convert it to physical schema + * and then update the tvpTypeName to have 2 part names. + */ + if (token->tvpInfo->tvpTypeSchemaName) + { + char *db_name = pltsql_plugin_handler_ptr->get_cur_db_name(); + char *logical_schema = downcase_truncate_identifier(token->tvpInfo->tvpTypeSchemaName, + strlen(token->tvpInfo->tvpTypeSchemaName), true); + char *physical_schema = pltsql_plugin_handler_ptr->get_physical_schema_name(db_name, logical_schema); + char *tempStr = psprintf("%s.%s", physical_schema, tvpTypeName); + + pfree(tvpTypeName); + tvpTypeName = tempStr; + + pfree(logical_schema); + pfree(physical_schema); + pfree(db_name); + } + /* Setting a unique name for TVP temp table. */ tableName = psprintf("%s_TDS_TVP_TEMP_TABLE_%d", token->tvpInfo->tableName, rand()); + finalTableName = downcase_truncate_identifier(tableName, strlen(tableName), true); + pfree(tableName); + + /* Connect to the SPI manager. */ + if ((rc = SPI_connect()) < 0) + elog(ERROR, "SPI_connect() failed in TDS Listener " + "with return code %d", rc); + /* * We change the dialect to postgres to create temp tables @@ -2016,19 +2097,17 @@ TdsRecvTypeTable(const char *message, const ParameterToken token) (superuser() ? PGC_SUSET : PGC_USERSET), PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); - /* Connect to the SPI manager. */ - if ((rc = SPI_connect()) < 0) - elog(ERROR, "SPI_connect() failed in TDS Listener " - "with return code %d", rc); - if (!xactStarted) StartTransactionCommand(); PushActiveSnapshot(GetTransactionSnapshot()); - + /* Explicity retrieve the oid for TVP type and map it. */ + if (token->paramMeta.pgTypeOid == InvalidOid) + FetchTvpTypeOid(token, tvpTypeName); query = psprintf("CREATE TEMPORARY TABLE IF NOT EXISTS %s (like %s including all)", - tableName, token->tvpInfo->tvpTypeName); + finalTableName, tvpTypeName); + pfree(tvpTypeName); /* @@ -2038,7 +2117,13 @@ TdsRecvTypeTable(const char *message, const ParameterToken token) rc = SPI_execute(query, false, 1); if (rc != SPI_OK_UTILITY) + { + /* Reset dialect. */ + set_config_option("babelfishpg_tsql.sql_dialect", "tsql", + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); elog(ERROR, "Failed to create the underlying table for table-valued parameter: %d", rc); + } SPI_finish(); PopActiveSnapshot(); @@ -2151,10 +2236,16 @@ TdsRecvTypeTable(const char *message, const ParameterToken token) { query[1] = ' '; /* Convert the first ',' into a blank space. */ - src = psprintf("Insert into %s values %s", tableName, query); + src = psprintf("Insert into %s values %s", finalTableName, query); if ((rc = SPI_connect()) < 0) + { + /* Reset dialect. */ + set_config_option("babelfishpg_tsql.sql_dialect", "tsql", + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); elog(ERROR, "SPI_connect() failed in TDS Listener " "with return code %d", rc); + } rc = SPI_execute_with_args(src, nargs, argtypes, @@ -2162,7 +2253,13 @@ TdsRecvTypeTable(const char *message, const ParameterToken token) false, 1); if (rc != SPI_OK_INSERT) + { + /* Reset dialect. */ + set_config_option("babelfishpg_tsql.sql_dialect", "tsql", + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); elog(ERROR, "Failed to insert in the underlying table for table-valued parameter: %d", rc); + } SPI_finish(); PopActiveSnapshot(); @@ -2184,8 +2281,6 @@ TdsRecvTypeTable(const char *message, const ParameterToken token) } pfree(token->tvpInfo->colMetaData); - finalTableName = downcase_truncate_identifier(tableName, strlen(tableName), true); - item = (TvpLookupItem *) palloc(sizeof(TvpLookupItem)); item->name = downcase_truncate_identifier(token->paramMeta.colName.data, strlen(token->paramMeta.colName.data), diff --git a/contrib/babelfishpg_tds/src/include/tds_request.h b/contrib/babelfishpg_tds/src/include/tds_request.h index 48aa1f7179..ed05bf06db 100644 --- a/contrib/babelfishpg_tds/src/include/tds_request.h +++ b/contrib/babelfishpg_tds/src/include/tds_request.h @@ -477,8 +477,6 @@ SetColMetadataForTvp(ParameterToken temp,const StringInfo message, uint64_t *off char *tempString; int i = 0; char *messageData = message->data; - char *db_name = pltsql_plugin_handler_ptr->get_cur_db_name(); - char *physical_schema = NULL; StringInfo tempStringInfo = palloc( sizeof(StringInfoData)); uint32_t collation; @@ -505,16 +503,9 @@ SetColMetadataForTvp(ParameterToken temp,const StringInfo message, uint64_t *off *offset += len * 2; temp->len += len; - - if(i==1) - physical_schema = pltsql_plugin_handler_ptr->get_physical_schema_name(db_name,tempStringInfo->data); - /* if schema name is specified */ - else if(physical_schema) - { - temp->tvpInfo->tvpTypeName = psprintf("%s.%s", physical_schema, tempStringInfo->data); - pfree(physical_schema); - } - /* if schema name not specified */ + + if(i == 1) + temp->tvpInfo->tvpTypeSchemaName = tempStringInfo->data; else temp->tvpInfo->tvpTypeName = tempStringInfo->data; @@ -529,7 +520,6 @@ SetColMetadataForTvp(ParameterToken temp,const StringInfo message, uint64_t *off temp->paramOrdinal + 1))); } } - pfree(db_name); temp->tvpInfo->tableName = tempStringInfo->data; i = 0; diff --git a/contrib/babelfishpg_tds/src/include/tds_typeio.h b/contrib/babelfishpg_tds/src/include/tds_typeio.h index ae39974f05..1a25e2487d 100644 --- a/contrib/babelfishpg_tds/src/include/tds_typeio.h +++ b/contrib/babelfishpg_tds/src/include/tds_typeio.h @@ -222,6 +222,7 @@ typedef struct TvpRowData typedef struct TvpData { char *tvpTypeName; + char *tvpTypeSchemaName; char *tableName; int colCount; int rowCount; diff --git a/test/dotnet/ExpectedOutput/TestTvp.out b/test/dotnet/ExpectedOutput/TestTvp.out index 99fa2bbb70..4884995318 100644 --- a/test/dotnet/ExpectedOutput/TestTvp.out +++ b/test/dotnet/ExpectedOutput/TestTvp.out @@ -10,3 +10,25 @@ 1#!#1#!#1#!#1#!#True#!#hi #!#hi #!#hi#!#hi#!#4949#!#494900000000#!#10/10/2022 00:00:00#!#10/10/2022 10:10:10#!#143.5000#!#ce8af10a-2709-43b0-9e4e-a02753929d17#!#12.11#!#13.11#!#1.330#!#45.122#!#10:10:10#!#10/10/2022 10:10:10 #Q#drop type testtvp.tableType #Q#drop schema testtvp +#Q#create type this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong as table (a int, b smallint, c bigint, d tinyint, e bit, f char(10), g nchar(10), h varchar(10), i nvarchar(10), l varbinary(10), m binary(10), n date, o datetime, p money, q uniqueidentifier,r float, s real, t numeric(4,3), u decimal(5,3), v time(5), w datetime2(5)) +#Q#Select * from @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong +#D#int#!#smallint#!#bigint#!#tinyint#!#bit#!#char#!#nchar#!#varchar#!#nvarchar#!#varbinary#!#binary#!#date#!#datetime#!#money#!#uniqueidentifier#!#float#!#real#!#decimal#!#decimal#!#time#!#datetime2 +1#!#1#!#1#!#1#!#True#!#hi #!#hi #!#hi#!#hi#!#4949#!#494900000000#!#10/10/2022 00:00:00#!#10/10/2022 10:10:10#!#143.5000#!#ce8af10a-2709-43b0-9e4e-a02753929d17#!#12.11#!#13.11#!#1.330#!#45.122#!#10:10:10#!#10/10/2022 10:10:10 +#Q#drop type this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong +#Q#Create table tvp_table(a int, b smallint, c bigint, d tinyint, e bit, f char(10), g nchar(10), h varchar(10), i nvarchar(10), l varbinary(10), m binary(10), n date, o datetime, p money, q uniqueidentifier,r float, s real, t numeric(4,3), u decimal(5,3), v time(5), w datetime2(5)) +#Q#create type this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong as table (a int, b smallint, c bigint, d tinyint, e bit, f char(10), g nchar(10), h varchar(10), i nvarchar(10), l varbinary(10), m binary(10), n date, o datetime, p money, q uniqueidentifier,r float, s real, t numeric(4,3), u decimal(5,3), v time(5), w datetime2(5)) +#Q#create procedure tvp_proc @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong as this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong READONLY AS BEGIN insert into tvp_table select * from @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong END +#Q#tvp_proc +#Q#Select * from tvp_table +#D#int#!#smallint#!#bigint#!#tinyint#!#bit#!#char#!#nchar#!#varchar#!#nvarchar#!#varbinary#!#binary#!#date#!#datetime#!#money#!#uniqueidentifier#!#float#!#real#!#decimal#!#decimal#!#time#!#datetime2 +1#!#1#!#1#!#1#!#True#!#hi #!#hi #!#hi#!#hi#!#4949#!#494900000000#!#10/10/2022 00:00:00#!#10/10/2022 10:10:10#!#143.5000#!#ce8af10a-2709-43b0-9e4e-a02753929d17#!#12.11#!#13.11#!#1.330#!#45.122#!#10:10:10#!#10/10/2022 10:10:10 +#Q#drop procedure tvp_proc +#Q#drop table tvp_table +#Q#drop type this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong +#Q#create schema this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong +#Q#create type this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong as table (a int, b smallint, c bigint, d tinyint, e bit, f char(10), g nchar(10), h varchar(10), i nvarchar(10), l varbinary(10), m binary(10), n date, o datetime, p money, q uniqueidentifier,r float, s real, t numeric(4,3), u decimal(5,3), v time(5), w datetime2(5)) +#Q#Select * from @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong +#D#int#!#smallint#!#bigint#!#tinyint#!#bit#!#char#!#nchar#!#varchar#!#nvarchar#!#varbinary#!#binary#!#date#!#datetime#!#money#!#uniqueidentifier#!#float#!#real#!#decimal#!#decimal#!#time#!#datetime2 +1#!#1#!#1#!#1#!#True#!#hi #!#hi #!#hi#!#hi#!#4949#!#494900000000#!#10/10/2022 00:00:00#!#10/10/2022 10:10:10#!#143.5000#!#ce8af10a-2709-43b0-9e4e-a02753929d17#!#12.11#!#13.11#!#1.330#!#45.122#!#10:10:10#!#10/10/2022 10:10:10 +#Q#drop type this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong +#Q#drop schema this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong diff --git a/test/dotnet/input/Datatypes/TestTvp.txt b/test/dotnet/input/Datatypes/TestTvp.txt index 3792df8448..01bc74f8a8 100644 --- a/test/dotnet/input/Datatypes/TestTvp.txt +++ b/test/dotnet/input/Datatypes/TestTvp.txt @@ -9,3 +9,25 @@ create type testtvp.tableType as table (a int, b smallint, c bigint, d tinyint, prepst#!#Select * from @a #!#tvp|-|a|-|testtvp.tableType|-|../../../utils/tvp-dotnet.csv drop type testtvp.tableType drop schema testtvp + +#test tvp with huge type name and parameter name +create type this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong as table (a int, b smallint, c bigint, d tinyint, e bit, f char(10), g nchar(10), h varchar(10), i nvarchar(10), l varbinary(10), m binary(10), n date, o datetime, p money, q uniqueidentifier,r float, s real, t numeric(4,3), u decimal(5,3), v time(5), w datetime2(5)) +prepst#!#Select * from @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong#!#tvp|-|this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong|-|this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong|-|../../../utils/tvp-dotnet.csv +drop type this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong + +#test tvp with huge type name and parameter name but this time executing a stored proc using SP CUSTOMTYPE +Create table tvp_table(a int, b smallint, c bigint, d tinyint, e bit, f char(10), g nchar(10), h varchar(10), i nvarchar(10), l varbinary(10), m binary(10), n date, o datetime, p money, q uniqueidentifier,r float, s real, t numeric(4,3), u decimal(5,3), v time(5), w datetime2(5)) +create type this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong as table (a int, b smallint, c bigint, d tinyint, e bit, f char(10), g nchar(10), h varchar(10), i nvarchar(10), l varbinary(10), m binary(10), n date, o datetime, p money, q uniqueidentifier,r float, s real, t numeric(4,3), u decimal(5,3), v time(5), w datetime2(5)) +create procedure tvp_proc @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong as this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong READONLY AS BEGIN insert into tvp_table select * from @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong END +storedproc#!#prep#!#tvp_proc#!#tvp|-|this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong|-|this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong|-|../../../utils/tvp-dotnet.csv +Select * from tvp_table +drop procedure tvp_proc +drop table tvp_table +drop type this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong + +#testt tvp with huge type name and parameter name and huge schema name +create schema this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong +create type this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong as table (a int, b smallint, c bigint, d tinyint, e bit, f char(10), g nchar(10), h varchar(10), i nvarchar(10), l varbinary(10), m binary(10), n date, o datetime, p money, q uniqueidentifier,r float, s real, t numeric(4,3), u decimal(5,3), v time(5), w datetime2(5)) +prepst#!#Select * from @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong#!#tvp|-|this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong|-|this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong|-|../../../utils/tvp-dotnet.csv +drop type this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong +drop schema this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong \ No newline at end of file From 7df165fa7374d6472302282356d5a38dfe06bb8a Mon Sep 17 00:00:00 2001 From: Satarupa Biswas Date: Fri, 17 Mar 2023 22:06:10 +0530 Subject: [PATCH 020/363] DATEADD() gives wrong output with DATETIMEOFFSET (#1340) Postgres outputs datetimeoffset data by removing/subtracting input timezone value from it. Fix includes, working on the engine output to include timezone and thereby retain the input timestamp as is. Task: BABEL-1625 Signed-off-by: Satarupa Biswas Co-authored-by: Satarupa Biswas --- .../babelfishpg_tsql/sql/sys_functions.sql | 4 + .../babelfishpg_tsql--3.1.0--3.2.0.sql | 48 +++++ test/JDBC/expected/BABEL-1625-vu-prepare.out | 96 +++++++++ test/JDBC/expected/BABEL-1625-vu-verify.out | 189 ++++++++++++++++++ test/JDBC/expected/BABEL-3474-vu-verify.out | 8 +- .../dateadd_internal_df-vu-verify.out | 8 +- test/JDBC/input/BABEL-1625-vu-prepare.sql | 96 +++++++++ test/JDBC/input/BABEL-1625-vu-verify.sql | 94 +++++++++ test/JDBC/upgrade/13_4/schedule | 3 +- test/JDBC/upgrade/13_5/schedule | 3 +- test/JDBC/upgrade/13_6/schedule | 3 +- test/JDBC/upgrade/13_7/schedule | 3 +- test/JDBC/upgrade/13_8/schedule | 3 +- test/JDBC/upgrade/13_9/schedule | 3 +- test/JDBC/upgrade/14_3/schedule | 3 +- test/JDBC/upgrade/14_5/schedule | 3 +- test/JDBC/upgrade/14_6/schedule | 5 +- test/JDBC/upgrade/14_7/schedule | 5 +- test/JDBC/upgrade/14_8/schedule | 5 +- test/JDBC/upgrade/15_1/schedule | 5 +- test/JDBC/upgrade/15_2/schedule | 5 +- test/JDBC/upgrade/latest/schedule | 5 +- test/JDBC/upgrade/master/schedule | 5 +- 23 files changed, 572 insertions(+), 30 deletions(-) create mode 100644 test/JDBC/expected/BABEL-1625-vu-prepare.out create mode 100644 test/JDBC/expected/BABEL-1625-vu-verify.out create mode 100644 test/JDBC/input/BABEL-1625-vu-prepare.sql create mode 100644 test/JDBC/input/BABEL-1625-vu-verify.sql diff --git a/contrib/babelfishpg_tsql/sql/sys_functions.sql b/contrib/babelfishpg_tsql/sql/sys_functions.sql index 1a57c6e90f..4a8e31697f 100644 --- a/contrib/babelfishpg_tsql/sql/sys_functions.sql +++ b/contrib/babelfishpg_tsql/sql/sys_functions.sql @@ -1222,7 +1222,11 @@ LANGUAGE plpgsql IMMUTABLE; but should keep using OPERATOR(sys.+) when input date is in datetimeoffset type. */ CREATE OR REPLACE FUNCTION sys.dateadd_internal_df(IN datepart PG_CATALOG.TEXT, IN num INTEGER, IN startdate datetimeoffset) RETURNS datetimeoffset AS $$ +DECLARE + timezone INTEGER; BEGIN + timezone = sys.babelfish_get_datetimeoffset_tzoffset(startdate)::INTEGER * 2; + startdate = startdate OPERATOR(sys.+) make_interval(mins => timezone); CASE datepart WHEN 'year' THEN RETURN startdate OPERATOR(sys.+) make_interval(years => num); diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql index ec6ee7a571..85d07090ab 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql @@ -586,6 +586,54 @@ END; $BODY$ LANGUAGE plpgsql STABLE; +/* + This function is needed when input date is datetimeoffset type. When running the following query in postgres using tsql dialect, it failed. + select dateadd(minute, -70, '2016-12-26 00:30:05.523456+8'::datetimeoffset); + We tried to merge this function with sys.dateadd_internal by using '+' when adding interval to datetimeoffset, + but the error shows : operator does not exist: sys.datetimeoffset + interval. As the result, we should not use '+' directly + but should keep using OPERATOR(sys.+) when input date is in datetimeoffset type. +*/ +CREATE OR REPLACE FUNCTION sys.dateadd_internal_df(IN datepart PG_CATALOG.TEXT, IN num INTEGER, IN startdate datetimeoffset) RETURNS datetimeoffset AS $$ +DECLARE + timezone INTEGER; +BEGIN + timezone = sys.babelfish_get_datetimeoffset_tzoffset(startdate)::INTEGER * 2; + startdate = startdate OPERATOR(sys.+) make_interval(mins => timezone); + CASE datepart + WHEN 'year' THEN + RETURN startdate OPERATOR(sys.+) make_interval(years => num); + WHEN 'quarter' THEN + RETURN startdate OPERATOR(sys.+) make_interval(months => num * 3); + WHEN 'month' THEN + RETURN startdate OPERATOR(sys.+) make_interval(months => num); + WHEN 'dayofyear', 'y' THEN + RETURN startdate OPERATOR(sys.+) make_interval(days => num); + WHEN 'day' THEN + RETURN startdate OPERATOR(sys.+) make_interval(days => num); + WHEN 'week' THEN + RETURN startdate OPERATOR(sys.+) make_interval(weeks => num); + WHEN 'weekday' THEN + RETURN startdate OPERATOR(sys.+) make_interval(days => num); + WHEN 'hour' THEN + RETURN startdate OPERATOR(sys.+) make_interval(hours => num); + WHEN 'minute' THEN + RETURN startdate OPERATOR(sys.+) make_interval(mins => num); + WHEN 'second' THEN + RETURN startdate OPERATOR(sys.+) make_interval(secs => num); + WHEN 'millisecond' THEN + RETURN startdate OPERATOR(sys.+) make_interval(secs => (num::numeric) * 0.001); + WHEN 'microsecond' THEN + RETURN startdate OPERATOR(sys.+) make_interval(secs => (num::numeric) * 0.000001); + WHEN 'nanosecond' THEN + -- Best we can do - Postgres does not support nanosecond precision + RETURN startdate OPERATOR(sys.+) make_interval(secs => TRUNC((num::numeric)* 0.000000001, 6)); + ELSE + RAISE EXCEPTION '"%" is not a recognized dateadd option.', datepart; + END CASE; +END; +$$ +STRICT +LANGUAGE plpgsql IMMUTABLE; -- Drops the temporary procedure used by the upgrade script. -- Please have this be one of the last statements executed in this upgrade script. diff --git a/test/JDBC/expected/BABEL-1625-vu-prepare.out b/test/JDBC/expected/BABEL-1625-vu-prepare.out new file mode 100644 index 0000000000..6d0b105ab2 --- /dev/null +++ b/test/JDBC/expected/BABEL-1625-vu-prepare.out @@ -0,0 +1,96 @@ +-- [BABEL-1625] expected value = 1912-11-25 12:24:32.0000000 +10:00 +-- expected value = 1912-11-25 12:24:32.0000000 +10:00 +CREATE VIEW BABEL_1625_vu_prepare_v1 AS (SELECT DATEADD(month, 1, cast('1912-10-25 12:24:32 +10:0' as DATETIMEOFFSET))); +GO + +-- expected value = 1914-10-25 12:24:32.0000000 -10:52 +CREATE VIEW BABEL_1625_vu_prepare_v2 AS (SELECT DATEADD(year, 2, cast('1912-10-25 12:24:32 -10:52' as DATETIMEOFFSET))); +GO + +-- expected value = 1912-10-28 12:24:32.0000000 +06:45 +CREATE VIEW BABEL_1625_vu_prepare_v3 AS (SELECT DATEADD(day, 3, cast('1912-10-25 12:24:32 +06:45' as DATETIMEOFFSET))); +GO + +-- expected value = 1912-10-25 16:24:32.0000000 -11:37 +CREATE VIEW BABEL_1625_vu_prepare_v4 AS (SELECT DATEADD(hour, 4, cast('1912-10-25 12:24:32 -11:37' as DATETIMEOFFSET))); +GO + +-- expected value = 1912-10-25 12:29:32.0000000 +04:44 +CREATE VIEW BABEL_1625_vu_prepare_v5 AS (SELECT DATEADD(minute, 5, cast('1912-10-25 12:24:32 +04:44' as DATETIMEOFFSET))); +GO + +-- expected value = 1912-10-25 12:24:38.0000000 -02:23 +CREATE VIEW BABEL_1625_vu_prepare_v6 AS (SELECT DATEADD(second, 6, cast('1912-10-25 12:24:32 -02:23' as DATETIMEOFFSET))); +GO + +-- expected value = 2001-02-28 12:24:32.0000000 +10:00 +CREATE PROCEDURE BABEL_1625_vu_prepare_p1 AS (SELECT DATEADD(year, 1, cast('2000-02-28 12:24:32 +10:0' as DATETIMEOFFSET))); +GO + +-- expected value = 2000-03-28 12:24:32.0000000 +10:00 +CREATE PROCEDURE BABEL_1625_vu_prepare_p2 AS (SELECT DATEADD(month, 1, cast('2000-02-28 12:24:32 +10:0' as DATETIMEOFFSET))); +GO + +-- expected value = 2000-02-29 12:24:32.0000000 +10:00 +CREATE PROCEDURE BABEL_1625_vu_prepare_p3 AS (SELECT DATEADD(day, 1, cast('2000-02-28 12:24:32 +10:0' as DATETIMEOFFSET))); +GO + +-- expected value = 2000-02-28 13:24:32.0000000 +10:00 +CREATE PROCEDURE BABEL_1625_vu_prepare_p4 AS (SELECT DATEADD(hour, 1, cast('2000-02-28 12:24:32 +10:0' as DATETIMEOFFSET))); +GO + +-- expected value = 2000-02-28 12:25:32.0000000 +10:00 +CREATE PROCEDURE BABEL_1625_vu_prepare_p5 AS (SELECT DATEADD(minute, 1, cast('2000-02-28 12:24:32 +10:0' as DATETIMEOFFSET))); +GO + +-- expected value = 2000-02-28 12:24:33.0000000 +10:00 +CREATE PROCEDURE BABEL_1625_vu_prepare_p6 AS (SELECT DATEADD(second, 1, cast('2000-02-28 12:24:32 +10:0' as DATETIMEOFFSET))); +GO + +-- expected value = 1919-10-25 17:56:28.0000000 +11:59 +CREATE FUNCTION BABEL_1625_vu_prepare_f1() +RETURNS DATETIMEOFFSET AS +BEGIN +RETURN (SELECT DATEADD(year, 7, cast('1912-10-25 17:56:28 +11:59' as DATETIMEOFFSET))); +END +GO + +-- expected value = 1913-05-25 17:56:28.0000000 +11:59 +CREATE FUNCTION BABEL_1625_vu_prepare_f2() +RETURNS DATETIMEOFFSET AS +BEGIN +RETURN (SELECT DATEADD(month, 7, cast('1912-10-25 17:56:28 +11:59' as DATETIMEOFFSET))); +END +GO + +-- expected value = 1912-11-01 17:56:28.0000000 +11:59 +CREATE FUNCTION BABEL_1625_vu_prepare_f3() +RETURNS DATETIMEOFFSET AS +BEGIN +RETURN (SELECT DATEADD(day, 7, cast('1912-10-25 17:56:28 +11:59' as DATETIMEOFFSET))); +END +GO + +-- expected value = 1912-10-26 00:56:28.0000000 +11:59 +CREATE FUNCTION BABEL_1625_vu_prepare_f4() +RETURNS DATETIMEOFFSET AS +BEGIN +RETURN (SELECT DATEADD(hour, 7, cast('1912-10-25 17:56:28 +11:59' as DATETIMEOFFSET))); +END +GO + +-- expected value = 1912-10-25 18:03:28.0000000 +11:59 +CREATE FUNCTION BABEL_1625_vu_prepare_f5() +RETURNS DATETIMEOFFSET AS +BEGIN +RETURN (SELECT DATEADD(minute, 7, cast('1912-10-25 17:56:28 +11:59' as DATETIMEOFFSET))); +END +GO + +-- expected value = 1912-10-25 17:56:35.0000000 +11:59 +CREATE FUNCTION BABEL_1625_vu_prepare_f6() +RETURNS DATETIMEOFFSET AS +BEGIN +RETURN (SELECT DATEADD(second, 7, cast('1912-10-25 17:56:28 +11:59' as DATETIMEOFFSET))); +END +GO diff --git a/test/JDBC/expected/BABEL-1625-vu-verify.out b/test/JDBC/expected/BABEL-1625-vu-verify.out new file mode 100644 index 0000000000..990297421c --- /dev/null +++ b/test/JDBC/expected/BABEL-1625-vu-verify.out @@ -0,0 +1,189 @@ +declare @dt datetimeoffset(6); +set @dt = '1912-10-25 12:24:32 +10:0'; +select dateadd(month,1,@dt); +GO +~~START~~ +datetimeoffset +1912-11-25 12:24:32.0000000 +10:00 +~~END~~ + + +SELECT * FROM BABEL_1625_vu_prepare_v1 +GO +~~START~~ +datetimeoffset +1912-11-25 12:24:32.0000000 +10:00 +~~END~~ + +DROP VIEW BABEL_1625_vu_prepare_v1 +GO + +SELECT * FROM BABEL_1625_vu_prepare_v2 +GO +~~START~~ +datetimeoffset +1914-10-25 12:24:32.0000000 -10:52 +~~END~~ + +DROP VIEW BABEL_1625_vu_prepare_v2 +GO + +SELECT * FROM BABEL_1625_vu_prepare_v3 +GO +~~START~~ +datetimeoffset +1912-10-28 12:24:32.0000000 +06:45 +~~END~~ + +DROP VIEW BABEL_1625_vu_prepare_v3 +GO + +SELECT * FROM BABEL_1625_vu_prepare_v4 +GO +~~START~~ +datetimeoffset +1912-10-25 16:24:32.0000000 -11:37 +~~END~~ + +DROP VIEW BABEL_1625_vu_prepare_v4 +GO + +SELECT * FROM BABEL_1625_vu_prepare_v5 +GO +~~START~~ +datetimeoffset +1912-10-25 12:29:32.0000000 +04:44 +~~END~~ + +DROP VIEW BABEL_1625_vu_prepare_v5 +GO + +SELECT * FROM BABEL_1625_vu_prepare_v6 +GO +~~START~~ +datetimeoffset +1912-10-25 12:24:38.0000000 -02:23 +~~END~~ + +DROP VIEW BABEL_1625_vu_prepare_v6 +GO + +EXEC BABEL_1625_vu_prepare_p1 +GO +~~START~~ +datetimeoffset +2001-02-28 12:24:32.0000000 +10:00 +~~END~~ + +DROP procedure BABEL_1625_vu_prepare_p1 +GO + +EXEC BABEL_1625_vu_prepare_p2 +GO +~~START~~ +datetimeoffset +2000-03-28 12:24:32.0000000 +10:00 +~~END~~ + +DROP procedure BABEL_1625_vu_prepare_p2 +GO + +EXEC BABEL_1625_vu_prepare_p3 +GO +~~START~~ +datetimeoffset +2000-02-29 12:24:32.0000000 +10:00 +~~END~~ + +DROP procedure BABEL_1625_vu_prepare_p3 +GO + +EXEC BABEL_1625_vu_prepare_p4 +GO +~~START~~ +datetimeoffset +2000-02-28 13:24:32.0000000 +10:00 +~~END~~ + +DROP procedure BABEL_1625_vu_prepare_p4 +GO + +EXEC BABEL_1625_vu_prepare_p5 +GO +~~START~~ +datetimeoffset +2000-02-28 12:25:32.0000000 +10:00 +~~END~~ + +DROP procedure BABEL_1625_vu_prepare_p5 +GO + +EXEC BABEL_1625_vu_prepare_p6 +GO +~~START~~ +datetimeoffset +2000-02-28 12:24:33.0000000 +10:00 +~~END~~ + +DROP procedure BABEL_1625_vu_prepare_p6 +GO + +SELECT BABEL_1625_vu_prepare_f1() +GO +~~START~~ +datetimeoffset +1919-10-25 17:56:28.0000000 +11:59 +~~END~~ + +DROP FUNCTION BABEL_1625_vu_prepare_f1() +GO + +SELECT BABEL_1625_vu_prepare_f2() +GO +~~START~~ +datetimeoffset +1913-05-25 17:56:28.0000000 +11:59 +~~END~~ + +DROP FUNCTION BABEL_1625_vu_prepare_f2() +GO + +SELECT BABEL_1625_vu_prepare_f3() +GO +~~START~~ +datetimeoffset +1912-11-01 17:56:28.0000000 +11:59 +~~END~~ + +DROP FUNCTION BABEL_1625_vu_prepare_f3() +GO + +SELECT BABEL_1625_vu_prepare_f4() +GO +~~START~~ +datetimeoffset +1912-10-26 00:56:28.0000000 +11:59 +~~END~~ + +DROP FUNCTION BABEL_1625_vu_prepare_f4() +GO + +SELECT BABEL_1625_vu_prepare_f5() +GO +~~START~~ +datetimeoffset +1912-10-25 18:03:28.0000000 +11:59 +~~END~~ + +DROP FUNCTION BABEL_1625_vu_prepare_f5() +GO + +SELECT BABEL_1625_vu_prepare_f6() +GO +~~START~~ +datetimeoffset +1912-10-25 17:56:35.0000000 +11:59 +~~END~~ + +DROP FUNCTION BABEL_1625_vu_prepare_f6() +GO diff --git a/test/JDBC/expected/BABEL-3474-vu-verify.out b/test/JDBC/expected/BABEL-3474-vu-verify.out index 7909190f81..0d3ed8025a 100644 --- a/test/JDBC/expected/BABEL-3474-vu-verify.out +++ b/test/JDBC/expected/BABEL-3474-vu-verify.out @@ -116,7 +116,7 @@ SELECT * FROM BABEL_3474_vu_prepare_v13 GO ~~START~~ datetimeoffset -2016-12-26 16:40:05.5234560 +08:00 +2016-12-27 00:40:05.5234560 +08:00 ~~END~~ DROP VIEW BABEL_3474_vu_prepare_v13 @@ -126,7 +126,7 @@ SELECT * FROM BABEL_3474_vu_prepare_v14 GO ~~START~~ datetimeoffset -2017-02-26 15:30:05.5234560 +08:00 +2017-02-26 23:30:05.5234560 +08:00 ~~END~~ DROP VIEW BABEL_3474_vu_prepare_v14 @@ -250,7 +250,7 @@ EXEC BABEL_3474_vu_prepare_p13 GO ~~START~~ datetimeoffset -2016-12-26 16:40:05.5234560 +08:00 +2016-12-27 00:40:05.5234560 +08:00 ~~END~~ DROP procedure BABEL_3474_vu_prepare_p13 @@ -260,7 +260,7 @@ EXEC BABEL_3474_vu_prepare_p14 GO ~~START~~ datetimeoffset -2017-02-26 15:30:05.5234560 +08:00 +2017-02-26 23:30:05.5234560 +08:00 ~~END~~ DROP procedure BABEL_3474_vu_prepare_p14 diff --git a/test/JDBC/expected/dateadd_internal_df-vu-verify.out b/test/JDBC/expected/dateadd_internal_df-vu-verify.out index 14f5699d83..5c9d5122c6 100644 --- a/test/JDBC/expected/dateadd_internal_df-vu-verify.out +++ b/test/JDBC/expected/dateadd_internal_df-vu-verify.out @@ -2,7 +2,7 @@ SELECT SYS.dateadd_internal_df('minute', -70, cast('2016-12-26 00:30:05.523456+8 GO ~~START~~ datetimeoffset -2016-12-25 15:20:05.5234560 +08:00 +2016-12-25 23:20:05.5234560 +08:00 ~~END~~ @@ -10,7 +10,7 @@ SELECT * FROM dateadd_internal_df_view_vu_prepare GO ~~START~~ datetimeoffset -2016-12-25 15:20:05.5234560 +08:00 +2016-12-25 23:20:05.5234560 +08:00 ~~END~~ @@ -18,7 +18,7 @@ EXEC dateadd_internal_df_proc_vu_prepare GO ~~START~~ datetimeoffset -2016-12-25 15:20:05.5234560 +08:00 +2016-12-25 23:20:05.5234560 +08:00 ~~END~~ @@ -26,7 +26,7 @@ SELECT dateadd_internal_df_func_vu_prepare() GO ~~START~~ datetimeoffset -2016-12-25 15:20:05.5234560 +08:00 +2016-12-25 23:20:05.5234560 +08:00 ~~END~~ diff --git a/test/JDBC/input/BABEL-1625-vu-prepare.sql b/test/JDBC/input/BABEL-1625-vu-prepare.sql new file mode 100644 index 0000000000..6d0b105ab2 --- /dev/null +++ b/test/JDBC/input/BABEL-1625-vu-prepare.sql @@ -0,0 +1,96 @@ +-- [BABEL-1625] expected value = 1912-11-25 12:24:32.0000000 +10:00 +-- expected value = 1912-11-25 12:24:32.0000000 +10:00 +CREATE VIEW BABEL_1625_vu_prepare_v1 AS (SELECT DATEADD(month, 1, cast('1912-10-25 12:24:32 +10:0' as DATETIMEOFFSET))); +GO + +-- expected value = 1914-10-25 12:24:32.0000000 -10:52 +CREATE VIEW BABEL_1625_vu_prepare_v2 AS (SELECT DATEADD(year, 2, cast('1912-10-25 12:24:32 -10:52' as DATETIMEOFFSET))); +GO + +-- expected value = 1912-10-28 12:24:32.0000000 +06:45 +CREATE VIEW BABEL_1625_vu_prepare_v3 AS (SELECT DATEADD(day, 3, cast('1912-10-25 12:24:32 +06:45' as DATETIMEOFFSET))); +GO + +-- expected value = 1912-10-25 16:24:32.0000000 -11:37 +CREATE VIEW BABEL_1625_vu_prepare_v4 AS (SELECT DATEADD(hour, 4, cast('1912-10-25 12:24:32 -11:37' as DATETIMEOFFSET))); +GO + +-- expected value = 1912-10-25 12:29:32.0000000 +04:44 +CREATE VIEW BABEL_1625_vu_prepare_v5 AS (SELECT DATEADD(minute, 5, cast('1912-10-25 12:24:32 +04:44' as DATETIMEOFFSET))); +GO + +-- expected value = 1912-10-25 12:24:38.0000000 -02:23 +CREATE VIEW BABEL_1625_vu_prepare_v6 AS (SELECT DATEADD(second, 6, cast('1912-10-25 12:24:32 -02:23' as DATETIMEOFFSET))); +GO + +-- expected value = 2001-02-28 12:24:32.0000000 +10:00 +CREATE PROCEDURE BABEL_1625_vu_prepare_p1 AS (SELECT DATEADD(year, 1, cast('2000-02-28 12:24:32 +10:0' as DATETIMEOFFSET))); +GO + +-- expected value = 2000-03-28 12:24:32.0000000 +10:00 +CREATE PROCEDURE BABEL_1625_vu_prepare_p2 AS (SELECT DATEADD(month, 1, cast('2000-02-28 12:24:32 +10:0' as DATETIMEOFFSET))); +GO + +-- expected value = 2000-02-29 12:24:32.0000000 +10:00 +CREATE PROCEDURE BABEL_1625_vu_prepare_p3 AS (SELECT DATEADD(day, 1, cast('2000-02-28 12:24:32 +10:0' as DATETIMEOFFSET))); +GO + +-- expected value = 2000-02-28 13:24:32.0000000 +10:00 +CREATE PROCEDURE BABEL_1625_vu_prepare_p4 AS (SELECT DATEADD(hour, 1, cast('2000-02-28 12:24:32 +10:0' as DATETIMEOFFSET))); +GO + +-- expected value = 2000-02-28 12:25:32.0000000 +10:00 +CREATE PROCEDURE BABEL_1625_vu_prepare_p5 AS (SELECT DATEADD(minute, 1, cast('2000-02-28 12:24:32 +10:0' as DATETIMEOFFSET))); +GO + +-- expected value = 2000-02-28 12:24:33.0000000 +10:00 +CREATE PROCEDURE BABEL_1625_vu_prepare_p6 AS (SELECT DATEADD(second, 1, cast('2000-02-28 12:24:32 +10:0' as DATETIMEOFFSET))); +GO + +-- expected value = 1919-10-25 17:56:28.0000000 +11:59 +CREATE FUNCTION BABEL_1625_vu_prepare_f1() +RETURNS DATETIMEOFFSET AS +BEGIN +RETURN (SELECT DATEADD(year, 7, cast('1912-10-25 17:56:28 +11:59' as DATETIMEOFFSET))); +END +GO + +-- expected value = 1913-05-25 17:56:28.0000000 +11:59 +CREATE FUNCTION BABEL_1625_vu_prepare_f2() +RETURNS DATETIMEOFFSET AS +BEGIN +RETURN (SELECT DATEADD(month, 7, cast('1912-10-25 17:56:28 +11:59' as DATETIMEOFFSET))); +END +GO + +-- expected value = 1912-11-01 17:56:28.0000000 +11:59 +CREATE FUNCTION BABEL_1625_vu_prepare_f3() +RETURNS DATETIMEOFFSET AS +BEGIN +RETURN (SELECT DATEADD(day, 7, cast('1912-10-25 17:56:28 +11:59' as DATETIMEOFFSET))); +END +GO + +-- expected value = 1912-10-26 00:56:28.0000000 +11:59 +CREATE FUNCTION BABEL_1625_vu_prepare_f4() +RETURNS DATETIMEOFFSET AS +BEGIN +RETURN (SELECT DATEADD(hour, 7, cast('1912-10-25 17:56:28 +11:59' as DATETIMEOFFSET))); +END +GO + +-- expected value = 1912-10-25 18:03:28.0000000 +11:59 +CREATE FUNCTION BABEL_1625_vu_prepare_f5() +RETURNS DATETIMEOFFSET AS +BEGIN +RETURN (SELECT DATEADD(minute, 7, cast('1912-10-25 17:56:28 +11:59' as DATETIMEOFFSET))); +END +GO + +-- expected value = 1912-10-25 17:56:35.0000000 +11:59 +CREATE FUNCTION BABEL_1625_vu_prepare_f6() +RETURNS DATETIMEOFFSET AS +BEGIN +RETURN (SELECT DATEADD(second, 7, cast('1912-10-25 17:56:28 +11:59' as DATETIMEOFFSET))); +END +GO diff --git a/test/JDBC/input/BABEL-1625-vu-verify.sql b/test/JDBC/input/BABEL-1625-vu-verify.sql new file mode 100644 index 0000000000..c1b52cb972 --- /dev/null +++ b/test/JDBC/input/BABEL-1625-vu-verify.sql @@ -0,0 +1,94 @@ +declare @dt datetimeoffset(6); +set @dt = '1912-10-25 12:24:32 +10:0'; +select dateadd(month,1,@dt); +GO + +SELECT * FROM BABEL_1625_vu_prepare_v1 +GO +DROP VIEW BABEL_1625_vu_prepare_v1 +GO + +SELECT * FROM BABEL_1625_vu_prepare_v2 +GO +DROP VIEW BABEL_1625_vu_prepare_v2 +GO + +SELECT * FROM BABEL_1625_vu_prepare_v3 +GO +DROP VIEW BABEL_1625_vu_prepare_v3 +GO + +SELECT * FROM BABEL_1625_vu_prepare_v4 +GO +DROP VIEW BABEL_1625_vu_prepare_v4 +GO + +SELECT * FROM BABEL_1625_vu_prepare_v5 +GO +DROP VIEW BABEL_1625_vu_prepare_v5 +GO + +SELECT * FROM BABEL_1625_vu_prepare_v6 +GO +DROP VIEW BABEL_1625_vu_prepare_v6 +GO + +EXEC BABEL_1625_vu_prepare_p1 +GO +DROP procedure BABEL_1625_vu_prepare_p1 +GO + +EXEC BABEL_1625_vu_prepare_p2 +GO +DROP procedure BABEL_1625_vu_prepare_p2 +GO + +EXEC BABEL_1625_vu_prepare_p3 +GO +DROP procedure BABEL_1625_vu_prepare_p3 +GO + +EXEC BABEL_1625_vu_prepare_p4 +GO +DROP procedure BABEL_1625_vu_prepare_p4 +GO + +EXEC BABEL_1625_vu_prepare_p5 +GO +DROP procedure BABEL_1625_vu_prepare_p5 +GO + +EXEC BABEL_1625_vu_prepare_p6 +GO +DROP procedure BABEL_1625_vu_prepare_p6 +GO + +SELECT BABEL_1625_vu_prepare_f1() +GO +DROP FUNCTION BABEL_1625_vu_prepare_f1() +GO + +SELECT BABEL_1625_vu_prepare_f2() +GO +DROP FUNCTION BABEL_1625_vu_prepare_f2() +GO + +SELECT BABEL_1625_vu_prepare_f3() +GO +DROP FUNCTION BABEL_1625_vu_prepare_f3() +GO + +SELECT BABEL_1625_vu_prepare_f4() +GO +DROP FUNCTION BABEL_1625_vu_prepare_f4() +GO + +SELECT BABEL_1625_vu_prepare_f5() +GO +DROP FUNCTION BABEL_1625_vu_prepare_f5() +GO + +SELECT BABEL_1625_vu_prepare_f6() +GO +DROP FUNCTION BABEL_1625_vu_prepare_f6() +GO diff --git a/test/JDBC/upgrade/13_4/schedule b/test/JDBC/upgrade/13_4/schedule index b1390a5f38..6b4c0941a8 100644 --- a/test/JDBC/upgrade/13_4/schedule +++ b/test/JDBC/upgrade/13_4/schedule @@ -87,7 +87,6 @@ BABEL-2787-2 BABEL-2845 BABEL-2884 BABEL-3249 -BABEL-3474 BABEL-3588 BABEL-PROCID babel_trigger @@ -199,3 +198,5 @@ test_windows_login_before_15_2 BABEL-3657 BABEL-3938 rowcount +BABEL-1625 +BABEL-3474 diff --git a/test/JDBC/upgrade/13_5/schedule b/test/JDBC/upgrade/13_5/schedule index 0f6f9202d7..b297bdf61e 100644 --- a/test/JDBC/upgrade/13_5/schedule +++ b/test/JDBC/upgrade/13_5/schedule @@ -134,7 +134,6 @@ BABEL-2787-2 BABEL-2845 BABEL-2884 BABEL-3249 -BABEL-3474 BABEL-3588 BABEL-PROCID babel_trigger @@ -250,3 +249,5 @@ test_windows_login_before_15_2 BABEL-3657 BABEL-3938 rowcount +BABEL-1625 +BABEL-3474 diff --git a/test/JDBC/upgrade/13_6/schedule b/test/JDBC/upgrade/13_6/schedule index 7e2f8a88f0..7ece90d9e2 100644 --- a/test/JDBC/upgrade/13_6/schedule +++ b/test/JDBC/upgrade/13_6/schedule @@ -146,7 +146,6 @@ BABEL-2944 BABEL-3116 BABEL-3118 BABEL-3249 -BABEL-3474 BABEL-3588 BABEL-383 BABEL-405 @@ -310,3 +309,5 @@ Test-sp_babelfish_volatility BABEL-3657 BABEL-3938 rowcount +BABEL-1625 +BABEL-3474 diff --git a/test/JDBC/upgrade/13_7/schedule b/test/JDBC/upgrade/13_7/schedule index cb6950ec2c..19aba12c0f 100644 --- a/test/JDBC/upgrade/13_7/schedule +++ b/test/JDBC/upgrade/13_7/schedule @@ -143,7 +143,6 @@ BABEL-2944 BABEL-3116 BABEL-3118 BABEL-3249 -BABEL-3474 BABEL-3588 BABEL-3369 BABEL-3370 @@ -305,3 +304,5 @@ BABEL_SCHEMATA BABEL-3657 BABEL-3938 rowcount +BABEL-1625 +BABEL-3474 diff --git a/test/JDBC/upgrade/13_8/schedule b/test/JDBC/upgrade/13_8/schedule index cb6950ec2c..19aba12c0f 100644 --- a/test/JDBC/upgrade/13_8/schedule +++ b/test/JDBC/upgrade/13_8/schedule @@ -143,7 +143,6 @@ BABEL-2944 BABEL-3116 BABEL-3118 BABEL-3249 -BABEL-3474 BABEL-3588 BABEL-3369 BABEL-3370 @@ -305,3 +304,5 @@ BABEL_SCHEMATA BABEL-3657 BABEL-3938 rowcount +BABEL-1625 +BABEL-3474 diff --git a/test/JDBC/upgrade/13_9/schedule b/test/JDBC/upgrade/13_9/schedule index 67b03c1082..d16ab0cf6d 100644 --- a/test/JDBC/upgrade/13_9/schedule +++ b/test/JDBC/upgrade/13_9/schedule @@ -140,7 +140,6 @@ BABEL-2944 BABEL-3116 BABEL-3118 BABEL-3249 -BABEL-3474 BABEL-3588 BABEL-3369 BABEL-3370 @@ -308,3 +307,5 @@ Test-sp_babelfish_volatility BABEL-3657 BABEL-3938 rowcount +BABEL-1625 +BABEL-3474 diff --git a/test/JDBC/upgrade/14_3/schedule b/test/JDBC/upgrade/14_3/schedule index b8ca6b0d60..b027049bd9 100644 --- a/test/JDBC/upgrade/14_3/schedule +++ b/test/JDBC/upgrade/14_3/schedule @@ -145,7 +145,6 @@ BABEL-2944 BABEL-3116 BABEL-3118 BABEL-3249 -BABEL-3474 BABEL-3588 BABEL-383 BABEL-405 @@ -323,3 +322,5 @@ BABEL-3657 BABEL-3938 binary-index rowcount +BABEL-1625 +BABEL-3474 diff --git a/test/JDBC/upgrade/14_5/schedule b/test/JDBC/upgrade/14_5/schedule index 611dfcbe1f..d835422d98 100644 --- a/test/JDBC/upgrade/14_5/schedule +++ b/test/JDBC/upgrade/14_5/schedule @@ -122,7 +122,6 @@ BABEL-2944 BABEL-3116 BABEL-3118 BABEL-3249 -BABEL-3474 BABEL-3588 BABEL-3369 BABEL-3370 @@ -337,3 +336,5 @@ BABEL-3657 BABEL-3938 binary-index rowcount +BABEL-1625 +BABEL-3474 diff --git a/test/JDBC/upgrade/14_6/schedule b/test/JDBC/upgrade/14_6/schedule index a5bd4445f7..3f24322f90 100644 --- a/test/JDBC/upgrade/14_6/schedule +++ b/test/JDBC/upgrade/14_6/schedule @@ -129,7 +129,6 @@ BABEL-3117 BABEL-3118 BABEL-3249 BABEL-3486 -BABEL-3474 BABEL-3614 BABEL-3646 BABEL-3748-before-14_7 @@ -256,7 +255,6 @@ BABEL-SP_SPROC_COLUMNS-dep BABEL-3000-dep format msdb-dbo-syspolicy_system_health_state -dateadd_internal_df sys-all_columns sys-assembly_modules sys-change_tracking_databases @@ -364,3 +362,6 @@ BABEL-3657 BABEL-3938 binary-index rowcount +BABEL-1625 +BABEL-3474 +dateadd_internal_df diff --git a/test/JDBC/upgrade/14_7/schedule b/test/JDBC/upgrade/14_7/schedule index 612c4a0d43..c0a68dfa9a 100644 --- a/test/JDBC/upgrade/14_7/schedule +++ b/test/JDBC/upgrade/14_7/schedule @@ -135,7 +135,6 @@ BABEL-3117 BABEL-3118 BABEL-3249 BABEL-3486 -BABEL-3474 BABEL-3614 BABEL-3646 BABEL-383 @@ -271,7 +270,6 @@ Test-sp_helprole-dep Test-sp_helprolemember-dep format msdb-dbo-syspolicy_system_health_state -dateadd_internal_df sys-all_columns sys-all_columns-dep sys-assembly_modules @@ -395,3 +393,6 @@ babel_context_info binary-index BABEL-745 rowcount +BABEL-1625 +BABEL-3474 +dateadd_internal_df diff --git a/test/JDBC/upgrade/14_8/schedule b/test/JDBC/upgrade/14_8/schedule index 0f901ee95f..381beefef4 100644 --- a/test/JDBC/upgrade/14_8/schedule +++ b/test/JDBC/upgrade/14_8/schedule @@ -135,7 +135,6 @@ BABEL-3117 BABEL-3118 BABEL-3249 BABEL-3486 -BABEL-3474 BABEL-3614 BABEL-3646 BABEL-383 @@ -271,7 +270,6 @@ Test-sp_helprole-dep Test-sp_helprolemember-dep format msdb-dbo-syspolicy_system_health_state -dateadd_internal_df sys-all_columns sys-all_columns-dep sys-assembly_modules @@ -393,3 +391,6 @@ BABEL-733 BABEL-3938 binary-index rowcount +BABEL-1625 +BABEL-3474 +dateadd_internal_df diff --git a/test/JDBC/upgrade/15_1/schedule b/test/JDBC/upgrade/15_1/schedule index a92fde4491..9a3e4c1aa3 100644 --- a/test/JDBC/upgrade/15_1/schedule +++ b/test/JDBC/upgrade/15_1/schedule @@ -131,7 +131,6 @@ BABEL-3117 BABEL-3118 BABEL-3249 BABEL-3486 -BABEL-3474 BABEL-3614 BABEL-3646 BABEL-383 @@ -263,7 +262,6 @@ Test-sp_helprole-dep Test-sp_helprolemember-dep format msdb-dbo-syspolicy_system_health_state -dateadd_internal_df sys-all_columns sys-assembly_modules sys-change_tracking_databases @@ -373,3 +371,6 @@ BABEL-3657 BABEL-3938 binary-index rowcount +BABEL-1625 +BABEL-3474 +dateadd_internal_df diff --git a/test/JDBC/upgrade/15_2/schedule b/test/JDBC/upgrade/15_2/schedule index 9341c416ce..78859feb76 100644 --- a/test/JDBC/upgrade/15_2/schedule +++ b/test/JDBC/upgrade/15_2/schedule @@ -133,7 +133,6 @@ BABEL-3117 BABEL-3118 BABEL-3249 BABEL-3486 -BABEL-3474 BABEL-3614 BABEL-3646 BABEL-383 @@ -270,7 +269,6 @@ Test-sp_helprole-dep Test-sp_helprolemember-dep format msdb-dbo-syspolicy_system_health_state -dateadd_internal_df sys-all_columns sys-all_columns-dep sys-all_sql_modules @@ -411,3 +409,6 @@ BABEL-NEXT-VALUE-FOR binary-index rowcount # test_windows_sp_helpuser +BABEL-1625 +BABEL-3474 +dateadd_internal_df diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index 69c210a6ff..af42f6296d 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -134,7 +134,6 @@ BABEL-3117 BABEL-3118 BABEL-3249 BABEL-3486 -BABEL-3474 BABEL-3614 BABEL-3646 BABEL-383 @@ -271,7 +270,6 @@ Test-sp_helprole-dep Test-sp_helprolemember-dep format msdb-dbo-syspolicy_system_health_state -dateadd_internal_df sys-all_columns sys-all_columns-dep sys-all_sql_modules @@ -417,3 +415,6 @@ binary-index test_windows_sp_helpuser BABEL-3478 rowcount +BABEL-1625 +BABEL-3474 +dateadd_internal_df diff --git a/test/JDBC/upgrade/master/schedule b/test/JDBC/upgrade/master/schedule index f51af2f745..5ac00e6da8 100644 --- a/test/JDBC/upgrade/master/schedule +++ b/test/JDBC/upgrade/master/schedule @@ -134,7 +134,6 @@ BABEL-3116 BABEL-3118 BABEL-3249 BABEL-3486 -BABEL-3474 BABEL-3614 BABEL-3646 BABEL-383 @@ -271,7 +270,6 @@ Test-sp_helprole-dep Test-sp_helprolemember-dep format msdb-dbo-syspolicy_system_health_state -dateadd_internal_df sys-all_columns sys-all_columns-dep # sys-all_sql_modules @@ -412,3 +410,6 @@ BABEL-3938 BABEL-NEXT-VALUE-FOR binary-index # test_windows_sp_helpuser +BABEL-1625 +BABEL-3474 +dateadd_internal_df From 3db679f7596769b85a22e55153cdaca9457867e0 Mon Sep 17 00:00:00 2001 From: pratikzode <73869399+pratikzode@users.noreply.github.com> Date: Fri, 17 Mar 2023 12:27:49 -0700 Subject: [PATCH 021/363] BABEL-1199 Support DATABASE_PRINCIPAL_ID() T-SQL function (#1344) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * BABEL-1199 Support DATABASE_PRINCIPAL_ID() T-SQL function SELECT DATABASE_PRINCIPAL_ID(); Retrieve the ID of the current user. SELECT DATABASE_PRINCIPAL_ID(‘principal_name’); Retrieve the ID of the specific database principal. Task: BABEL-1199 Signed-off-by: pratikzode * BABEL-1199 Added to schedule file Have added BABEL-1199 to 13_6, 13_9, 14_3, 14_5, 14_6, 14_8,15_1,15_2 Task: BABEL-1199 Signed-off-by: pratikzode * BABEL-1199 Deleted test from schedule Task: BABEL-1199 Signed-off-by: pratikzode * BABEL-1199 Added sys schema Task: BABEL-1199 Signed-off-by: pratikzode --------- Signed-off-by: pratikzode --- .../babelfishpg_tsql/sql/sys_functions.sql | 5 ++ .../babelfishpg_tsql--3.1.0--3.2.0.sql | 5 ++ test/JDBC/expected/BABEL-1199-vu-cleanup.out | 23 ++++++ test/JDBC/expected/BABEL-1199-vu-prepare.out | 30 +++++++ test/JDBC/expected/BABEL-1199-vu-verify.out | 80 +++++++++++++++++++ test/JDBC/input/BABEL-1199-vu-cleanup.sql | 23 ++++++ test/JDBC/input/BABEL-1199-vu-prepare.sql | 30 +++++++ test/JDBC/input/BABEL-1199-vu-verify.sql | 30 +++++++ test/JDBC/upgrade/latest/schedule | 1 + .../expected_dependency.out | 1 - 10 files changed, 227 insertions(+), 1 deletion(-) create mode 100644 test/JDBC/expected/BABEL-1199-vu-cleanup.out create mode 100644 test/JDBC/expected/BABEL-1199-vu-prepare.out create mode 100644 test/JDBC/expected/BABEL-1199-vu-verify.out create mode 100644 test/JDBC/input/BABEL-1199-vu-cleanup.sql create mode 100644 test/JDBC/input/BABEL-1199-vu-prepare.sql create mode 100644 test/JDBC/input/BABEL-1199-vu-verify.sql diff --git a/contrib/babelfishpg_tsql/sql/sys_functions.sql b/contrib/babelfishpg_tsql/sql/sys_functions.sql index 4a8e31697f..1fcbb9c92d 100644 --- a/contrib/babelfishpg_tsql/sql/sys_functions.sql +++ b/contrib/babelfishpg_tsql/sql/sys_functions.sql @@ -1738,6 +1738,11 @@ CREATE OR REPLACE FUNCTION sys.servername() CREATE OR REPLACE FUNCTION sys.servicename() RETURNS sys.NVARCHAR(128) AS 'babelfishpg_tsql' LANGUAGE C STABLE; +CREATE OR REPLACE FUNCTION sys.database_principal_id(IN user_name sys.sysname DEFAULT NULL) +RETURNS OID +AS 'babelfishpg_tsql', 'user_id' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + -- In tsql @@max_precision represents max precision that server supports -- As of now, we do not support change in max_precision. So, returning default value CREATE OR REPLACE FUNCTION sys.max_precision() diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql index 85d07090ab..159dece211 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql @@ -431,6 +431,11 @@ ALTER FUNCTION sys.json_modify RENAME TO json_modify_deprecated_in_3_2_0; CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'json_modify_deprecated_in_3_2_0'); +CREATE OR REPLACE FUNCTION sys.database_principal_id(IN user_name sys.sysname DEFAULT NULL) +RETURNS OID +AS 'babelfishpg_tsql', 'user_id' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + /* * JSON MODIFY * This function is used to update the value of a property in a JSON string and returns the updated JSON string. diff --git a/test/JDBC/expected/BABEL-1199-vu-cleanup.out b/test/JDBC/expected/BABEL-1199-vu-cleanup.out new file mode 100644 index 0000000000..0f6d3d8efc --- /dev/null +++ b/test/JDBC/expected/BABEL-1199-vu-cleanup.out @@ -0,0 +1,23 @@ +DROP VIEW view_current_principal_id; +GO + +DROP PROCEDURE proc_current_principal_id; +GO + +DROP VIEW view_db_owner_principal_id; +GO + +DROP PROCEDURE proc_db_owner_principal_id; +GO + +DROP VIEW view_db_owner_principal_id_v1; +GO + +DROP LOGIN testuser; +GO + +DROP USER testuser; +GO + +DROP ROLE roletest; +GO diff --git a/test/JDBC/expected/BABEL-1199-vu-prepare.out b/test/JDBC/expected/BABEL-1199-vu-prepare.out new file mode 100644 index 0000000000..398ccdc312 --- /dev/null +++ b/test/JDBC/expected/BABEL-1199-vu-prepare.out @@ -0,0 +1,30 @@ +CREATE VIEW dbo.view_current_principal_id AS +SELECT user_name(DATABASE_PRINCIPAL_ID()); +GO + +CREATE PROCEDURE dbo.proc_current_principal_id +AS +BEGIN + SELECT user_name(DATABASE_PRINCIPAL_ID()); +END; +GO + +CREATE VIEW dbo.view_db_owner_principal_id AS +SELECT user_name(DATABASE_PRINCIPAL_ID('db_owner')); +GO + +CREATE PROCEDURE dbo.proc_db_owner_principal_id +AS +BEGIN + SELECT user_name(DATABASE_PRINCIPAL_ID('db_owner')); +END; +GO + +CREATE VIEW dbo.view_db_owner_principal_id_v1 AS +SELECT (DATABASE_PRINCIPAL_ID('db_temp')); +GO + +CREATE LOGIN testuser WITH PASSWORD = 'testpassword'; +CREATE USER testuser FOR LOGIN testuser; +CREATE ROLE roletest; +GO diff --git a/test/JDBC/expected/BABEL-1199-vu-verify.out b/test/JDBC/expected/BABEL-1199-vu-verify.out new file mode 100644 index 0000000000..34289d1be3 --- /dev/null +++ b/test/JDBC/expected/BABEL-1199-vu-verify.out @@ -0,0 +1,80 @@ +SELECT * FROM view_current_principal_id; +GO +~~START~~ +nvarchar +dbo +~~END~~ + + +EXEC proc_current_principal_id; +GO +~~START~~ +nvarchar +dbo +~~END~~ + + +SELECT * FROM view_db_owner_principal_id; +GO +~~START~~ +nvarchar +db_owner +~~END~~ + + +EXEC proc_db_owner_principal_id; +GO +~~START~~ +nvarchar +db_owner +~~END~~ + + +SELECT * FROM view_db_owner_principal_id_v1; +GO +~~START~~ +int + +~~END~~ + + + +SELECT user_name(DATABASE_PRINCIPAL_ID('db_owner')); +GO +~~START~~ +nvarchar +db_owner +~~END~~ + + +SELECT user_name(DATABASE_PRINCIPAL_ID('dbo')); +GO +~~START~~ +nvarchar +dbo +~~END~~ + + +SELECT user_name(DATABASE_PRINCIPAL_ID('guest')); +GO +~~START~~ +nvarchar +guest +~~END~~ + + +SELECT user_name(DATABASE_PRINCIPAL_ID('testuser')); +GO +~~START~~ +nvarchar +testuser +~~END~~ + + +SELECT user_name(DATABASE_PRINCIPAL_ID('roletest')); +GO +~~START~~ +nvarchar +roletest +~~END~~ + diff --git a/test/JDBC/input/BABEL-1199-vu-cleanup.sql b/test/JDBC/input/BABEL-1199-vu-cleanup.sql new file mode 100644 index 0000000000..b399ec2efe --- /dev/null +++ b/test/JDBC/input/BABEL-1199-vu-cleanup.sql @@ -0,0 +1,23 @@ +DROP VIEW view_current_principal_id; +GO + +DROP PROCEDURE proc_current_principal_id; +GO + +DROP VIEW view_db_owner_principal_id; +GO + +DROP PROCEDURE proc_db_owner_principal_id; +GO + +DROP VIEW view_db_owner_principal_id_v1; +GO + +DROP LOGIN testuser; +GO + +DROP USER testuser; +GO + +DROP ROLE roletest; +GO \ No newline at end of file diff --git a/test/JDBC/input/BABEL-1199-vu-prepare.sql b/test/JDBC/input/BABEL-1199-vu-prepare.sql new file mode 100644 index 0000000000..52973ce8e9 --- /dev/null +++ b/test/JDBC/input/BABEL-1199-vu-prepare.sql @@ -0,0 +1,30 @@ +CREATE VIEW dbo.view_current_principal_id AS +SELECT user_name(DATABASE_PRINCIPAL_ID()); +GO + +CREATE PROCEDURE dbo.proc_current_principal_id +AS +BEGIN + SELECT user_name(DATABASE_PRINCIPAL_ID()); +END; +GO + +CREATE VIEW dbo.view_db_owner_principal_id AS +SELECT user_name(DATABASE_PRINCIPAL_ID('db_owner')); +GO + +CREATE PROCEDURE dbo.proc_db_owner_principal_id +AS +BEGIN + SELECT user_name(DATABASE_PRINCIPAL_ID('db_owner')); +END; +GO + +CREATE VIEW dbo.view_db_owner_principal_id_v1 AS +SELECT (DATABASE_PRINCIPAL_ID('db_temp')); +GO + +CREATE LOGIN testuser WITH PASSWORD = 'testpassword'; +CREATE USER testuser FOR LOGIN testuser; +CREATE ROLE roletest; +GO \ No newline at end of file diff --git a/test/JDBC/input/BABEL-1199-vu-verify.sql b/test/JDBC/input/BABEL-1199-vu-verify.sql new file mode 100644 index 0000000000..bce78b94e1 --- /dev/null +++ b/test/JDBC/input/BABEL-1199-vu-verify.sql @@ -0,0 +1,30 @@ +SELECT * FROM view_current_principal_id; +GO + +EXEC proc_current_principal_id; +GO + +SELECT * FROM view_db_owner_principal_id; +GO + +EXEC proc_db_owner_principal_id; +GO + +SELECT * FROM view_db_owner_principal_id_v1; +GO + + +SELECT user_name(DATABASE_PRINCIPAL_ID('db_owner')); +GO + +SELECT user_name(DATABASE_PRINCIPAL_ID('dbo')); +GO + +SELECT user_name(DATABASE_PRINCIPAL_ID('guest')); +GO + +SELECT user_name(DATABASE_PRINCIPAL_ID('testuser')); +GO + +SELECT user_name(DATABASE_PRINCIPAL_ID('roletest')); +GO \ No newline at end of file diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index af42f6296d..7b886aff40 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -409,6 +409,7 @@ test_windows_alter_user BABEL-733 BABEL-745 BABEL-3938 +BABEL-1199 BABEL-NEXT-VALUE-FOR babel_context_info binary-index diff --git a/test/python/expected/upgrade_validation/expected_dependency.out b/test/python/expected/upgrade_validation/expected_dependency.out index 450602fa4f..c936707ea6 100644 --- a/test/python/expected/upgrade_validation/expected_dependency.out +++ b/test/python/expected/upgrade_validation/expected_dependency.out @@ -668,7 +668,6 @@ Function sys.uniqueidentifier_hash(sys.uniqueidentifier) Function sys.uniqueidentifier_sqlvariant(sys.uniqueidentifier) Function sys.update(text) Function sys.user_id(text) -Function sys.user_name(oid) Function sys.user_name_sysname() Function sys.varbinary(sys.varbinary,integer,boolean) Function sys.varbinary2uniqueidentifier(sys.bbf_varbinary,integer,boolean) From e2d3449ed48a7715e11eedd50737a7655d9b5c56 Mon Sep 17 00:00:00 2001 From: Yanjie Xu Date: Fri, 17 Mar 2023 16:28:09 -0700 Subject: [PATCH 022/363] Fix uninitialized error on context_info Task: BABEL-748 Signed-off-by: Yanjie Xu --- contrib/babelfishpg_tsql/runtime/functions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/babelfishpg_tsql/runtime/functions.c b/contrib/babelfishpg_tsql/runtime/functions.c index d6640c8a70..6917591a12 100644 --- a/contrib/babelfishpg_tsql/runtime/functions.c +++ b/contrib/babelfishpg_tsql/runtime/functions.c @@ -1771,7 +1771,7 @@ host_name(PG_FUNCTION_ARGS) Datum context_info(PG_FUNCTION_ARGS) { - Datum context_info; + Datum context_info = (Datum) 0; if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->get_context_info) context_info = (*pltsql_protocol_plugin_ptr)->get_context_info(); From 2c628b8c3b8857ed7651d38f9a5cbd2f422f2c8b Mon Sep 17 00:00:00 2001 From: Kristian Lejao <1741885+lejaokri@users.noreply.github.com> Date: Mon, 20 Mar 2023 09:47:32 -0700 Subject: [PATCH 023/363] Include public, sys, and INFORMATION_SCHEMA in sys.database_principals VIEW These dummy principals for read-only purposes. There are no actual objects behind them. Task: BABEL-3230 Signed-off-by: Kristian Lejao --- contrib/babelfishpg_tsql/sql/ownership.sql | 36 +++++++++-- .../babelfishpg_tsql--3.1.0--3.2.0.sql | 61 +++++++++++++++++++ test/JDBC/expected/BABEL-LOGIN-USER-EXT.out | 6 ++ test/JDBC/expected/BABEL-ROLE-vu-verify.out | 14 +++++ test/JDBC/expected/BABEL-USER.out | 3 + .../input/ownership/BABEL-ROLE-vu-verify.mix | 7 +++ 6 files changed, 122 insertions(+), 5 deletions(-) diff --git a/contrib/babelfishpg_tsql/sql/ownership.sql b/contrib/babelfishpg_tsql/sql/ownership.sql index 1760aacc63..5508447a9d 100644 --- a/contrib/babelfishpg_tsql/sql/ownership.sql +++ b/contrib/babelfishpg_tsql/sql/ownership.sql @@ -335,17 +335,18 @@ SELECT pg_catalog.pg_extension_config_dump('sys.babelfish_authid_login_ext', '') SELECT pg_catalog.pg_extension_config_dump('sys.babelfish_authid_user_ext', ''); -- DATABASE_PRINCIPALS -CREATE OR REPLACE VIEW sys.database_principals AS SELECT +CREATE OR REPLACE VIEW sys.database_principals AS +SELECT CAST(Ext.orig_username AS SYS.SYSNAME) AS name, CAST(Base.oid AS INT) AS principal_id, CAST(Ext.type AS CHAR(1)) as type, CAST( - CASE + CASE WHEN Ext.type = 'S' THEN 'SQL_USER' WHEN Ext.type = 'R' THEN 'DATABASE_ROLE' WHEN Ext.type = 'U' THEN 'WINDOWS_USER' - ELSE NULL - END + ELSE NULL + END AS SYS.NVARCHAR(60)) AS type_desc, CAST(Ext.default_schema_name AS SYS.SYSNAME) AS default_schema_name, CAST(Ext.create_date AS SYS.DATETIME) AS create_date, @@ -362,7 +363,32 @@ FROM pg_catalog.pg_roles AS Base INNER JOIN sys.babelfish_authid_user_ext AS Ext ON Base.rolname = Ext.rolname LEFT OUTER JOIN pg_catalog.pg_roles Base2 ON Ext.login_name = Base2.rolname -WHERE Ext.database_name = DB_NAME(); +WHERE Ext.database_name = DB_NAME() +UNION ALL +SELECT +CAST(name AS SYS.SYSNAME) AS name, +CAST(-1 AS INT) AS principal_id, +CAST(type AS CHAR(1)) as type, +CAST( + CASE + WHEN type = 'S' THEN 'SQL_USER' + WHEN type = 'R' THEN 'DATABASE_ROLE' + WHEN type = 'U' THEN 'WINDOWS_USER' + ELSE NULL + END + AS SYS.NVARCHAR(60)) AS type_desc, +CAST(NULL AS SYS.SYSNAME) AS default_schema_name, +CAST(NULL AS SYS.DATETIME) AS create_date, +CAST(NULL AS SYS.DATETIME) AS modify_date, +CAST(-1 AS INT) AS owning_principal_id, +CAST(CAST(0 AS INT) AS SYS.VARBINARY(85)) AS SID, +CAST(0 AS SYS.BIT) AS is_fixed_role, +CAST(-1 AS INT) AS authentication_type, +CAST(NULL AS SYS.NVARCHAR(60)) AS authentication_type_desc, +CAST(NULL AS SYS.SYSNAME) AS default_language_name, +CAST(-1 AS INT) AS default_language_lcid, +CAST(0 AS SYS.BIT) AS allow_encrypted_value_modifications +FROM (VALUES ('public', 'R'), ('sys', 'S'), ('INFORMATION_SCHEMA', 'S')) as dummy_principals(name, type); GRANT SELECT ON sys.database_principals TO PUBLIC; diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql index 159dece211..23068dece8 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql @@ -640,6 +640,67 @@ $$ STRICT LANGUAGE plpgsql IMMUTABLE; +-- DATABASE_PRINCIPALS: Include Hard coded public, sys, INFORMATION_SCHEMA users +ALTER VIEW sys.database_principals RENAME TO database_principals_deprecated_3_2_0; + +CREATE OR REPLACE VIEW sys.database_principals AS +SELECT +CAST(Ext.orig_username AS SYS.SYSNAME) AS name, +CAST(Base.oid AS INT) AS principal_id, +CAST(Ext.type AS CHAR(1)) as type, +CAST( + CASE + WHEN Ext.type = 'S' THEN 'SQL_USER' + WHEN Ext.type = 'R' THEN 'DATABASE_ROLE' + WHEN Ext.type = 'U' THEN 'WINDOWS_USER' + ELSE NULL + END + AS SYS.NVARCHAR(60)) AS type_desc, +CAST(Ext.default_schema_name AS SYS.SYSNAME) AS default_schema_name, +CAST(Ext.create_date AS SYS.DATETIME) AS create_date, +CAST(Ext.modify_date AS SYS.DATETIME) AS modify_date, +CAST(Ext.owning_principal_id AS INT) AS owning_principal_id, +CAST(CAST(Base2.oid AS INT) AS SYS.VARBINARY(85)) AS SID, +CAST(Ext.is_fixed_role AS SYS.BIT) AS is_fixed_role, +CAST(Ext.authentication_type AS INT) AS authentication_type, +CAST(Ext.authentication_type_desc AS SYS.NVARCHAR(60)) AS authentication_type_desc, +CAST(Ext.default_language_name AS SYS.SYSNAME) AS default_language_name, +CAST(Ext.default_language_lcid AS INT) AS default_language_lcid, +CAST(Ext.allow_encrypted_value_modifications AS SYS.BIT) AS allow_encrypted_value_modifications +FROM pg_catalog.pg_roles AS Base INNER JOIN sys.babelfish_authid_user_ext AS Ext +ON Base.rolname = Ext.rolname +LEFT OUTER JOIN pg_catalog.pg_roles Base2 +ON Ext.login_name = Base2.rolname +WHERE Ext.database_name = DB_NAME() +UNION ALL +SELECT +CAST(name AS SYS.SYSNAME) AS name, +CAST(-1 AS INT) AS principal_id, +CAST(type AS CHAR(1)) as type, +CAST( + CASE + WHEN type = 'S' THEN 'SQL_USER' + WHEN type = 'R' THEN 'DATABASE_ROLE' + WHEN type = 'U' THEN 'WINDOWS_USER' + ELSE NULL + END + AS SYS.NVARCHAR(60)) AS type_desc, +CAST(NULL AS SYS.SYSNAME) AS default_schema_name, +CAST(NULL AS SYS.DATETIME) AS create_date, +CAST(NULL AS SYS.DATETIME) AS modify_date, +CAST(-1 AS INT) AS owning_principal_id, +CAST(CAST(0 AS INT) AS SYS.VARBINARY(85)) AS SID, +CAST(0 AS SYS.BIT) AS is_fixed_role, +CAST(-1 AS INT) AS authentication_type, +CAST(NULL AS SYS.NVARCHAR(60)) AS authentication_type_desc, +CAST(NULL AS SYS.SYSNAME) AS default_language_name, +CAST(-1 AS INT) AS default_language_lcid, +CAST(0 AS SYS.BIT) AS allow_encrypted_value_modifications +FROM (VALUES ('public', 'R'), ('sys', 'S'), ('INFORMATION_SCHEMA', 'S')) as dummy_principals(name, type); + +GRANT SELECT ON sys.database_principals TO PUBLIC; +CALL sys.babelfish_drop_deprecated_object('view', 'sys', 'database_principals_deprecated_3_2_0'); + -- Drops the temporary procedure used by the upgrade script. -- Please have this be one of the last statements executed in this upgrade script. DROP PROCEDURE sys.babelfish_drop_deprecated_object(varchar, varchar, varchar); diff --git a/test/JDBC/expected/BABEL-LOGIN-USER-EXT.out b/test/JDBC/expected/BABEL-LOGIN-USER-EXT.out index d93ac02abd..569e7b0a19 100644 --- a/test/JDBC/expected/BABEL-LOGIN-USER-EXT.out +++ b/test/JDBC/expected/BABEL-LOGIN-USER-EXT.out @@ -960,6 +960,9 @@ varchar#!#varchar dbo#!#dbo db_owner#!# guest#!# +INFORMATION_SCHEMA#!# +public#!# +sys#!# ~~END~~ @@ -989,6 +992,9 @@ varchar#!#varchar dbo#!#dbo db_owner#!# guest#!# +INFORMATION_SCHEMA#!# +public#!# +sys#!# ~~END~~ diff --git a/test/JDBC/expected/BABEL-ROLE-vu-verify.out b/test/JDBC/expected/BABEL-ROLE-vu-verify.out index 277445a2d1..da21b79fdd 100644 --- a/test/JDBC/expected/BABEL-ROLE-vu-verify.out +++ b/test/JDBC/expected/BABEL-ROLE-vu-verify.out @@ -7,9 +7,23 @@ master ~~END~~ + +-- Ensure public, sys and INFORMATION_SCHEMA +-- are in database_principals after an upgrade +SELECT name, type, type_desc +FROM sys.database_principals +WHERE name IN ('public', 'sys', 'INFORMATION_SCHEMA') +ORDER BY name -- Test CREATE ROLE CREATE ROLE babel_role_vu_prepare_role1 GO +~~START~~ +varchar#!#char#!#nvarchar +INFORMATION_SCHEMA#!#S#!#SQL_USER +public#!#R#!#DATABASE_ROLE +sys#!#S#!#SQL_USER +~~END~~ + EXEC babel_role_vu_prepare_user_ext_master GO diff --git a/test/JDBC/expected/BABEL-USER.out b/test/JDBC/expected/BABEL-USER.out index 5ccb991143..811b623202 100644 --- a/test/JDBC/expected/BABEL-USER.out +++ b/test/JDBC/expected/BABEL-USER.out @@ -73,6 +73,9 @@ varchar#!#varchar dbo#!#dbo db_owner#!# guest#!# +INFORMATION_SCHEMA#!# +public#!# +sys#!# ~~END~~ diff --git a/test/JDBC/input/ownership/BABEL-ROLE-vu-verify.mix b/test/JDBC/input/ownership/BABEL-ROLE-vu-verify.mix index fc63688c8a..2489cdb4ed 100644 --- a/test/JDBC/input/ownership/BABEL-ROLE-vu-verify.mix +++ b/test/JDBC/input/ownership/BABEL-ROLE-vu-verify.mix @@ -2,6 +2,13 @@ SELECT DB_NAME() GO +-- Ensure public, sys and INFORMATION_SCHEMA +-- are in database_principals after an upgrade +SELECT name, type, type_desc +FROM sys.database_principals +WHERE name IN ('public', 'sys', 'INFORMATION_SCHEMA') +ORDER BY name + -- Test CREATE ROLE CREATE ROLE babel_role_vu_prepare_role1 GO From f177e5756a45e5d148dcca25b9e1048791a05c40 Mon Sep 17 00:00:00 2001 From: Sharu Goel <30777678+thephantomthief@users.noreply.github.com> Date: Tue, 21 Mar 2023 16:33:05 +0530 Subject: [PATCH 024/363] Fix crash in sp_addlinkedserver (#1345) This commit fixes a crash in sp_addlinkedserver that was arising due to an attempt to free pointer to a string literal. Signed-off-by: Sharu Goel goelshar@amazon.com --- contrib/babelfishpg_tsql/src/procedures.c | 12 ++++++------ test/JDBC/expected/linked_servers-vu-prepare.out | 12 ++++++++++-- test/JDBC/input/linked_servers-vu-prepare.mix | 8 ++++++-- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/contrib/babelfishpg_tsql/src/procedures.c b/contrib/babelfishpg_tsql/src/procedures.c index 8fe03bb818..952ffdb7dd 100644 --- a/contrib/babelfishpg_tsql/src/procedures.c +++ b/contrib/babelfishpg_tsql/src/procedures.c @@ -2137,8 +2137,8 @@ Datum sp_addlinkedserver_internal(PG_FUNCTION_ARGS) { char *linked_server = PG_ARGISNULL(0) ? NULL : lowerstr(text_to_cstring(PG_GETARG_TEXT_P(0))); - char *srv_product = PG_ARGISNULL(1) ? "" : lowerstr(text_to_cstring(PG_GETARG_TEXT_P(1))); - char *provider = PG_ARGISNULL(2) ? "" : lowerstr(text_to_cstring(PG_GETARG_TEXT_P(2))); + char *srv_product = PG_ARGISNULL(1) ? NULL : lowerstr(text_to_cstring(PG_GETARG_TEXT_P(1))); + char *provider = PG_ARGISNULL(2) ? NULL : lowerstr(text_to_cstring(PG_GETARG_TEXT_P(2))); char *data_src = PG_ARGISNULL(3) ? NULL : text_to_cstring(PG_GETARG_TEXT_P(3)); char *provstr = PG_ARGISNULL(5) ? NULL : text_to_cstring(PG_GETARG_TEXT_P(5)); char *catalog = PG_ARGISNULL(6) ? NULL : text_to_cstring(PG_GETARG_TEXT_P(6)); @@ -2157,7 +2157,7 @@ sp_addlinkedserver_internal(PG_FUNCTION_ARGS) (errcode(ERRCODE_FDW_ERROR), errmsg("@server parameter cannot be NULL"))); - if (strlen(srv_product) == 10 && (strncmp(srv_product, "sql server", 10) == 0)) + if (srv_product && (strlen(srv_product) == 10) && (strncmp(srv_product, "sql server", 10) == 0)) { /* * if server product is "SQL Server", rest of the arguments need not be @@ -2168,14 +2168,14 @@ sp_addlinkedserver_internal(PG_FUNCTION_ARGS) } else { - if (((strlen(provider) == 7) && (strncmp(provider, "sqlncli", 7) == 0)) || + if (provider && (((strlen(provider) == 7) && (strncmp(provider, "sqlncli", 7) == 0)) || ((strlen(provider) == 10) && (strncmp(provider, "msoledbsql", 10) == 0)) || - ((strlen(provider) == 8) && (strncmp(provider, "sqloledb", 8) == 0))) + ((strlen(provider) == 8) && (strncmp(provider, "sqloledb", 8) == 0)))) { /* if provider is a valid T-SQL provider, we throw a warning indicating internally, we will be using tds_fdw */ provider_warning = true; } - else if ((strlen(provider) != 7) || (strncmp(provider, "tds_fdw", 7) != 0)) + else if (!provider || (strlen(provider) != 7) || (strncmp(provider, "tds_fdw", 7) != 0)) ereport(ERROR, (errcode(ERRCODE_FDW_ERROR), errmsg("Unsupported provider '%s'. Supported provider is 'tds_fdw'", provider))); diff --git a/test/JDBC/expected/linked_servers-vu-prepare.out b/test/JDBC/expected/linked_servers-vu-prepare.out index dc1036191b..2222d4b9ea 100644 --- a/test/JDBC/expected/linked_servers-vu-prepare.out +++ b/test/JDBC/expected/linked_servers-vu-prepare.out @@ -41,10 +41,18 @@ GO EXEC sp_addlinkedserver @server = N'hello.world.com', @srvproduct=N'SQL Server' GO --- Create linked server with a non-null provider string (Will throw warning internally) -EXEC sp_addlinkedserver @server = N'mssql_server2', @srvproduct=N'', @provider=N'tds_fdw', @datasrc=N'localhost', @provstr='blahblahblah', @catalog=N'master' +-- Create linked server with a non-null provider string and NULL @srvproduct (Will throw warning internally) +EXEC sp_addlinkedserver @server = N'mssql_server2', @provider=N'tds_fdw', @datasrc=N'localhost', @provstr='blahblahblah', @catalog=N'master' GO +-- Try to create linked server with NULL @provider (Should throw error) +EXEC sp_addlinkedserver @server = N'mssql_server', @srvproduct=N'', @provider=NULL, @datasrc=N'localhost', @catalog=N'master' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Unsupported provider '(null)'. Supported provider is 'tds_fdw')~~ + + -- Try to create linked server with same server name (Should throw error) EXEC sp_addlinkedserver @server = N'mssql_server', @srvproduct=N'', @provider=N'tds_fdw', @datasrc=N'localhost', @catalog=N'master' GO diff --git a/test/JDBC/input/linked_servers-vu-prepare.mix b/test/JDBC/input/linked_servers-vu-prepare.mix index 6e87066d27..9b22c45180 100644 --- a/test/JDBC/input/linked_servers-vu-prepare.mix +++ b/test/JDBC/input/linked_servers-vu-prepare.mix @@ -29,8 +29,12 @@ GO EXEC sp_addlinkedserver @server = N'hello.world.com', @srvproduct=N'SQL Server' GO --- Create linked server with a non-null provider string (Will throw warning internally) -EXEC sp_addlinkedserver @server = N'mssql_server2', @srvproduct=N'', @provider=N'tds_fdw', @datasrc=N'localhost', @provstr='blahblahblah', @catalog=N'master' +-- Create linked server with a non-null provider string and NULL @srvproduct (Will throw warning internally) +EXEC sp_addlinkedserver @server = N'mssql_server2', @provider=N'tds_fdw', @datasrc=N'localhost', @provstr='blahblahblah', @catalog=N'master' +GO + +-- Try to create linked server with NULL @provider (Should throw error) +EXEC sp_addlinkedserver @server = N'mssql_server', @srvproduct=N'', @provider=NULL, @datasrc=N'localhost', @catalog=N'master' GO -- Try to create linked server with same server name (Should throw error) From 243e3294c5fee7863e7846b30d8a821b7e4b4242 Mon Sep 17 00:00:00 2001 From: Dipesh Dhameliya Date: Thu, 23 Mar 2023 10:04:35 +0530 Subject: [PATCH 025/363] Run pgindent on each babelfish extensions code (#1357) * Run pgindent on each babelfish extensions * fix compilation error --------- Co-authored-by: Dipesh Dhameliya --- .../src/babelfishpg_common.c | 88 +- .../src/babelfishpg_common.h | 72 +- contrib/babelfishpg_common/src/bit.c | 238 +- contrib/babelfishpg_common/src/coerce.c | 73 +- contrib/babelfishpg_common/src/collation.c | 1191 ++--- contrib/babelfishpg_common/src/collation.h | 150 +- contrib/babelfishpg_common/src/datetime.c | 185 +- contrib/babelfishpg_common/src/datetime.h | 2 +- contrib/babelfishpg_common/src/datetime2.c | 77 +- contrib/babelfishpg_common/src/datetime2.h | 2 +- .../babelfishpg_common/src/datetimeoffset.c | 131 +- .../babelfishpg_common/src/datetimeoffset.h | 4 +- .../src/encoding/encoding.h | 44 +- .../src/encoding/encoding_utils.c | 28 +- .../babelfishpg_common/src/encoding/mb/conv.c | 44 +- .../utf8_and_big5/utf8_and_big5.c | 18 +- .../utf8_and_gbk/utf8_and_gbk.c | 20 +- .../utf8_and_sjis/utf8_and_sjis.c | 20 +- .../utf8_and_uhc/utf8_and_uhc.c | 18 +- .../utf8_and_win/utf8_and_win.c | 22 +- contrib/babelfishpg_common/src/instr.c | 5 +- contrib/babelfishpg_common/src/instr.h | 13 +- contrib/babelfishpg_common/src/numeric.c | 105 +- .../babelfishpg_common/src/smalldatetime.c | 228 +- contrib/babelfishpg_common/src/sqlvariant.c | 2663 +++++------ contrib/babelfishpg_common/src/sqlvariant.h | 46 +- contrib/babelfishpg_common/src/typecode.c | 390 +- contrib/babelfishpg_common/src/typecode.h | 64 +- .../babelfishpg_common/src/uniqueidentifier.c | 129 +- contrib/babelfishpg_common/src/varbinary.c | 728 +-- contrib/babelfishpg_common/src/varchar.c | 286 +- contrib/babelfishpg_common/src/varchar.h | 2 +- contrib/babelfishpg_money/fixeddecimal.c | 455 +- .../backend/fault_injection/fault_injection.c | 52 +- .../fault_injection/fault_injection_tests.c | 118 +- .../src/backend/tds/err_handler.c | 150 +- contrib/babelfishpg_tds/src/backend/tds/guc.c | 388 +- .../src/backend/tds/support_funcs.c | 8 +- .../src/backend/tds/tds-secure-openssl.c | 92 +- contrib/babelfishpg_tds/src/backend/tds/tds.c | 154 +- .../src/backend/tds/tds_data_map.c | 412 +- .../babelfishpg_tds/src/backend/tds/tds_srv.c | 56 +- .../src/backend/tds/tdsbulkload.c | 993 ++-- .../babelfishpg_tds/src/backend/tds/tdscomm.c | 147 +- .../src/backend/tds/tdslogin.c | 755 +-- .../src/backend/tds/tdsprinttup.c | 6 +- .../src/backend/tds/tdsprotocol.c | 178 +- .../src/backend/tds/tdsresponse.c | 1732 +++---- .../babelfishpg_tds/src/backend/tds/tdsrpc.c | 1838 ++++---- .../src/backend/tds/tdssecure.c | 105 +- .../src/backend/tds/tdssqlbatch.c | 33 +- .../src/backend/tds/tdstimestamp.c | 315 +- .../src/backend/tds/tdstypeio.c | 1804 ++++---- .../src/backend/tds/tdsutils.c | 441 +- .../babelfishpg_tds/src/backend/tds/tdsxact.c | 83 +- .../src/backend/utils/adt/numeric.c | 38 +- .../src/backend/utils/adt/varchar.c | 8 +- .../src/backend/utils/adt/xml.c | 204 +- .../babelfishpg_tds/src/include/err_handler.h | 57 +- .../src/include/faultinjection.h | 25 +- contrib/babelfishpg_tds/src/include/guc.h | 12 +- contrib/babelfishpg_tds/src/include/tds.h | 5 +- .../babelfishpg_tds/src/include/tds_debug.h | 4 +- .../babelfishpg_tds/src/include/tds_instr.h | 5 +- contrib/babelfishpg_tds/src/include/tds_int.h | 128 +- .../src/include/tds_iofuncmap.h | 56 +- .../src/include/tds_protocol.h | 10 +- .../babelfishpg_tds/src/include/tds_request.h | 580 +-- .../src/include/tds_response.h | 26 +- .../babelfishpg_tds/src/include/tds_secure.h | 19 +- .../src/include/tds_timestamp.h | 16 +- .../src/include/tds_typecode.h | 2 +- .../babelfishpg_tds/src/include/tds_typeio.h | 395 +- .../babelfishpg_tds/src/include/tdsprinttup.h | 2 - contrib/babelfishpg_tsql/runtime/functions.c | 953 ++-- contrib/babelfishpg_tsql/src/analyzer.c | 469 +- contrib/babelfishpg_tsql/src/analyzer.h | 4 +- contrib/babelfishpg_tsql/src/applock.c | 437 +- .../babelfishpg_tsql/src/babelfish_version.h | 1 - .../src/backend_parser/gram-tsql-epilogue.y.c | 1462 +++--- .../src/backend_parser/gram-tsql-prologue.y.h | 59 +- .../src/backend_parser/gram_hook.c | 134 +- .../src/backend_parser/gramparse.h | 8 +- .../src/backend_parser/parser.c | 22 +- .../src/backend_parser/scan-tsql-epilogue.l.c | 19 +- .../src/backend_parser/scan-tsql-prologue.l.h | 2 +- .../src/backend_parser/scanner.h | 12 +- contrib/babelfishpg_tsql/src/catalog.c | 1099 ++--- contrib/babelfishpg_tsql/src/catalog.h | 124 +- contrib/babelfishpg_tsql/src/codegen.c | 877 ++-- contrib/babelfishpg_tsql/src/codegen.h | 4 +- contrib/babelfishpg_tsql/src/collation.c | 387 +- contrib/babelfishpg_tsql/src/collation.h | 92 +- .../babelfishpg_tsql/src/collationproperty.c | 17 +- .../babelfishpg_tsql/src/compile_context.c | 75 +- .../babelfishpg_tsql/src/compile_context.h | 28 +- contrib/babelfishpg_tsql/src/cursor.c | 698 +-- .../babelfishpg_tsql/src/databasepropertyex.c | 50 +- contrib/babelfishpg_tsql/src/datatype_info.h | 267 +- contrib/babelfishpg_tsql/src/dbcmds.c | 444 +- contrib/babelfishpg_tsql/src/dbcmds.h | 2 +- contrib/babelfishpg_tsql/src/dynastack.c | 43 +- contrib/babelfishpg_tsql/src/dynastack.h | 18 +- contrib/babelfishpg_tsql/src/dynavec.c | 124 +- contrib/babelfishpg_tsql/src/dynavec.h | 36 +- contrib/babelfishpg_tsql/src/err_handler.c | 256 +- contrib/babelfishpg_tsql/src/err_handler.h | 21 +- contrib/babelfishpg_tsql/src/format.c | 949 ++-- contrib/babelfishpg_tsql/src/format.h | 74 +- contrib/babelfishpg_tsql/src/guc.c | 1877 ++++---- contrib/babelfishpg_tsql/src/guc.h | 19 +- contrib/babelfishpg_tsql/src/hooks.c | 1439 +++--- contrib/babelfishpg_tsql/src/hooks.h | 8 +- contrib/babelfishpg_tsql/src/iterative_exec.c | 1270 ++--- contrib/babelfishpg_tsql/src/iterative_exec.h | 19 +- contrib/babelfishpg_tsql/src/json_funcs.c | 260 +- contrib/babelfishpg_tsql/src/linked_servers.c | 550 ++- contrib/babelfishpg_tsql/src/linked_servers.h | 38 +- contrib/babelfishpg_tsql/src/multidb.c | 1485 +++--- contrib/babelfishpg_tsql/src/multidb.h | 5 +- contrib/babelfishpg_tsql/src/pl_comp-2.c | 46 +- contrib/babelfishpg_tsql/src/pl_comp.c | 645 +-- contrib/babelfishpg_tsql/src/pl_exec-2.c | 1835 ++++---- contrib/babelfishpg_tsql/src/pl_exec.c | 2614 ++++++----- contrib/babelfishpg_tsql/src/pl_explain.c | 103 +- contrib/babelfishpg_tsql/src/pl_explain.h | 6 +- contrib/babelfishpg_tsql/src/pl_funcs-2.c | 694 +-- contrib/babelfishpg_tsql/src/pl_funcs-2.h | 2 +- contrib/babelfishpg_tsql/src/pl_funcs.c | 63 +- contrib/babelfishpg_tsql/src/pl_handler.c | 4072 +++++++++-------- .../babelfishpg_tsql/src/pl_reserved_kwlist.h | 6 +- contrib/babelfishpg_tsql/src/pl_scanner.c | 122 +- .../src/pl_unreserved_kwlist.h | 6 +- contrib/babelfishpg_tsql/src/plan_inval.c | 36 +- contrib/babelfishpg_tsql/src/plerrcodes.h | 1 - contrib/babelfishpg_tsql/src/pltsql-2.h | 172 +- contrib/babelfishpg_tsql/src/pltsql.h | 680 +-- .../babelfishpg_tsql/src/pltsql_bulkcopy.c | 130 +- .../babelfishpg_tsql/src/pltsql_bulkcopy.h | 33 +- contrib/babelfishpg_tsql/src/pltsql_coerce.c | 1195 ++--- .../src/pltsql_function_probin_handler.c | 308 +- .../babelfishpg_tsql/src/pltsql_identity.c | 120 +- contrib/babelfishpg_tsql/src/pltsql_instr.h | 9 +- .../babelfishpg_tsql/src/pltsql_ruleutils.c | 366 +- contrib/babelfishpg_tsql/src/pltsql_utils.c | 489 +- contrib/babelfishpg_tsql/src/prepare.c | 305 +- contrib/babelfishpg_tsql/src/procedures.c | 1997 ++++---- contrib/babelfishpg_tsql/src/properties.c | 349 +- contrib/babelfishpg_tsql/src/rolecmds.c | 830 ++-- contrib/babelfishpg_tsql/src/rolecmds.h | 14 +- contrib/babelfishpg_tsql/src/schemacmds.c | 71 +- contrib/babelfishpg_tsql/src/session.c | 130 +- contrib/babelfishpg_tsql/src/session.h | 4 +- .../babelfishpg_tsql/src/special_keywords.c | 143 +- contrib/babelfishpg_tsql/src/stmt_walker.c | 348 +- contrib/babelfishpg_tsql/src/stmt_walker.h | 112 +- contrib/babelfishpg_tsql/src/string.c | 778 ++-- contrib/babelfishpg_tsql/src/tablecmds.c | 303 +- contrib/babelfishpg_tsql/src/tsqlHandler.c | 18 +- contrib/babelfishpg_tsql/src/tsqlNodes.c | 32 +- contrib/babelfishpg_tsql/src/tsqlNodes.h | 159 +- .../src/tsqlUnsupportedFeatureHandler.h | 0 contrib/babelfishpg_tsql/src/tsql_analyze.c | 158 +- contrib/babelfishpg_tsql/src/tsql_analyze.h | 2 +- .../babelfishpg_tsql/src/tsql_for/forjson.c | 151 +- .../src/tsql_for/forjson_old.c | 168 +- .../babelfishpg_tsql/src/tsql_for/forxml.c | 207 +- .../src/tsql_for/forxml_old.c | 116 +- .../babelfishpg_tsql/src/tsql_for/tsql_for.c | 17 +- .../babelfishpg_tsql/src/tsql_for/tsql_for.h | 18 +- 170 files changed, 29297 insertions(+), 26116 deletions(-) delete mode 100644 contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.h diff --git a/contrib/babelfishpg_common/src/babelfishpg_common.c b/contrib/babelfishpg_common/src/babelfishpg_common.c index 47afcc99b5..ff199f076c 100644 --- a/contrib/babelfishpg_common/src/babelfishpg_common.c +++ b/contrib/babelfishpg_common/src/babelfishpg_common.c @@ -8,7 +8,7 @@ #include "optimizer/planner.h" #include "parser/parse_collate.h" #include "parser/parse_target.h" -#include "parser/scansup.h" /* downcase_identifier */ +#include "parser/scansup.h" /* downcase_identifier */ #include "utils/guc.h" #include "babelfishpg_common.h" @@ -25,51 +25,57 @@ extern Datum init_tcode_trans_tab(PG_FUNCTION_ARGS); PG_MODULE_MAGIC; -char *pltsql_default_locale = NULL; -char *pltsql_server_collation_name = NULL; +char *pltsql_default_locale = NULL; +char *pltsql_server_collation_name = NULL; /* Dump and Restore */ -char *babelfish_restored_server_collation_name = NULL; +char *babelfish_restored_server_collation_name = NULL; -const char * -BabelfishTranslateCollation( - const char *collname, - Oid collnamespace, - int32 encoding); +const char *BabelfishTranslateCollation( + const char *collname, + Oid collnamespace, + int32 encoding); CLUSTER_COLLATION_OID_hook_type prev_CLUSTER_COLLATION_OID_hook = NULL; TranslateCollation_hook_type prev_TranslateCollation_hook = NULL; PreCreateCollation_hook_type prev_PreCreateCollation_hook = NULL; /* Module callbacks */ -void _PG_init(void); -void _PG_fini(void); +void _PG_init(void); +void _PG_fini(void); -static bool check_server_collation_name(char **newval, void **extra, GucSource source) +static bool +check_server_collation_name(char **newval, void **extra, GucSource source) { if (is_valid_server_collation_name(*newval)) { /* - * We are storing value in lower case since - * Collation names are stored in lowercase into pg catalog (pg_collation). + * We are storing value in lower case since Collation names are stored + * in lowercase into pg catalog (pg_collation). */ - int length = strlen(*newval); + int length = strlen(*newval); + strncpy(*newval, downcase_identifier(*newval, length, false, false), length); return true; } return false; } -static bool check_default_locale (char **newval, void **extra, GucSource source) +static bool +check_default_locale(char **newval, void **extra, GucSource source) { if (find_locale(*newval) >= 0) return true; return false; } -static bool check_restored_server_collation_name(char **newval, void **extra, GucSource source) +static bool +check_restored_server_collation_name(char **newval, void **extra, GucSource source) { - /* NULL should be treated as valid value for babelfishpg_tsql.restored_server_collation_name */ + /* + * NULL should be treated as valid value for + * babelfishpg_tsql.restored_server_collation_name + */ if (*newval == NULL) return true; @@ -79,7 +85,7 @@ static bool check_restored_server_collation_name(char **newval, void **extra, Gu void _PG_init(void) { - FunctionCallInfo fcinfo = NULL; /* empty interface */ + FunctionCallInfo fcinfo = NULL; /* empty interface */ collation_callbacks **coll_cb_ptr; common_utility_plugin **common_utility_plugin_ptr; @@ -92,32 +98,32 @@ _PG_init(void) *common_utility_plugin_ptr = get_common_utility_plugin(); DefineCustomStringVariable("babelfishpg_tsql.server_collation_name", - gettext_noop("Name of the default server collation."), - NULL, - &pltsql_server_collation_name, - "sql_latin1_general_cp1_ci_as", - PGC_SIGHUP, - GUC_NO_RESET_ALL, - check_server_collation_name, NULL, NULL); + gettext_noop("Name of the default server collation."), + NULL, + &pltsql_server_collation_name, + "sql_latin1_general_cp1_ci_as", + PGC_SIGHUP, + GUC_NO_RESET_ALL, + check_server_collation_name, NULL, NULL); DefineCustomStringVariable("babelfishpg_tsql.default_locale", - gettext_noop("The default locale to use when creating a new collation."), - NULL, - &pltsql_default_locale, - "en_US", - PGC_SUSET, /* only superuser can set */ - 0, - check_default_locale, NULL, NULL); + gettext_noop("The default locale to use when creating a new collation."), + NULL, + &pltsql_default_locale, + "en_US", + PGC_SUSET, /* only superuser can set */ + 0, + check_default_locale, NULL, NULL); DefineCustomStringVariable("babelfishpg_tsql.restored_server_collation_name", - gettext_noop("To persist the user defined setting of babelfishpg_tsql.server_collation_name GUC"), - NULL, - &babelfish_restored_server_collation_name, - NULL, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - check_restored_server_collation_name, NULL, NULL); + gettext_noop("To persist the user defined setting of babelfishpg_tsql.server_collation_name GUC"), + NULL, + &babelfish_restored_server_collation_name, + NULL, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + check_restored_server_collation_name, NULL, NULL); handle_type_and_collation_hook = handle_type_and_collation; avoid_collation_override_hook = check_target_type_is_sys_varchar; @@ -146,7 +152,7 @@ _PG_fini(void) common_utility_plugin * get_common_utility_plugin(void) { - if(!common_utility_plugin_var.convertVarcharToSQLVariantByteA) + if (!common_utility_plugin_var.convertVarcharToSQLVariantByteA) { common_utility_plugin_var.convertVarcharToSQLVariantByteA = &convertVarcharToSQLVariantByteA; common_utility_plugin_var.convertIntToSQLVariantByteA = &convertIntToSQLVariantByteA; diff --git a/contrib/babelfishpg_common/src/babelfishpg_common.h b/contrib/babelfishpg_common/src/babelfishpg_common.h index 154be7bf37..9092d2ae38 100644 --- a/contrib/babelfishpg_common/src/babelfishpg_common.h +++ b/contrib/babelfishpg_common/src/babelfishpg_common.h @@ -5,39 +5,39 @@ typedef struct common_utility_plugin { /* Function pointers set up by the plugin */ - bytea* (*convertVarcharToSQLVariantByteA) (VarChar *vch, Oid coll); - bytea* (*convertIntToSQLVariantByteA) (int ret); - void* (*tsql_varchar_input) (const char *s, size_t len, int32 atttypmod); - void* (*tsql_bpchar_input) (const char *s, size_t len, int32 atttypmod); - bool (*is_tsql_bpchar_datatype) (Oid oid); - bool (*is_tsql_nchar_datatype) (Oid oid); - bool (*is_tsql_varchar_datatype) (Oid oid); - bool (*is_tsql_nvarchar_datatype) (Oid oid); - bool (*is_tsql_text_datatype) (Oid oid); - bool (*is_tsql_ntext_datatype) (Oid oid); - bool (*is_tsql_image_datatype) (Oid oid); - bool (*is_tsql_binary_datatype) (Oid oid); - bool (*is_tsql_varbinary_datatype) (Oid oid); - bool (*is_tsql_timestamp_datatype) (Oid oid); - bool (*is_tsql_datetime2_datatype) (Oid oid); - bool (*is_tsql_smalldatetime_datatype) (Oid oid); - bool (*is_tsql_datetimeoffset_datatype) (Oid oid); - bool (*is_tsql_decimal_datatype) (Oid oid); - bool (*is_tsql_rowversion_or_timestamp_datatype) (Oid oid); - Datum (*datetime_in_str) (char *str); - Datum (*datetime2sqlvariant) (PG_FUNCTION_ARGS); - Datum (*tinyint2sqlvariant) (PG_FUNCTION_ARGS); - Datum (*translate_pg_type_to_tsql) (PG_FUNCTION_ARGS); - void (*TdsGetPGbaseType) (uint8 variantBaseType, int *pgBaseType, int tempLen, - int *dataLen, int *variantHeaderLen); - void (*TdsSetMetaData) (bytea *result, int pgBaseType, int scale, - int precision, int maxLen); - int (*TdsPGbaseType) (bytea *vlena); - void (*TdsGetMetaData) (bytea *result, int pgBaseType, int *scale, - int *precision, int *maxLen); - void (*TdsGetVariantBaseType) (int pgBaseType, int *variantBaseType, - bool *isBaseNum, bool *isBaseChar, - bool *isBaseDec, bool *isBaseBin, - bool *isBaseDate, int *variantHeaderLen); - Oid (*lookup_tsql_datatype_oid) (const char *typestr); -} common_utility_plugin; \ No newline at end of file + bytea *(*convertVarcharToSQLVariantByteA) (VarChar *vch, Oid coll); + bytea *(*convertIntToSQLVariantByteA) (int ret); + void *(*tsql_varchar_input) (const char *s, size_t len, int32 atttypmod); + void *(*tsql_bpchar_input) (const char *s, size_t len, int32 atttypmod); + bool (*is_tsql_bpchar_datatype) (Oid oid); + bool (*is_tsql_nchar_datatype) (Oid oid); + bool (*is_tsql_varchar_datatype) (Oid oid); + bool (*is_tsql_nvarchar_datatype) (Oid oid); + bool (*is_tsql_text_datatype) (Oid oid); + bool (*is_tsql_ntext_datatype) (Oid oid); + bool (*is_tsql_image_datatype) (Oid oid); + bool (*is_tsql_binary_datatype) (Oid oid); + bool (*is_tsql_varbinary_datatype) (Oid oid); + bool (*is_tsql_timestamp_datatype) (Oid oid); + bool (*is_tsql_datetime2_datatype) (Oid oid); + bool (*is_tsql_smalldatetime_datatype) (Oid oid); + bool (*is_tsql_datetimeoffset_datatype) (Oid oid); + bool (*is_tsql_decimal_datatype) (Oid oid); + bool (*is_tsql_rowversion_or_timestamp_datatype) (Oid oid); + Datum (*datetime_in_str) (char *str); + Datum (*datetime2sqlvariant) (PG_FUNCTION_ARGS); + Datum (*tinyint2sqlvariant) (PG_FUNCTION_ARGS); + Datum (*translate_pg_type_to_tsql) (PG_FUNCTION_ARGS); + void (*TdsGetPGbaseType) (uint8 variantBaseType, int *pgBaseType, int tempLen, + int *dataLen, int *variantHeaderLen); + void (*TdsSetMetaData) (bytea *result, int pgBaseType, int scale, + int precision, int maxLen); + int (*TdsPGbaseType) (bytea *vlena); + void (*TdsGetMetaData) (bytea *result, int pgBaseType, int *scale, + int *precision, int *maxLen); + void (*TdsGetVariantBaseType) (int pgBaseType, int *variantBaseType, + bool *isBaseNum, bool *isBaseChar, + bool *isBaseDec, bool *isBaseBin, + bool *isBaseDate, int *variantHeaderLen); + Oid (*lookup_tsql_datatype_oid) (const char *typestr); +} common_utility_plugin; diff --git a/contrib/babelfishpg_common/src/bit.c b/contrib/babelfishpg_common/src/bit.c index da2fb159b5..f809365197 100644 --- a/contrib/babelfishpg_common/src/bit.c +++ b/contrib/babelfishpg_common/src/bit.c @@ -92,47 +92,47 @@ parse_bit_with_len(const char *value, size_t len, bool *result) } break; default: - { - int i = 0; - - /* Skip the minus sign */ - if (*value == '-') - i = 1; - /* Is it all 0's? */ - for (; i < len; i++) { - if (value[i] != '0') - break; + int i = 0; + + /* Skip the minus sign */ + if (*value == '-') + i = 1; + /* Is it all 0's? */ + for (; i < len; i++) + { + if (value[i] != '0') + break; + } + /* all 0's */ + if (i == len) + { + if (result) + *result = false; + return true; + } + + /* So it's not all 0's, is it all digits? */ + /* Skip the minus sign */ + if (*value == '-') + i = 1; + else + i = 0; + for (; i < len; i++) + { + if (!isdigit(value[i])) + break; + } + /* all digits and not all 0's, result should be true */ + if (i == len) + { + if (result) + *result = true; + return true; + } + /* not all digits, meaning invalid input */ + break; } - /* all 0's */ - if (i == len) - { - if (result) - *result = false; - return true; - } - - /* So it's not all 0's, is it all digits? */ - /* Skip the minus sign */ - if (*value == '-') - i = 1; - else - i = 0; - for (; i < len; i++) - { - if (!isdigit(value[i])) - break; - } - /* all digits and not all 0's, result should be true */ - if (i == len) - { - if (result) - *result = true; - return true; - } - /* not all digits, meaning invalid input */ - break; - } } if (result) @@ -237,8 +237,8 @@ bitsend(PG_FUNCTION_ARGS) Datum int2bit(PG_FUNCTION_ARGS) { - int input = PG_GETARG_INT16(0); - bool result = input == 0 ? false : true; + int input = PG_GETARG_INT16(0); + bool result = input == 0 ? false : true; PG_RETURN_BOOL(result); } @@ -246,8 +246,8 @@ int2bit(PG_FUNCTION_ARGS) Datum int4bit(PG_FUNCTION_ARGS) { - int32 input = PG_GETARG_INT32(0); - bool result = input == 0 ? false : true; + int32 input = PG_GETARG_INT32(0); + bool result = input == 0 ? false : true; PG_RETURN_BOOL(result); } @@ -255,8 +255,8 @@ int4bit(PG_FUNCTION_ARGS) Datum int8bit(PG_FUNCTION_ARGS) { - int64 input = PG_GETARG_INT64(0); - bool result = input == 0 ? false : true; + int64 input = PG_GETARG_INT64(0); + bool result = input == 0 ? false : true; PG_RETURN_BOOL(result); } @@ -265,8 +265,8 @@ int8bit(PG_FUNCTION_ARGS) Datum ftobit(PG_FUNCTION_ARGS) { - float4 arg = PG_GETARG_FLOAT4(0); - bool result = arg == 0 ? false : true; + float4 arg = PG_GETARG_FLOAT4(0); + bool result = arg == 0 ? false : true; PG_RETURN_BOOL(result); } @@ -275,8 +275,8 @@ ftobit(PG_FUNCTION_ARGS) Datum dtobit(PG_FUNCTION_ARGS) { - float8 arg = PG_GETARG_FLOAT8(0); - bool result = arg == 0 ? false : true; + float8 arg = PG_GETARG_FLOAT8(0); + bool result = arg == 0 ? false : true; PG_RETURN_BOOL(result); } @@ -284,11 +284,11 @@ dtobit(PG_FUNCTION_ARGS) Datum numeric_bit(PG_FUNCTION_ARGS) { - Numeric num = PG_GETARG_NUMERIC(0); - char *tmp; - bool result = false; - int len; - int i; + Numeric num = PG_GETARG_NUMERIC(0); + char *tmp; + bool result = false; + int len; + int i; if (numeric_is_nan(num)) ereport(ERROR, @@ -299,7 +299,7 @@ numeric_bit(PG_FUNCTION_ARGS) NumericGetDatum(num))); len = strlen(tmp); - for(i = 0; i < len; i++) + for (i = 0; i < len; i++) { /* Skip the decimal point */ if (tmp[i] == '.') @@ -318,7 +318,7 @@ numeric_bit(PG_FUNCTION_ARGS) Datum bitneg(PG_FUNCTION_ARGS) { - bool arg = PG_GETARG_BOOL(0); + bool arg = PG_GETARG_BOOL(0); PG_RETURN_BOOL(!arg); } @@ -390,174 +390,174 @@ bit_cmp(PG_FUNCTION_ARGS) Datum int4biteq(PG_FUNCTION_ARGS) { - int input1 = PG_GETARG_INT32(0); - bool arg1 = input1 == 0 ? false : true; - bool arg2 = PG_GETARG_BOOL(1); + int input1 = PG_GETARG_INT32(0); + bool arg1 = input1 == 0 ? false : true; + bool arg2 = PG_GETARG_BOOL(1); - PG_RETURN_BOOL(arg1 == arg2); + PG_RETURN_BOOL(arg1 == arg2); } Datum int4bitne(PG_FUNCTION_ARGS) { - int input1 = PG_GETARG_INT32(0); - bool arg1 = input1 == 0 ? false : true; - bool arg2 = PG_GETARG_BOOL(1); + int input1 = PG_GETARG_INT32(0); + bool arg1 = input1 == 0 ? false : true; + bool arg2 = PG_GETARG_BOOL(1); - PG_RETURN_BOOL(arg1 != arg2); + PG_RETURN_BOOL(arg1 != arg2); } Datum int4bitlt(PG_FUNCTION_ARGS) { - int input1 = PG_GETARG_INT32(0); - bool arg1 = input1 == 0 ? false : true; - bool arg2 = PG_GETARG_BOOL(1); + int input1 = PG_GETARG_INT32(0); + bool arg1 = input1 == 0 ? false : true; + bool arg2 = PG_GETARG_BOOL(1); - PG_RETURN_BOOL(arg1 < arg2); + PG_RETURN_BOOL(arg1 < arg2); } Datum int4bitle(PG_FUNCTION_ARGS) { - int input1 = PG_GETARG_INT32(0); - bool arg1 = input1 == 0 ? false : true; - bool arg2 = PG_GETARG_BOOL(1); + int input1 = PG_GETARG_INT32(0); + bool arg1 = input1 == 0 ? false : true; + bool arg2 = PG_GETARG_BOOL(1); - PG_RETURN_BOOL(arg1 <= arg2); + PG_RETURN_BOOL(arg1 <= arg2); } Datum int4bitgt(PG_FUNCTION_ARGS) { - int input1 = PG_GETARG_INT32(0); - bool arg1 = input1 == 0 ? false : true; - bool arg2 = PG_GETARG_BOOL(1); + int input1 = PG_GETARG_INT32(0); + bool arg1 = input1 == 0 ? false : true; + bool arg2 = PG_GETARG_BOOL(1); - PG_RETURN_BOOL(arg1 > arg2); + PG_RETURN_BOOL(arg1 > arg2); } Datum int4bitge(PG_FUNCTION_ARGS) { - int input1 = PG_GETARG_INT32(0); - bool arg1 = input1 == 0 ? false : true; - bool arg2 = PG_GETARG_BOOL(1); + int input1 = PG_GETARG_INT32(0); + bool arg1 = input1 == 0 ? false : true; + bool arg2 = PG_GETARG_BOOL(1); - PG_RETURN_BOOL(arg1 >= arg2); + PG_RETURN_BOOL(arg1 >= arg2); } /* Comparison between bit and int */ Datum bitint4eq(PG_FUNCTION_ARGS) { - bool arg1 = PG_GETARG_BOOL(0); - int input2 = PG_GETARG_INT32(1); - bool arg2 = input2 == 0 ? false : true; + bool arg1 = PG_GETARG_BOOL(0); + int input2 = PG_GETARG_INT32(1); + bool arg2 = input2 == 0 ? false : true; - PG_RETURN_BOOL(arg1 == arg2); + PG_RETURN_BOOL(arg1 == arg2); } Datum bitint4ne(PG_FUNCTION_ARGS) { - bool arg1 = PG_GETARG_BOOL(0); - int input2 = PG_GETARG_INT32(1); - bool arg2 = input2 == 0 ? false : true; + bool arg1 = PG_GETARG_BOOL(0); + int input2 = PG_GETARG_INT32(1); + bool arg2 = input2 == 0 ? false : true; - PG_RETURN_BOOL(arg1 != arg2); + PG_RETURN_BOOL(arg1 != arg2); } Datum bitint4lt(PG_FUNCTION_ARGS) { - bool arg1 = PG_GETARG_BOOL(0); - int input2 = PG_GETARG_INT32(1); - bool arg2 = input2 == 0 ? false : true; + bool arg1 = PG_GETARG_BOOL(0); + int input2 = PG_GETARG_INT32(1); + bool arg2 = input2 == 0 ? false : true; - PG_RETURN_BOOL(arg1 < arg2); + PG_RETURN_BOOL(arg1 < arg2); } Datum bitint4le(PG_FUNCTION_ARGS) { - bool arg1 = PG_GETARG_BOOL(0); - int input2 = PG_GETARG_INT32(1); - bool arg2 = input2 == 0 ? false : true; + bool arg1 = PG_GETARG_BOOL(0); + int input2 = PG_GETARG_INT32(1); + bool arg2 = input2 == 0 ? false : true; - PG_RETURN_BOOL(arg1 <= arg2); + PG_RETURN_BOOL(arg1 <= arg2); } Datum bitint4gt(PG_FUNCTION_ARGS) { - bool arg1 = PG_GETARG_BOOL(0); - int input2 = PG_GETARG_INT32(1); - bool arg2 = input2 == 0 ? false : true; + bool arg1 = PG_GETARG_BOOL(0); + int input2 = PG_GETARG_INT32(1); + bool arg2 = input2 == 0 ? false : true; - PG_RETURN_BOOL(arg1 > arg2); + PG_RETURN_BOOL(arg1 > arg2); } Datum bitint4ge(PG_FUNCTION_ARGS) { - bool arg1 = PG_GETARG_BOOL(0); - int input2 = PG_GETARG_INT32(1); - bool arg2 = input2 == 0 ? false : true; + bool arg1 = PG_GETARG_BOOL(0); + int input2 = PG_GETARG_INT32(1); + bool arg2 = input2 == 0 ? false : true; - PG_RETURN_BOOL(arg1 >= arg2); + PG_RETURN_BOOL(arg1 >= arg2); } Datum bit2int2(PG_FUNCTION_ARGS) { - bool bit = PG_GETARG_BOOL(0); + bool bit = PG_GETARG_BOOL(0); - PG_RETURN_INT16(bit ? 1 : 0); + PG_RETURN_INT16(bit ? 1 : 0); } Datum bit2int4(PG_FUNCTION_ARGS) { - bool bit = PG_GETARG_BOOL(0); + bool bit = PG_GETARG_BOOL(0); - PG_RETURN_INT32(bit ? 1 : 0); + PG_RETURN_INT32(bit ? 1 : 0); } Datum bit2int8(PG_FUNCTION_ARGS) { - bool bit = PG_GETARG_BOOL(0); + bool bit = PG_GETARG_BOOL(0); - PG_RETURN_INT64(bit ? 1 : 0); + PG_RETURN_INT64(bit ? 1 : 0); } Datum bit2numeric(PG_FUNCTION_ARGS) { - bool bit = PG_GETARG_BOOL(0); - Numeric num = bit ? tsql_set_var_from_str_wrapper("1") : tsql_set_var_from_str_wrapper("0"); + bool bit = PG_GETARG_BOOL(0); + Numeric num = bit ? tsql_set_var_from_str_wrapper("1") : tsql_set_var_from_str_wrapper("0"); - PG_RETURN_NUMERIC(num); + PG_RETURN_NUMERIC(num); } Datum bit2fixeddec(PG_FUNCTION_ARGS) { - bool bit = PG_GETARG_BOOL(0); + bool bit = PG_GETARG_BOOL(0); - PG_RETURN_INT64(bit ? 1*FIXEDDECIMAL_MULTIPLIER : 0); + PG_RETURN_INT64(bit ? 1 * FIXEDDECIMAL_MULTIPLIER : 0); } Datum varchar2bit(PG_FUNCTION_ARGS) { - bool result; - char *str; + bool result; + char *str; - VarChar *source = PG_GETARG_VARCHAR_PP(0); + VarChar *source = PG_GETARG_VARCHAR_PP(0); const char *s_data = VARDATA_ANY(source); - int len = VARSIZE_ANY_EXHDR(source); + int len = VARSIZE_ANY_EXHDR(source); str = (char *) palloc(len + 1); memcpy(str, s_data, len); diff --git a/contrib/babelfishpg_common/src/coerce.c b/contrib/babelfishpg_common/src/coerce.c index 334261d9ea..1b7db188d9 100644 --- a/contrib/babelfishpg_common/src/coerce.c +++ b/contrib/babelfishpg_common/src/coerce.c @@ -9,7 +9,7 @@ #include "postgres.h" #include "access/htup_details.h" -#include "access/parallel.h" /* InitializingParallelWorker */ +#include "access/parallel.h" /* InitializingParallelWorker */ #include "miscadmin.h" #include "catalog/pg_authid.h" #include "catalog/pg_cast.h" @@ -39,8 +39,9 @@ * (i.e. real datatype to integral type - PG uses round but T-SQL uses trunc) */ -// dtrunc in float.c -inline static float8 dtrunc_(float8 arg1) +/* dtrunc in float.c */ +inline static float8 +dtrunc_(float8 arg1) { float8 result; @@ -52,7 +53,8 @@ inline static float8 dtrunc_(float8 arg1) return result; } -inline static float4 ftrunc_(float4 arg1) +inline static float4 +ftrunc_(float4 arg1) { float8 result; @@ -70,7 +72,7 @@ PG_FUNCTION_INFO_V1(dtrunci8); Datum dtrunci8(PG_FUNCTION_ARGS) { - float8 num = PG_GETARG_FLOAT8(0); + float8 num = PG_GETARG_FLOAT8(0); /* * Get rid of any fractional part in the input. This is so we don't fail @@ -95,7 +97,7 @@ PG_FUNCTION_INFO_V1(dtrunci4); Datum dtrunci4(PG_FUNCTION_ARGS) { - float8 num = PG_GETARG_FLOAT8(0); + float8 num = PG_GETARG_FLOAT8(0); /* * Get rid of any fractional part in the input. This is so we don't fail @@ -120,7 +122,7 @@ PG_FUNCTION_INFO_V1(dtrunci2); Datum dtrunci2(PG_FUNCTION_ARGS) { - float8 num = PG_GETARG_FLOAT8(0); + float8 num = PG_GETARG_FLOAT8(0); /* * Get rid of any fractional part in the input. This is so we don't fail @@ -145,7 +147,7 @@ PG_FUNCTION_INFO_V1(ftrunci8); Datum ftrunci8(PG_FUNCTION_ARGS) { - float4 num = PG_GETARG_FLOAT4(0); + float4 num = PG_GETARG_FLOAT4(0); /* * Get rid of any fractional part in the input. This is so we don't fail @@ -170,7 +172,7 @@ PG_FUNCTION_INFO_V1(ftrunci4); Datum ftrunci4(PG_FUNCTION_ARGS) { - float4 num = PG_GETARG_FLOAT4(0); + float4 num = PG_GETARG_FLOAT4(0); /* * Get rid of any fractional part in the input. This is so we don't fail @@ -195,7 +197,7 @@ PG_FUNCTION_INFO_V1(ftrunci2); Datum ftrunci2(PG_FUNCTION_ARGS) { - float4 num = PG_GETARG_FLOAT4(0); + float4 num = PG_GETARG_FLOAT4(0); /* * Get rid of any fractional part in the input. This is so we don't fail @@ -222,9 +224,9 @@ PG_FUNCTION_INFO_V1(pltsql_bpchar_name); Datum pltsql_text_name(PG_FUNCTION_ARGS) { - text *s = PG_GETARG_TEXT_PP(0); - Name result; - int len; + text *s = PG_GETARG_TEXT_PP(0); + Name result; + int len; const char *saved_dialect = GetConfigOption("babelfishpg_tsql.sql_dialect", true, true); len = VARSIZE_ANY_EXHDR(s); @@ -232,28 +234,29 @@ pltsql_text_name(PG_FUNCTION_ARGS) /* Truncate oversize input */ if (len >= NAMEDATALEN) { - if (cstr_to_name_hook) /* to apply special truncation logic */ + if (cstr_to_name_hook) /* to apply special truncation logic */ { - Name n; + Name n; + PG_TRY(); { /* T-SQL casting. follow T-SQL truncation rule */ set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); - n = (*cstr_to_name_hook)(VARDATA_ANY(s), len); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + n = (*cstr_to_name_hook) (VARDATA_ANY(s), len); } PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RE_THROW(); } PG_END_TRY(); set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_NAME(n); } @@ -272,10 +275,10 @@ pltsql_text_name(PG_FUNCTION_ARGS) Datum pltsql_bpchar_name(PG_FUNCTION_ARGS) { - BpChar *s = PG_GETARG_BPCHAR_PP(0); - char *s_data; - Name result; - int len; + BpChar *s = PG_GETARG_BPCHAR_PP(0); + char *s_data; + Name result; + int len; const char *saved_dialect = GetConfigOption("babelfishpg_tsql.sql_dialect", true, true); len = VARSIZE_ANY_EXHDR(s); @@ -284,9 +287,9 @@ pltsql_bpchar_name(PG_FUNCTION_ARGS) /* Truncate oversize input */ if (len >= NAMEDATALEN) { - if (cstr_to_name_hook) /* to apply special truncation logic */ + if (cstr_to_name_hook) /* to apply special truncation logic */ { - Name n; + Name n; /* Remove trailing blanks */ while (len > 0) @@ -300,21 +303,21 @@ pltsql_bpchar_name(PG_FUNCTION_ARGS) { /* T-SQL casting. follow T-SQL truncation rule */ set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); - n = (*cstr_to_name_hook)(VARDATA_ANY(s), len); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + n = (*cstr_to_name_hook) (VARDATA_ANY(s), len); } PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RE_THROW(); } PG_END_TRY(); set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_NAME(n); } diff --git a/contrib/babelfishpg_common/src/collation.c b/contrib/babelfishpg_common/src/collation.c index 85ad04baaa..ac1b0f9edb 100644 --- a/contrib/babelfishpg_common/src/collation.c +++ b/contrib/babelfishpg_common/src/collation.c @@ -27,12 +27,12 @@ collation_callbacks collation_callbacks_var = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; /* Cached values derived from server_collation_name */ -static int server_collation_collidx = NOT_FOUND; -static Oid server_collation_oid = InvalidOid; +static int server_collation_collidx = NOT_FOUND; +static Oid server_collation_oid = InvalidOid; static bool db_collation_is_CI_AS = true; -/* - * Below two vars are defined to store the value of the babelfishpg_tsql.server_collation_name +/* + * Below two vars are defined to store the value of the babelfishpg_tsql.server_collation_name * and babelfishpg_tsql.default_locale. * We only need to lookup and store once because they can not be changed once babelfish db is initialised. */ @@ -40,8 +40,8 @@ static char *server_collation_name = NULL; static const char *bbf_default_locale = NULL; /* Hash tables to help backward searching (from OID to Persist ID) */ -HTAB *ht_like2ilike = NULL; -HTAB *ht_oid2collid = NULL; +HTAB *ht_like2ilike = NULL; +HTAB *ht_oid2collid = NULL; @@ -52,14 +52,14 @@ HTAB *ht_oid2collid = NULL; */ like_ilike_info like_ilike_table[] = { - {0, "~~", "~~*", "pg_catalog", "name", "pg_catalog", "text", false, 0}, - {0, "!~~", "!~~*", "pg_catalog", "name", "pg_catalog", "text", true, 0}, - {0, "~~", "~~*", "pg_catalog", "text", "pg_catalog", "text", false, 0}, - {0, "!~~", "!~~*", "pg_catalog", "text", "pg_catalog", "text", true, 0}, - {0, "~~", "~~*", "pg_catalog", "bpchar", "pg_catalog", "text", false, 0}, - {0, "!~~", "!~~*", "pg_catalog", "bpchar", "pg_catalog", "text", true, 0}, - {0, "~~", "~~*", "sys", "bpchar", "pg_catalog", "text", false, 0}, - {0, "!~~", "!~~*", "sys", "bpchar", "pg_catalog", "text", true, 0}, + {0, "~~", "~~*", "pg_catalog", "name", "pg_catalog", "text", false, 0}, + {0, "!~~", "!~~*", "pg_catalog", "name", "pg_catalog", "text", true, 0}, + {0, "~~", "~~*", "pg_catalog", "text", "pg_catalog", "text", false, 0}, + {0, "!~~", "!~~*", "pg_catalog", "text", "pg_catalog", "text", true, 0}, + {0, "~~", "~~*", "pg_catalog", "bpchar", "pg_catalog", "text", false, 0}, + {0, "!~~", "!~~*", "pg_catalog", "bpchar", "pg_catalog", "text", true, 0}, + {0, "~~", "~~*", "sys", "bpchar", "pg_catalog", "text", false, 0}, + {0, "!~~", "!~~*", "sys", "bpchar", "pg_catalog", "text", true, 0}, }; #define TOTAL_LIKE_OP_COUNT (sizeof(like_ilike_table)/sizeof(like_ilike_table[0])) @@ -69,7 +69,7 @@ like_ilike_info like_ilike_table[] = * below structure for coll_infos sorted lexicographically by collname. * Otherwise it will break collationproperty(). * - * In addition, all collations in this list must have a suffix of the form Cx_Ay, + * In addition, all collations in this list must have a suffix of the form Cx_Ay, * which implies that the CS_AS collation sorts last among collations with the * same collation name prefix. */ @@ -80,41 +80,41 @@ like_ilike_info like_ilike_table[] = */ coll_translate_t coll_translations[] = { - { "latin1_general_100_bin2", "bbf_unicode_bin2", 1252 }, - { "latin1_general_140_bin2", "bbf_unicode_bin2", 1252 }, - { "latin1_general_90_bin2", "bbf_unicode_bin2", 1252 }, - { "latin1_general_bin2", "bbf_unicode_bin2", 1252 }, - { "latin1_general_ci_ai", "bbf_unicode_cp1_ci_ai", 1252 }, - { "latin1_general_ci_as", "bbf_unicode_cp1_ci_as", 1252 }, - { "latin1_general_cs_ai", "bbf_unicode_cp1_cs_ai", 1252 }, - { "latin1_general_cs_as", "bbf_unicode_cp1_cs_as", 1252 }, - { "sql_latin1_general_cp1250_ci_as", "bbf_unicode_cp1250_ci_as", 1250 }, - { "sql_latin1_general_cp1250_cs_as", "bbf_unicode_cp1250_cs_as", 1250 }, - { "sql_latin1_general_cp1251_ci_as", "bbf_unicode_cp1_ci_as", 1251 }, - { "sql_latin1_general_cp1251_cs_as", "bbf_unicode_cp1_cs_as", 1251 }, - { "sql_latin1_general_cp1253_ci_as", "bbf_unicode_cp1253_ci_as", 1253 }, - { "sql_latin1_general_cp1253_cs_as", "bbf_unicode_cp1253_cs_as", 1253 }, - { "sql_latin1_general_cp1254_ci_as", "bbf_unicode_cp1254_ci_as", 1254 }, - { "sql_latin1_general_cp1254_cs_as", "bbf_unicode_cp1254_cs_as", 1254 }, - { "sql_latin1_general_cp1255_ci_as", "bbf_unicode_cp1255_ci_as", 1255 }, - { "sql_latin1_general_cp1255_cs_as", "bbf_unicode_cp1255_cs_as", 1255 }, - { "sql_latin1_general_cp1256_ci_as", "bbf_unicode_cp1256_ci_as", 1256 }, - { "sql_latin1_general_cp1256_cs_as", "bbf_unicode_cp1256_cs_as", 1256 }, - { "sql_latin1_general_cp1257_ci_as", "bbf_unicode_cp1257_ci_as", 1257 }, - { "sql_latin1_general_cp1257_cs_as", "bbf_unicode_cp1257_cs_as", 1257 }, - { "sql_latin1_general_cp1258_ci_as", "bbf_unicode_cp1258_ci_as", 1258 }, - { "sql_latin1_general_cp1258_cs_as", "bbf_unicode_cp1258_cs_as", 1258 }, - { "sql_latin1_general_cp1_ci_ai", "bbf_unicode_cp1_ci_ai", 1252 }, - { "sql_latin1_general_cp1_ci_as", "bbf_unicode_cp1_ci_as", 1252 }, /* default */ - { "sql_latin1_general_cp1_cs_ai", "bbf_unicode_cp1_cs_ai", 1252 }, - { "sql_latin1_general_cp1_cs_as", "bbf_unicode_cp1_cs_as", 1252 }, - - //{ "sql_latin1_general_cp850_ci_as", "bbf_unicode_cp850_ci_as", 850 }, - //{ "sql_latin1_general_cp850_cs_as", "bbf_unicode_cp850_cs_as", 850 }, - - { "sql_latin1_general_cp874_ci_as", "bbf_unicode_cp874_ci_as", 874 }, - { "sql_latin1_general_cp874_cs_as", "bbf_unicode_cp874_cs_as", 874 }, - { "sql_latin1_general_pref_cp1_cs_as", "bbf_unicode_pref_cp1_cs_as", 1252 } + {"latin1_general_100_bin2", "bbf_unicode_bin2", 1252}, + {"latin1_general_140_bin2", "bbf_unicode_bin2", 1252}, + {"latin1_general_90_bin2", "bbf_unicode_bin2", 1252}, + {"latin1_general_bin2", "bbf_unicode_bin2", 1252}, + {"latin1_general_ci_ai", "bbf_unicode_cp1_ci_ai", 1252}, + {"latin1_general_ci_as", "bbf_unicode_cp1_ci_as", 1252}, + {"latin1_general_cs_ai", "bbf_unicode_cp1_cs_ai", 1252}, + {"latin1_general_cs_as", "bbf_unicode_cp1_cs_as", 1252}, + {"sql_latin1_general_cp1250_ci_as", "bbf_unicode_cp1250_ci_as", 1250}, + {"sql_latin1_general_cp1250_cs_as", "bbf_unicode_cp1250_cs_as", 1250}, + {"sql_latin1_general_cp1251_ci_as", "bbf_unicode_cp1_ci_as", 1251}, + {"sql_latin1_general_cp1251_cs_as", "bbf_unicode_cp1_cs_as", 1251}, + {"sql_latin1_general_cp1253_ci_as", "bbf_unicode_cp1253_ci_as", 1253}, + {"sql_latin1_general_cp1253_cs_as", "bbf_unicode_cp1253_cs_as", 1253}, + {"sql_latin1_general_cp1254_ci_as", "bbf_unicode_cp1254_ci_as", 1254}, + {"sql_latin1_general_cp1254_cs_as", "bbf_unicode_cp1254_cs_as", 1254}, + {"sql_latin1_general_cp1255_ci_as", "bbf_unicode_cp1255_ci_as", 1255}, + {"sql_latin1_general_cp1255_cs_as", "bbf_unicode_cp1255_cs_as", 1255}, + {"sql_latin1_general_cp1256_ci_as", "bbf_unicode_cp1256_ci_as", 1256}, + {"sql_latin1_general_cp1256_cs_as", "bbf_unicode_cp1256_cs_as", 1256}, + {"sql_latin1_general_cp1257_ci_as", "bbf_unicode_cp1257_ci_as", 1257}, + {"sql_latin1_general_cp1257_cs_as", "bbf_unicode_cp1257_cs_as", 1257}, + {"sql_latin1_general_cp1258_ci_as", "bbf_unicode_cp1258_ci_as", 1258}, + {"sql_latin1_general_cp1258_cs_as", "bbf_unicode_cp1258_cs_as", 1258}, + {"sql_latin1_general_cp1_ci_ai", "bbf_unicode_cp1_ci_ai", 1252}, + {"sql_latin1_general_cp1_ci_as", "bbf_unicode_cp1_ci_as", 1252}, /* default */ + {"sql_latin1_general_cp1_cs_ai", "bbf_unicode_cp1_cs_ai", 1252}, + {"sql_latin1_general_cp1_cs_as", "bbf_unicode_cp1_cs_as", 1252}, + + /* { "sql_latin1_general_cp850_ci_as", "bbf_unicode_cp850_ci_as", 850 }, */ + /* { "sql_latin1_general_cp850_cs_as", "bbf_unicode_cp850_cs_as", 850 }, */ + + {"sql_latin1_general_cp874_ci_as", "bbf_unicode_cp874_ci_as", 874}, + {"sql_latin1_general_cp874_cs_as", "bbf_unicode_cp874_cs_as", 874}, + {"sql_latin1_general_pref_cp1_cs_as", "bbf_unicode_pref_cp1_cs_as", 1252} }; #define TOTAL_COLL_TRANSLATION_COUNT (sizeof(coll_translations)/sizeof(coll_translations[0])) @@ -126,192 +126,210 @@ coll_translate_t coll_translations[] = */ coll_translate_t reverse_coll_translations[] = { - { "bbf_unicode_cp1_ci_as", "latin1_general_ci_as", 1252 }, /* default */ - { "bbf_unicode_cp1_ci_ai", "latin1_general_ci_ai", 1252 }, - { "bbf_unicode_cp1_cs_ai", "latin1_general_cs_ai", 1252 }, - { "bbf_unicode_cp1_cs_as", "latin1_general_cs_as", 1252 }, - { "bbf_unicode_bin2", "latin1_general_bin2", 1252 }, - { "bbf_unicode_cp1250_ci_as", "sql_latin1_general_cp1250_ci_as", 1250 }, - { "bbf_unicode_cp1250_cs_as", "sql_latin1_general_cp1250_cs_as", 1250 }, - { "bbf_unicode_cp1253_ci_as", "sql_latin1_general_cp1253_ci_as", 1253 }, - { "bbf_unicode_cp1253_cs_as", "sql_latin1_general_cp1253_cs_as", 1253 }, - { "bbf_unicode_cp1254_ci_as", "sql_latin1_general_cp1254_ci_as", 1254 }, - { "bbf_unicode_cp1254_cs_as", "sql_latin1_general_cp1254_cs_as", 1254 }, - { "bbf_unicode_cp1255_ci_as", "sql_latin1_general_cp1255_ci_as", 1255 }, - { "bbf_unicode_cp1255_cs_as", "sql_latin1_general_cp1255_cs_as", 1255 }, - { "bbf_unicode_cp1256_ci_as", "sql_latin1_general_cp1256_ci_as", 1256 }, - { "bbf_unicode_cp1256_cs_as", "sql_latin1_general_cp1256_cs_as", 1256 }, - { "bbf_unicode_cp1257_ci_as", "sql_latin1_general_cp1257_ci_as", 1257 }, - { "bbf_unicode_cp1257_cs_as", "sql_latin1_general_cp1257_cs_as", 1257 }, - { "bbf_unicode_cp1258_ci_as", "sql_latin1_general_cp1258_ci_as", 1258 }, - { "bbf_unicode_cp1258_cs_as", "sql_latin1_general_cp1258_cs_as", 1258 }, - { "bbf_unicode_cp874_ci_as", "sql_latin1_general_cp874_ci_as", 874 }, - { "bbf_unicode_cp874_cs_as", "sql_latin1_general_cp874_cs_as", 874 }, - { "bbf_unicode_pref_cp1_cs_as", "sql_latin1_general_pref_cp1_cs_as", 1252 } + {"bbf_unicode_cp1_ci_as", "latin1_general_ci_as", 1252}, /* default */ + {"bbf_unicode_cp1_ci_ai", "latin1_general_ci_ai", 1252}, + {"bbf_unicode_cp1_cs_ai", "latin1_general_cs_ai", 1252}, + {"bbf_unicode_cp1_cs_as", "latin1_general_cs_as", 1252}, + {"bbf_unicode_bin2", "latin1_general_bin2", 1252}, + {"bbf_unicode_cp1250_ci_as", "sql_latin1_general_cp1250_ci_as", 1250}, + {"bbf_unicode_cp1250_cs_as", "sql_latin1_general_cp1250_cs_as", 1250}, + {"bbf_unicode_cp1253_ci_as", "sql_latin1_general_cp1253_ci_as", 1253}, + {"bbf_unicode_cp1253_cs_as", "sql_latin1_general_cp1253_cs_as", 1253}, + {"bbf_unicode_cp1254_ci_as", "sql_latin1_general_cp1254_ci_as", 1254}, + {"bbf_unicode_cp1254_cs_as", "sql_latin1_general_cp1254_cs_as", 1254}, + {"bbf_unicode_cp1255_ci_as", "sql_latin1_general_cp1255_ci_as", 1255}, + {"bbf_unicode_cp1255_cs_as", "sql_latin1_general_cp1255_cs_as", 1255}, + {"bbf_unicode_cp1256_ci_as", "sql_latin1_general_cp1256_ci_as", 1256}, + {"bbf_unicode_cp1256_cs_as", "sql_latin1_general_cp1256_cs_as", 1256}, + {"bbf_unicode_cp1257_ci_as", "sql_latin1_general_cp1257_ci_as", 1257}, + {"bbf_unicode_cp1257_cs_as", "sql_latin1_general_cp1257_cs_as", 1257}, + {"bbf_unicode_cp1258_ci_as", "sql_latin1_general_cp1258_ci_as", 1258}, + {"bbf_unicode_cp1258_cs_as", "sql_latin1_general_cp1258_cs_as", 1258}, + {"bbf_unicode_cp874_ci_as", "sql_latin1_general_cp874_ci_as", 874}, + {"bbf_unicode_cp874_cs_as", "sql_latin1_general_cp874_cs_as", 874}, + {"bbf_unicode_pref_cp1_cs_as", "sql_latin1_general_pref_cp1_cs_as", 1252} }; #define TOTAL_REVERSE_COLL_TRANSLATION_COUNT (sizeof(reverse_coll_translations)/sizeof(reverse_coll_translations[0])) -coll_info coll_infos[] = +coll_info coll_infos[] = { - {0, "arabic_ci_ai", 1025, 0, 196608, 0, 0x000f, 1256, PG_WIN1256,}, - {0, "arabic_ci_as", 1025, 0, 196608, 0, 0x000d, 1256, PG_WIN1256,}, - {0, "arabic_cs_as", 1025, 0, 196608, 0, 0x000c, 1256, PG_WIN1256,}, - - {0, "bbf_unicode_bin2", 1033, 0, 196608, 54, 0x0220, 1252, PG_WIN1252}, - - {0, "bbf_unicode_cp1250_ci_ai", 1045, 0, 196608, 0, 0x000f, 1250, PG_WIN1250,}, - {0, "bbf_unicode_cp1250_ci_as", 1045, 0, 196608, 0, 0x000d, 1250, PG_WIN1250,}, - {0, "bbf_unicode_cp1250_cs_ai", 1045, 0, 196608, 0, 0x000e, 1250, PG_WIN1250,}, - {0, "bbf_unicode_cp1250_cs_as", 1045, 0, 196608, 0, 0x000c, 1250, PG_WIN1250,}, - - {0, "bbf_unicode_cp1251_ci_ai", 1049, 0, 196608, 0, 0x000f, 1251, PG_WIN1251}, - {0, "bbf_unicode_cp1251_ci_as", 1049, 0, 196608, 0, 0x000d, 1251, PG_WIN1251}, - {0, "bbf_unicode_cp1251_cs_ai", 1049, 0, 196608, 0, 0x000e, 1251, PG_WIN1251}, - {0, "bbf_unicode_cp1251_cs_as", 1049, 0, 196608, 0, 0x000c, 1251, PG_WIN1251}, - - // {0, "bbf_unicode_cp1252_ci_ai", 1033, 0, 196608, 54, 0x000f, 1252, PG_WIN1252}, - // {0, "bbf_unicode_cp1252_ci_as", 1033, 0, 196608, 52, 0x000d, 1252, PG_WIN1252}, - // {0, "bbf_unicode_cp1252_cs_ai", 1033, 0, 196608, 51, 0x000e, 1252, PG_WIN1252}, - // {0, "bbf_unicode_cp1252_cs_as", 1033, 0, 196608, 51, 0x000c, 1252, PG_WIN1252}, - - {0, "bbf_unicode_cp1253_ci_ai", 1032, 0, 196608, 0, 0x000f, 1253, PG_WIN1253}, - {0, "bbf_unicode_cp1253_ci_as", 1032, 0, 196608, 0, 0x000d, 1253, PG_WIN1253}, - {0, "bbf_unicode_cp1253_cs_ai", 1032, 0, 196608, 0, 0x000e, 1253, PG_WIN1253}, - {0, "bbf_unicode_cp1253_cs_as", 1032, 0, 196608, 0, 0x000c, 1253, PG_WIN1253}, - - {0, "bbf_unicode_cp1254_ci_ai", 1055, 0, 196608, 0, 0x000f, 1254, PG_WIN1254}, - {0, "bbf_unicode_cp1254_ci_as", 1055, 0, 196608, 0, 0x000d, 1254, PG_WIN1254}, - {0, "bbf_unicode_cp1254_cs_ai", 1055, 0, 196608, 0, 0x000e, 1254, PG_WIN1254}, - {0, "bbf_unicode_cp1254_cs_as", 1055, 0, 196608, 0, 0x000c, 1254, PG_WIN1254}, - - {0, "bbf_unicode_cp1255_ci_ai", 1037, 0, 196608, 0, 0x000f, 1255, PG_WIN1255}, - {0, "bbf_unicode_cp1255_ci_as", 1037, 0, 196608, 0, 0x000d, 1255, PG_WIN1255}, - {0, "bbf_unicode_cp1255_cs_ai", 1037, 0, 196608, 0, 0x000e, 1255, PG_WIN1255}, - {0, "bbf_unicode_cp1255_cs_as", 1037, 0, 196608, 0, 0x000c, 1255, PG_WIN1255}, - - {0, "bbf_unicode_cp1256_ci_ai", 1025, 0, 196608, 0, 0x000f, 1256, PG_WIN1256,}, - {0, "bbf_unicode_cp1256_ci_as", 1025, 0, 196608, 0, 0x000d, 1256, PG_WIN1256,}, - {0, "bbf_unicode_cp1256_cs_ai", 1025, 0, 196608, 0, 0x000e, 1256, PG_WIN1256,}, - {0, "bbf_unicode_cp1256_cs_as", 1025, 0, 196608, 0, 0x000c, 1256, PG_WIN1256,}, - - {0, "bbf_unicode_cp1257_ci_ai", 1061, 0, 196608, 0, 0x000f, 1257, PG_WIN1257}, - {0, "bbf_unicode_cp1257_ci_as", 1061, 0, 196608, 0, 0x000d, 1257, PG_WIN1257}, - {0, "bbf_unicode_cp1257_cs_ai", 1061, 0, 196608, 0, 0x000e, 1257, PG_WIN1257}, - {0, "bbf_unicode_cp1257_cs_as", 1061, 0, 196608, 0, 0x000c, 1257, PG_WIN1257}, - - {0, "bbf_unicode_cp1258_ci_ai", 1066, 0, 196608, 0, 0x000f, 1258, PG_WIN1258}, - {0, "bbf_unicode_cp1258_ci_as", 1066, 0, 196608, 0, 0x000d, 1258, PG_WIN1258}, - {0, "bbf_unicode_cp1258_cs_ai", 1066, 0, 196608, 0, 0x000e, 1258, PG_WIN1258}, - {0, "bbf_unicode_cp1258_cs_as", 1066, 0, 196608, 0, 0x000c, 1258, PG_WIN1258}, - - {0, "bbf_unicode_cp1_ci_ai", 1033, 0, 196608, 54, 0x000f, 1252, PG_WIN1252}, - {0, "bbf_unicode_cp1_ci_as", 1033, 0, 196608, 52, 0x000d, 1252, PG_WIN1252}, /* default */ - {0, "bbf_unicode_cp1_cs_ai", 1033, 0, 196608, 51, 0x000e, 1252, PG_WIN1252}, - {0, "bbf_unicode_cp1_cs_as", 1033, 0, 196608, 51, 0x000c, 1252, PG_WIN1252}, - - // {0, "bbf_unicode_cp850_ci_ai", 1033, 0, 196608, 54, 0x000f, 850}, - // {0, "bbf_unicode_cp850_ci_as", 1033, 0, 196608, 52, 0x000d, 850}, - // {0, "bbf_unicode_cp850_cs_ai", 1033, 0, 196608, 51, 0x000e, 850}, - // {0, "bbf_unicode_cp850_cs_as", 1033, 0, 196608, 51, 0x000c, 850}, - - {0, "bbf_unicode_cp874_ci_ai", 1054, 0, 196608, 0, 0x000f, 874, PG_WIN874}, - {0, "bbf_unicode_cp874_ci_as", 1054, 0, 196608, 0, 0x000d, 874, PG_WIN874}, - {0, "bbf_unicode_cp874_cs_ai", 1054, 0, 196608, 0, 0x000e, 874, PG_WIN874}, - {0, "bbf_unicode_cp874_cs_as", 1054, 0, 196608, 0, 0x000c, 874, PG_WIN874}, - - /* For the bbf_unicode_general collations, set lcid and codepage based on babelfishpg_tsql.default_locale */ - {0, "bbf_unicode_general_ci_ai", 1033, 0, 196608, 0, 0x000f, 0}, - {0, "bbf_unicode_general_ci_as", 1033, 0, 196608, 0, 0x000d, 0}, - {0, "bbf_unicode_general_cs_ai", 1033, 0, 196608, 0, 0x000e, 0}, - {0, "bbf_unicode_general_cs_as", 1033, 0, 196608, 0, 0x000c, 0}, - - /* pref collations */ - {0, "bbf_unicode_general_pref_cs_as", 1033, 0, 196608, 0, 0x000c, 0}, - {0, "bbf_unicode_pref_cp1250_cs_as", 1045, 0, 196608, 0, 0x000c, 1250, PG_WIN1250,}, - {0, "bbf_unicode_pref_cp1251_cs_as", 1049, 0, 196608, 0, 0x000c, 1251, PG_WIN1251}, - {0, "bbf_unicode_pref_cp1253_cs_as", 1032, 0, 196608, 0, 0x000c, 1253, PG_WIN1253}, - {0, "bbf_unicode_pref_cp1254_cs_as", 1055, 0, 196608, 0, 0x000c, 1254, PG_WIN1254}, - {0, "bbf_unicode_pref_cp1255_cs_as", 1037, 0, 196608, 0, 0x000c, 1255, PG_WIN1255}, - {0, "bbf_unicode_pref_cp1256_cs_as", 1025, 0, 196608, 0, 0x000c, 1256, PG_WIN1256,}, - {0, "bbf_unicode_pref_cp1257_cs_as", 1061, 0, 196608, 0, 0x000c, 1257, PG_WIN1257}, - {0, "bbf_unicode_pref_cp1258_cs_as", 1066, 0, 196608, 0, 0x000c, 1258, PG_WIN1258}, - {0, "bbf_unicode_pref_cp1_cs_as", 1033, 0, 196608, 51, 0x000c, 1252, PG_WIN1252,}, - // {0, "bbf_unicode_pref_cp850_cs_as", 1033, 0, 196608, 51, 0x000c, 850}, - {0, "bbf_unicode_pref_cp874_cs_as", 1054, 0, 196608, 0, 0x000c, 874, PG_WIN874}, - - {0, "chinese_prc_ci_ai", 2052, 0, 196608, 0, 0x000f, 936, PG_GBK}, - {0, "chinese_prc_ci_as", 2052, 0, 196608, 0, 0x000d, 936, PG_GBK}, - {0, "chinese_prc_cs_as", 2052, 0, 196608, 0, 0x000c, 936, PG_GBK}, - - {0, "cyrillic_general_ci_ai", 1049, 0, 196608, 0, 0x000f, 1251, PG_WIN1251}, - {0, "cyrillic_general_ci_as", 1049, 0, 196608, 0, 0x000d, 1251, PG_WIN1251}, - {0, "cyrillic_general_cs_as", 1049, 0, 196608, 0, 0x000c, 1251, PG_WIN1251}, - - {0, "estonian_ci_ai", 1061, 0, 196608, 0, 0x000f, 1257, PG_WIN1257}, - {0, "estonian_ci_as", 1061, 0, 196608, 0, 0x000d, 1257, PG_WIN1257}, - {0, "estonian_cs_as", 1061, 0, 196608, 0, 0x000c, 1257, PG_WIN1257}, - - {0, "finnish_swedish_ci_ai", 1035, 0, 196608, 0, 0x000f, 1252, PG_WIN1252,}, - {0, "finnish_swedish_ci_as", 1035, 0, 196608, 0, 0x000d, 1252, PG_WIN1252,}, - {0, "finnish_swedish_cs_as", 1035, 0, 196608, 0, 0x000c, 1252, PG_WIN1252,}, - - {0, "french_ci_ai", 1036, 0, 196608, 0, 0x000f, 1252, PG_WIN1252,}, - {0, "french_ci_as", 1036, 0, 196608, 0, 0x000d, 1252, PG_WIN1252,}, - {0, "french_cs_as", 1036, 0, 196608, 0, 0x000c, 1252, PG_WIN1252,}, - - {0, "greek_ci_ai", 1032, 0, 196608, 0, 0x000f, 1253, PG_WIN1253}, - {0, "greek_ci_as", 1032, 0, 196608, 0, 0x000d, 1253, PG_WIN1253}, - {0, "greek_cs_as", 1032, 0, 196608, 0, 0x000c, 1253, PG_WIN1253}, - - {0, "hebrew_ci_ai", 1037, 0, 196608, 0, 0x000f, 1255, PG_WIN1255}, - {0, "hebrew_ci_as", 1037, 0, 196608, 0, 0x000d, 1255, PG_WIN1255}, - {0, "hebrew_cs_as", 1037, 0, 196608, 0, 0x000c, 1255, PG_WIN1255}, - - {0, "japanese_ci_ai", 1041, 0, 196608, 0, 0x000f, 932, PG_SJIS}, - {0, "japanese_ci_as", 1041, 0, 196608, 0, 0x000d, 932, PG_SJIS}, - {0, "japanese_cs_as", 1041, 0, 196608, 0, 0x000c, 932, PG_SJIS}, - - {0, "korean_wansung_ci_ai", 1042, 0, 196608, 0, 0x000f, 949, PG_UHC}, - {0, "korean_wansung_ci_as", 1042, 0, 196608, 0, 0x000d, 949, PG_UHC}, - {0, "korean_wansung_cs_as", 1042, 0, 196608, 0, 0x000c, 949, PG_UHC}, - - {0, "modern_spanish_ci_ai", 3082, 0, 196608, 0, 0x000f, 1252, PG_WIN1252,}, - {0, "modern_spanish_ci_as", 3082, 0, 196608, 0, 0x000d, 1252, PG_WIN1252,}, - {0, "modern_spanish_cs_as", 3082, 0, 196608, 0, 0x000c, 1252, PG_WIN1252,}, - - {0, "mongolian_ci_ai", 1104, 0, 196608, 0, 0x000f, 1251, PG_WIN1251}, - {0, "mongolian_ci_as", 1104, 0, 196608, 0, 0x000d, 1251, PG_WIN1251}, - {0, "mongolian_cs_as", 1104, 0, 196608, 0, 0x000c, 1251, PG_WIN1251}, - - {0, "polish_ci_ai", 1045, 0, 196608, 0, 0x000f, 1250, PG_WIN1250,}, - {0, "polish_ci_as", 1045, 0, 196608, 0, 0x000d, 1250, PG_WIN1250,}, - {0, "polish_cs_as", 1045, 0, 196608, 0, 0x000c, 1250, PG_WIN1250,}, - - {0, "thai_ci_ai", 1054, 0, 196608, 0, 0x000f, 874, PG_WIN874}, - {0, "thai_ci_as", 1054, 0, 196608, 0, 0x000d, 874, PG_WIN874}, - {0, "thai_cs_as", 1054, 0, 196608, 0, 0x000c, 874, PG_WIN874}, - - {0, "traditional_spanish_ci_ai", 1034, 0, 196608, 0, 0x000f, 1252, PG_WIN1252,}, - {0, "traditional_spanish_ci_as", 1034, 0, 196608, 0, 0x000d, 1252, PG_WIN1252,}, - {0, "traditional_spanish_cs_as", 1034, 0, 196608, 0, 0x000c, 1252, PG_WIN1252,}, - - {0, "turkish_ci_ai", 1055, 0, 196608, 0, 0x000f, 1254, PG_WIN1254}, - {0, "turkish_ci_as", 1055, 0, 196608, 0, 0x000d, 1254, PG_WIN1254}, - {0, "turkish_cs_as", 1055, 0, 196608, 0, 0x000c, 1254, PG_WIN1254}, - - {0, "ukrainian_ci_ai", 1058, 0, 196608, 0, 0x000f, 1251, PG_WIN1251}, - {0, "ukrainian_ci_as", 1058, 0, 196608, 0, 0x000d, 1251, PG_WIN1251}, - {0, "ukrainian_cs_as", 1058, 0, 196608, 0, 0x000c, 1251, PG_WIN1251}, - - {0, "vietnamese_ci_ai", 1066, 0, 196608, 0, 0x000f, 1258, PG_WIN1258}, - {0, "vietnamese_ci_as", 1066, 0, 196608, 0, 0x000d, 1258, PG_WIN1258}, - {0, "vietnamese_cs_as", 1066, 0, 196608, 0, 0x000c, 1258, PG_WIN1258}, + {0, "arabic_ci_ai", 1025, 0, 196608, 0, 0x000f, 1256, PG_WIN1256,}, + {0, "arabic_ci_as", 1025, 0, 196608, 0, 0x000d, 1256, PG_WIN1256,}, + {0, "arabic_cs_as", 1025, 0, 196608, 0, 0x000c, 1256, PG_WIN1256,}, + + {0, "bbf_unicode_bin2", 1033, 0, 196608, 54, 0x0220, 1252, PG_WIN1252}, + + {0, "bbf_unicode_cp1250_ci_ai", 1045, 0, 196608, 0, 0x000f, 1250, PG_WIN1250,}, + {0, "bbf_unicode_cp1250_ci_as", 1045, 0, 196608, 0, 0x000d, 1250, PG_WIN1250,}, + {0, "bbf_unicode_cp1250_cs_ai", 1045, 0, 196608, 0, 0x000e, 1250, PG_WIN1250,}, + {0, "bbf_unicode_cp1250_cs_as", 1045, 0, 196608, 0, 0x000c, 1250, PG_WIN1250,}, + + {0, "bbf_unicode_cp1251_ci_ai", 1049, 0, 196608, 0, 0x000f, 1251, PG_WIN1251}, + {0, "bbf_unicode_cp1251_ci_as", 1049, 0, 196608, 0, 0x000d, 1251, PG_WIN1251}, + {0, "bbf_unicode_cp1251_cs_ai", 1049, 0, 196608, 0, 0x000e, 1251, PG_WIN1251}, + {0, "bbf_unicode_cp1251_cs_as", 1049, 0, 196608, 0, 0x000c, 1251, PG_WIN1251}, + + /* + * {0, "bbf_unicode_cp1252_ci_ai", 1033, 0, 196608, 54, 0x000f, 1252, + * PG_WIN1252}, + */ + + /* + * {0, "bbf_unicode_cp1252_ci_as", 1033, 0, 196608, 52, 0x000d, 1252, + * PG_WIN1252}, + */ + + /* + * {0, "bbf_unicode_cp1252_cs_ai", 1033, 0, 196608, 51, 0x000e, 1252, + * PG_WIN1252}, + */ + + /* + * {0, "bbf_unicode_cp1252_cs_as", 1033, 0, 196608, 51, 0x000c, 1252, + * PG_WIN1252}, + */ + + {0, "bbf_unicode_cp1253_ci_ai", 1032, 0, 196608, 0, 0x000f, 1253, PG_WIN1253}, + {0, "bbf_unicode_cp1253_ci_as", 1032, 0, 196608, 0, 0x000d, 1253, PG_WIN1253}, + {0, "bbf_unicode_cp1253_cs_ai", 1032, 0, 196608, 0, 0x000e, 1253, PG_WIN1253}, + {0, "bbf_unicode_cp1253_cs_as", 1032, 0, 196608, 0, 0x000c, 1253, PG_WIN1253}, + + {0, "bbf_unicode_cp1254_ci_ai", 1055, 0, 196608, 0, 0x000f, 1254, PG_WIN1254}, + {0, "bbf_unicode_cp1254_ci_as", 1055, 0, 196608, 0, 0x000d, 1254, PG_WIN1254}, + {0, "bbf_unicode_cp1254_cs_ai", 1055, 0, 196608, 0, 0x000e, 1254, PG_WIN1254}, + {0, "bbf_unicode_cp1254_cs_as", 1055, 0, 196608, 0, 0x000c, 1254, PG_WIN1254}, + + {0, "bbf_unicode_cp1255_ci_ai", 1037, 0, 196608, 0, 0x000f, 1255, PG_WIN1255}, + {0, "bbf_unicode_cp1255_ci_as", 1037, 0, 196608, 0, 0x000d, 1255, PG_WIN1255}, + {0, "bbf_unicode_cp1255_cs_ai", 1037, 0, 196608, 0, 0x000e, 1255, PG_WIN1255}, + {0, "bbf_unicode_cp1255_cs_as", 1037, 0, 196608, 0, 0x000c, 1255, PG_WIN1255}, + + {0, "bbf_unicode_cp1256_ci_ai", 1025, 0, 196608, 0, 0x000f, 1256, PG_WIN1256,}, + {0, "bbf_unicode_cp1256_ci_as", 1025, 0, 196608, 0, 0x000d, 1256, PG_WIN1256,}, + {0, "bbf_unicode_cp1256_cs_ai", 1025, 0, 196608, 0, 0x000e, 1256, PG_WIN1256,}, + {0, "bbf_unicode_cp1256_cs_as", 1025, 0, 196608, 0, 0x000c, 1256, PG_WIN1256,}, + + {0, "bbf_unicode_cp1257_ci_ai", 1061, 0, 196608, 0, 0x000f, 1257, PG_WIN1257}, + {0, "bbf_unicode_cp1257_ci_as", 1061, 0, 196608, 0, 0x000d, 1257, PG_WIN1257}, + {0, "bbf_unicode_cp1257_cs_ai", 1061, 0, 196608, 0, 0x000e, 1257, PG_WIN1257}, + {0, "bbf_unicode_cp1257_cs_as", 1061, 0, 196608, 0, 0x000c, 1257, PG_WIN1257}, + + {0, "bbf_unicode_cp1258_ci_ai", 1066, 0, 196608, 0, 0x000f, 1258, PG_WIN1258}, + {0, "bbf_unicode_cp1258_ci_as", 1066, 0, 196608, 0, 0x000d, 1258, PG_WIN1258}, + {0, "bbf_unicode_cp1258_cs_ai", 1066, 0, 196608, 0, 0x000e, 1258, PG_WIN1258}, + {0, "bbf_unicode_cp1258_cs_as", 1066, 0, 196608, 0, 0x000c, 1258, PG_WIN1258}, + + {0, "bbf_unicode_cp1_ci_ai", 1033, 0, 196608, 54, 0x000f, 1252, PG_WIN1252}, + {0, "bbf_unicode_cp1_ci_as", 1033, 0, 196608, 52, 0x000d, 1252, PG_WIN1252}, /* default */ + {0, "bbf_unicode_cp1_cs_ai", 1033, 0, 196608, 51, 0x000e, 1252, PG_WIN1252}, + {0, "bbf_unicode_cp1_cs_as", 1033, 0, 196608, 51, 0x000c, 1252, PG_WIN1252}, + + /* {0, "bbf_unicode_cp850_ci_ai", 1033, 0, 196608, 54, 0x000f, 850}, */ + /* {0, "bbf_unicode_cp850_ci_as", 1033, 0, 196608, 52, 0x000d, 850}, */ + /* {0, "bbf_unicode_cp850_cs_ai", 1033, 0, 196608, 51, 0x000e, 850}, */ + /* {0, "bbf_unicode_cp850_cs_as", 1033, 0, 196608, 51, 0x000c, 850}, */ + + {0, "bbf_unicode_cp874_ci_ai", 1054, 0, 196608, 0, 0x000f, 874, PG_WIN874}, + {0, "bbf_unicode_cp874_ci_as", 1054, 0, 196608, 0, 0x000d, 874, PG_WIN874}, + {0, "bbf_unicode_cp874_cs_ai", 1054, 0, 196608, 0, 0x000e, 874, PG_WIN874}, + {0, "bbf_unicode_cp874_cs_as", 1054, 0, 196608, 0, 0x000c, 874, PG_WIN874}, + + /* + * For the bbf_unicode_general collations, set lcid and codepage based on + * babelfishpg_tsql.default_locale + */ + {0, "bbf_unicode_general_ci_ai", 1033, 0, 196608, 0, 0x000f, 0}, + {0, "bbf_unicode_general_ci_as", 1033, 0, 196608, 0, 0x000d, 0}, + {0, "bbf_unicode_general_cs_ai", 1033, 0, 196608, 0, 0x000e, 0}, + {0, "bbf_unicode_general_cs_as", 1033, 0, 196608, 0, 0x000c, 0}, + + /* pref collations */ + {0, "bbf_unicode_general_pref_cs_as", 1033, 0, 196608, 0, 0x000c, 0}, + {0, "bbf_unicode_pref_cp1250_cs_as", 1045, 0, 196608, 0, 0x000c, 1250, PG_WIN1250,}, + {0, "bbf_unicode_pref_cp1251_cs_as", 1049, 0, 196608, 0, 0x000c, 1251, PG_WIN1251}, + {0, "bbf_unicode_pref_cp1253_cs_as", 1032, 0, 196608, 0, 0x000c, 1253, PG_WIN1253}, + {0, "bbf_unicode_pref_cp1254_cs_as", 1055, 0, 196608, 0, 0x000c, 1254, PG_WIN1254}, + {0, "bbf_unicode_pref_cp1255_cs_as", 1037, 0, 196608, 0, 0x000c, 1255, PG_WIN1255}, + {0, "bbf_unicode_pref_cp1256_cs_as", 1025, 0, 196608, 0, 0x000c, 1256, PG_WIN1256,}, + {0, "bbf_unicode_pref_cp1257_cs_as", 1061, 0, 196608, 0, 0x000c, 1257, PG_WIN1257}, + {0, "bbf_unicode_pref_cp1258_cs_as", 1066, 0, 196608, 0, 0x000c, 1258, PG_WIN1258}, + {0, "bbf_unicode_pref_cp1_cs_as", 1033, 0, 196608, 51, 0x000c, 1252, PG_WIN1252,}, + /* {0, "bbf_unicode_pref_cp850_cs_as", 1033, 0, 196608, 51, 0x000c, 850}, */ + {0, "bbf_unicode_pref_cp874_cs_as", 1054, 0, 196608, 0, 0x000c, 874, PG_WIN874}, + + {0, "chinese_prc_ci_ai", 2052, 0, 196608, 0, 0x000f, 936, PG_GBK}, + {0, "chinese_prc_ci_as", 2052, 0, 196608, 0, 0x000d, 936, PG_GBK}, + {0, "chinese_prc_cs_as", 2052, 0, 196608, 0, 0x000c, 936, PG_GBK}, + + {0, "cyrillic_general_ci_ai", 1049, 0, 196608, 0, 0x000f, 1251, PG_WIN1251}, + {0, "cyrillic_general_ci_as", 1049, 0, 196608, 0, 0x000d, 1251, PG_WIN1251}, + {0, "cyrillic_general_cs_as", 1049, 0, 196608, 0, 0x000c, 1251, PG_WIN1251}, + + {0, "estonian_ci_ai", 1061, 0, 196608, 0, 0x000f, 1257, PG_WIN1257}, + {0, "estonian_ci_as", 1061, 0, 196608, 0, 0x000d, 1257, PG_WIN1257}, + {0, "estonian_cs_as", 1061, 0, 196608, 0, 0x000c, 1257, PG_WIN1257}, + + {0, "finnish_swedish_ci_ai", 1035, 0, 196608, 0, 0x000f, 1252, PG_WIN1252,}, + {0, "finnish_swedish_ci_as", 1035, 0, 196608, 0, 0x000d, 1252, PG_WIN1252,}, + {0, "finnish_swedish_cs_as", 1035, 0, 196608, 0, 0x000c, 1252, PG_WIN1252,}, + + {0, "french_ci_ai", 1036, 0, 196608, 0, 0x000f, 1252, PG_WIN1252,}, + {0, "french_ci_as", 1036, 0, 196608, 0, 0x000d, 1252, PG_WIN1252,}, + {0, "french_cs_as", 1036, 0, 196608, 0, 0x000c, 1252, PG_WIN1252,}, + + {0, "greek_ci_ai", 1032, 0, 196608, 0, 0x000f, 1253, PG_WIN1253}, + {0, "greek_ci_as", 1032, 0, 196608, 0, 0x000d, 1253, PG_WIN1253}, + {0, "greek_cs_as", 1032, 0, 196608, 0, 0x000c, 1253, PG_WIN1253}, + + {0, "hebrew_ci_ai", 1037, 0, 196608, 0, 0x000f, 1255, PG_WIN1255}, + {0, "hebrew_ci_as", 1037, 0, 196608, 0, 0x000d, 1255, PG_WIN1255}, + {0, "hebrew_cs_as", 1037, 0, 196608, 0, 0x000c, 1255, PG_WIN1255}, + + {0, "japanese_ci_ai", 1041, 0, 196608, 0, 0x000f, 932, PG_SJIS}, + {0, "japanese_ci_as", 1041, 0, 196608, 0, 0x000d, 932, PG_SJIS}, + {0, "japanese_cs_as", 1041, 0, 196608, 0, 0x000c, 932, PG_SJIS}, + + {0, "korean_wansung_ci_ai", 1042, 0, 196608, 0, 0x000f, 949, PG_UHC}, + {0, "korean_wansung_ci_as", 1042, 0, 196608, 0, 0x000d, 949, PG_UHC}, + {0, "korean_wansung_cs_as", 1042, 0, 196608, 0, 0x000c, 949, PG_UHC}, + + {0, "modern_spanish_ci_ai", 3082, 0, 196608, 0, 0x000f, 1252, PG_WIN1252,}, + {0, "modern_spanish_ci_as", 3082, 0, 196608, 0, 0x000d, 1252, PG_WIN1252,}, + {0, "modern_spanish_cs_as", 3082, 0, 196608, 0, 0x000c, 1252, PG_WIN1252,}, + + {0, "mongolian_ci_ai", 1104, 0, 196608, 0, 0x000f, 1251, PG_WIN1251}, + {0, "mongolian_ci_as", 1104, 0, 196608, 0, 0x000d, 1251, PG_WIN1251}, + {0, "mongolian_cs_as", 1104, 0, 196608, 0, 0x000c, 1251, PG_WIN1251}, + + {0, "polish_ci_ai", 1045, 0, 196608, 0, 0x000f, 1250, PG_WIN1250,}, + {0, "polish_ci_as", 1045, 0, 196608, 0, 0x000d, 1250, PG_WIN1250,}, + {0, "polish_cs_as", 1045, 0, 196608, 0, 0x000c, 1250, PG_WIN1250,}, + + {0, "thai_ci_ai", 1054, 0, 196608, 0, 0x000f, 874, PG_WIN874}, + {0, "thai_ci_as", 1054, 0, 196608, 0, 0x000d, 874, PG_WIN874}, + {0, "thai_cs_as", 1054, 0, 196608, 0, 0x000c, 874, PG_WIN874}, + + {0, "traditional_spanish_ci_ai", 1034, 0, 196608, 0, 0x000f, 1252, PG_WIN1252,}, + {0, "traditional_spanish_ci_as", 1034, 0, 196608, 0, 0x000d, 1252, PG_WIN1252,}, + {0, "traditional_spanish_cs_as", 1034, 0, 196608, 0, 0x000c, 1252, PG_WIN1252,}, + + {0, "turkish_ci_ai", 1055, 0, 196608, 0, 0x000f, 1254, PG_WIN1254}, + {0, "turkish_ci_as", 1055, 0, 196608, 0, 0x000d, 1254, PG_WIN1254}, + {0, "turkish_cs_as", 1055, 0, 196608, 0, 0x000c, 1254, PG_WIN1254}, + + {0, "ukrainian_ci_ai", 1058, 0, 196608, 0, 0x000f, 1251, PG_WIN1251}, + {0, "ukrainian_ci_as", 1058, 0, 196608, 0, 0x000d, 1251, PG_WIN1251}, + {0, "ukrainian_cs_as", 1058, 0, 196608, 0, 0x000c, 1251, PG_WIN1251}, + + {0, "vietnamese_ci_ai", 1066, 0, 196608, 0, 0x000f, 1258, PG_WIN1258}, + {0, "vietnamese_ci_as", 1066, 0, 196608, 0, 0x000d, 1258, PG_WIN1258}, + {0, "vietnamese_cs_as", 1066, 0, 196608, 0, 0x000c, 1258, PG_WIN1258}, }; #define TOTAL_COLL_COUNT (sizeof(coll_infos)/sizeof(coll_infos[0])) -/* +/* * ICU locales: * https://www.localeplanet.com/icu/ * @@ -319,138 +337,138 @@ coll_info coll_infos[] = */ locale_info locales[] = { - {0x0436, 1252, PG_WIN1252, "af-ZA"}, // Afrikaans: South Africa - {0x041c, 1250, PG_WIN1250, "sq-AL"}, // Albanian: Albania - {0x1401, 1256, PG_WIN1256, "ar-DZ"}, // Arabic: Algeria - {0x3c01, 1256, PG_WIN1256, "ar-BH"}, // Arabic: Bahrain - {0x0c01, 1256, PG_WIN1256, "ar-EG"}, // Arabic: Egypt - {0x0801, 1256, PG_WIN1256, "ar-IQ"}, // Arabic: Iraq - {0x2c01, 1256, PG_WIN1256, "ar-JO"}, // Arabic: Jordan - {0x3401, 1256, PG_WIN1256, "ar-KW"}, // Arabic: Kuwait - {0x3001, 1256, PG_WIN1256, "ar-LB"}, // Arabic: Lebanon - {0x1001, 1256, PG_WIN1256, "ar-LY"}, // Arabic: Libya - {0x1801, 1256, PG_WIN1256, "ar-MA"}, // Arabic: Morocco - {0x2001, 1256, PG_WIN1256, "ar-OM"}, // Arabic: Oman - {0x4001, 1256, PG_WIN1256, "ar-QA"}, // Arabic: Qatar - {0x0401, 1256, PG_WIN1256, "ar-SA"}, // Arabic: Saudi Arabia - {0x2801, 1256, PG_WIN1256, "ar-SY"}, //Arabic: Syria - {0x1c01, 1256, PG_WIN1256, "ar-TN"}, // Arabic: Tunisia - {0x3801, 1256, PG_WIN1256, "ar-AE"}, // Arabic: U.A.E. - {0x2401, 1256, PG_WIN1256, "ar-YE"}, // Arabic: Yemen - // {0x042b, 0, "hy-AM"}, // Armenian: Armenia - {0x082c, 1251, PG_WIN1251, "az-Cyrl-AZ"}, // Azeri: Azerbaijan (Cyrillic) - {0x042c, 1250, PG_WIN1250, "az-Latn-AZ"}, // Azeri: Azerbaijan (Latin) - {0x042d, 1252, PG_WIN1252, "eu-ES"}, // Basque: Spain - {0x0423, 1251, PG_WIN1251, "be-BY"}, // Belarusian: Belarus - {0x0402, 1251, PG_WIN1251, "bg-BG"}, // Bulgarian: Bulgaria - {0x0403, 1252, PG_WIN1252, "ca-ES"}, // Catalan: Spain - {0x0c04, 950, PG_BIG5, "zh-HK"}, // Chinese: Hong Kong SAR, PRC (Traditional) - {0x1404, 950, PG_BIG5, "zh-MO"}, // Chinese: Macao SAR (Traditional) - {0x0804, 936, PG_GBK, "zh-CN"}, // Chinese: PRC (Simplified) - {0x1004, 936, PG_GBK, "zh-SG"}, // Chinese: Singapore (Simplified) - {0x0404, 950, PG_BIG5, "zh-TW"}, // Chinese: Taiwan (Traditional) - // {0x0827, 1257, PG_WIN1257, Classic Lithuanian: Lithuania - {0x041a, 1250, PG_WIN1250, "hr-HR"}, // Croatian: Croatia - {0x0405, 1250, PG_WIN1250, "cs-CZ"}, // Czech: Czech Republic - {0x0406, 1252, PG_WIN1252, "da-DK"}, // Danish: Denmark - {0x0813, 1252, PG_WIN1252, "nl-BE"}, // Dutch: Belgium - {0x0413, 1252, PG_WIN1252, "nl-NL"}, // Dutch: Netherlands - {0x0c09, 1252, PG_WIN1252, "en-AU"}, // English: Australia - {0x2809, 1252, PG_WIN1252, "en-BZ"}, // English: Belize - {0x1009, 1252, PG_WIN1252, "en-CA"}, // English: Canada - // {0x2409, 1252, PG_WIN1252, English: Caribbean - {0x1809, 1252, PG_WIN1252, "en-IE"}, // English: Ireland - {0x2009, 1252, PG_WIN1252, "en-JM"}, // English: Jamaica - {0x1409, 1252, PG_WIN1252, "en-NZ"}, // English: New Zealand - {0x3409, 1252, PG_WIN1252, "en-PH"}, // English: Philippines - {0x1c09, 1252, PG_WIN1252, "en-ZA"}, // English: South Africa - {0x2c09, 1252, PG_WIN1252, "en-TT"}, // English: Trinidad - {0x0809, 1252, PG_WIN1252, "en-GB"}, // English: United Kingdom - {0x0409, 1252, PG_WIN1252, "en-US"}, // English: United States - {0x3009, 1252, PG_WIN1252, "en-ZW"}, // English: Zimbabwe - {0x0425, 1257, PG_WIN1257, "et-EE"}, // Estonian: Estonia - {0x0438, 1252, PG_WIN1252, "fo-FO"}, // Faeroese: Faeroe Islands - {0x0429, 1256, PG_WIN1256, "fa-IR"}, // Farsi: Iran - {0x040b, 1252, PG_WIN1252, "fi-FI"}, // Finnish: Finland - {0x080c, 1252, PG_WIN1252, "fr-BE"}, // French: Belgium - {0x0c0c, 1252, PG_WIN1252, "fr-CA"}, // French: Canada - {0x040c, 1252, PG_WIN1252, "fr-FR"}, // French: France - {0x140c, 1252, PG_WIN1252, "fr-LU"}, // French: Luxembourg - {0x180c, 1252, PG_WIN1252, "fr-MC"}, // French: Monaco - {0x100c, 1252, PG_WIN1252, "fr-CH"}, // French: Switzerland - {0x042f, 1251, PG_WIN1251, "mk-MK"}, // Macedonian (FYROM) - // {0x0437, 0, "ka-GE"}, // Georgian: Georgia - {0x0c07, 1252, PG_WIN1252, "de-AT"}, // German: Austria - {0x0407, 1252, PG_WIN1252, "de-DE"}, // German: Germany - {0x1407, 1252, PG_WIN1252, "de-LI"}, // German: Liechtenstein - {0x1007, 1252, PG_WIN1252, "de-LU"}, // German: Luxembourg - {0x0807, 1252, PG_WIN1252, "de-CH"}, // German: Switzerland - {0x0408, 1253, PG_WIN1253, "el-GR"}, // Greek: Greece - // {0x0447, 0, "gu-IN"}, // Gujarati: India - {0x040d, 1255, PG_WIN1255, "he-IL"}, // Hebrew: Israel - // {0x0439, 0, "hi-IN"}, // Hindi: India - {0x040e, 1250, PG_WIN1250, "hu-HU"}, // Hungarian: Hungary - {0x040f, 1252, PG_WIN1252, "is-IS"}, // Icelandic: Iceland - {0x0421, 1252, PG_WIN1252, "id-ID"}, // Indonesian: Indonesia - {0x0410, 1252, PG_WIN1252, "it-IT"}, // Italian: Italy - {0x0810, 1252, PG_WIN1252, "it-CH"}, // Italian: Switzerland - {0x0411, 932, PG_SJIS, "ja-JP"}, // Japanese: Japan - // {0x044b, 0, "kn-IN"}, // Kannada: India - // {0x0457, 0, "kok-IN"}, // Konkani: India - {0x0412, 949, PG_UHC, "ko-KR"}, // Korean (Extended Wansung): Korea - {0x0440, 1251, PG_WIN1251, "ky-KG"}, // Kyrgyz: Kyrgyzstan - {0x0426, 1257, PG_WIN1257, "lv-LV"}, // Latvian: Latvia - {0x0427, 1257, PG_WIN1257, "lt-LT"}, // Lithuanian: Lithuania - {0x083e, 1252, PG_WIN1252, "ms-BN"}, // Malay: Brunei Darussalam - {0x043e, 1252, PG_WIN1252, "ms-MY"}, // Malay: Malaysia - // {0x044e, 0, "mr-IN"}, // Marathi: India - {0x0450, 1251, PG_WIN1251, "mn-MN"}, // Mongolian: Mongolia - {0x0414, 1252, PG_WIN1252, "nb-NO"}, // Norwegian: Norway (BokmÃ¥l) - {0x0814, 1252, PG_WIN1252, "nn-NO"}, // Norwegian: Norway (Nynorsk) - {0x0415, 1250, PG_WIN1250, "pl-PL"}, // Polish: Poland - {0x0416, 1252, PG_WIN1252, "pt-BR"}, // Portuguese: Brazil - {0x0816, 1252, PG_WIN1252, "pt-PT"}, // Portuguese: Portugal - // {0x0446, 0, "pa-IN"}, // Punjabi: India - {0x0418, 1250, PG_WIN1250, "ro-RO"}, // Romanian: Romania - {0x0419, 1251, PG_WIN1251, "ru-RU"}, // Russian: Russia - // {0x044f, 0, "sa-IN"}, // Sanskrit: India - {0x0c1a, 1251, PG_WIN1251, "sr-Cyrl-RS"}, // Serbian: Serbia (Cyrillic) - {0x081a, 1250, PG_WIN1250, "sr-Latn-RS"}, // Serbian: Serbia (Latin) - {0x041b, 1250, PG_WIN1250, "sk-SK"}, // Slovak: Slovakia - {0x0424, 1250, PG_WIN1250, "sl-SI"}, // Slovenian: Slovenia - {0x2c0a, 1252, PG_WIN1252, "es-AR"}, // Spanish: Argentina - {0x400a, 1252, PG_WIN1252, "es-BO"}, // Spanish: Bolivia - {0x340a, 1252, PG_WIN1252, "es-CL"}, // Spanish: Chile - {0x240a, 1252, PG_WIN1252, "es-CO"}, // Spanish: Colombia - {0x140a, 1252, PG_WIN1252, "es-CR"}, // Spanish: Costa Rica - {0x1c0a, 1252, PG_WIN1252, "es-DO"}, // Spanish: Dominican Republic - {0x300a, 1252, PG_WIN1252, "es-EC"}, // Spanish: Ecuador - {0x440a, 1252, PG_WIN1252, "es-SV"}, // Spanish: El Salvador - {0x100a, 1252, PG_WIN1252, "es-GT"}, // Spanish: Guatemala - {0x480a, 1252, PG_WIN1252, "es-HN"}, // Spanish: Honduras - {0x080a, 1252, PG_WIN1252, "es-MX"}, // Spanish: Mexico - {0x4c0a, 1252, PG_WIN1252, "es-NI"}, // Spanish: Nicaragua - {0x180a, 1252, PG_WIN1252, "es-PA"}, // Spanish: Panama - {0x3c0a, 1252, PG_WIN1252, "es-PY"}, // Spanish: Paraguay - {0x280a, 1252, PG_WIN1252, "es-PE"}, // Spanish: Peru - {0x500a, 1252, PG_WIN1252, "es-PR"}, // Spanish: Puerto Rico - {0x0c0a, 1252, PG_WIN1252, "es-ES"}, // Spanish: Spain (Modern Sort) - {0x040a, 1252, PG_WIN1252, "es-TRADITIONAL"}, // Spanish: Spain (International Sort) - {0x380a, 1252, PG_WIN1252, "es-UY"}, // Spanish: Uruguay - {0x200a, 1252, PG_WIN1252, "es-VE"}, // Spanish: Venezuela - {0x0441, 1252, PG_WIN1252, "sw-KE"}, // Swahili: Kenya - {0x081d, 1252, PG_WIN1252, "sv-FI"}, // Swedish: Finland - {0x041d, 1252, PG_WIN1252, "sv-SE"}, // Swedish: Sweden - {0x0444, 1251, PG_WIN1251, "tt-RU"}, // Tatar: Tatarstan - //{0x044a, 0, "te-IN"}, // Telgu: India - {0x041e, 874, PG_WIN874, "th-TH"}, // Thai: Thailand - {0x041f, 1254, PG_WIN1254, "tr-TR"}, // Turkish: Turkey - {0x0422, 1251, PG_WIN1251, "uk-UA"}, // Ukrainian: Ukraine - {0x0820, 1256, PG_WIN1256, "ur-IN"}, // Urdu: India - {0x0420, 1256, PG_WIN1256, "ur-PK"}, // Urdu: Pakistan - {0x0843, 1251, PG_WIN1251, "uz-Cyrl-UZ"}, // Uzbek: Uzbekistan (Cyrillic) - {0x0443, 1250, PG_WIN1250, "uz-Latn-UZ"}, // Uzbek: Uzbekistan (Latin) - {0x042a, 1258, PG_WIN1258, "vi-VN"}, // Vietnamese: Vietnam + {0x0436, 1252, PG_WIN1252, "af-ZA"}, //Afrikaans:South Africa + {0x041c, 1250, PG_WIN1250, "sq-AL"}, //Albanian:Albania + {0x1401, 1256, PG_WIN1256, "ar-DZ"}, //Arabic:Algeria + {0x3c01, 1256, PG_WIN1256, "ar-BH"}, //Arabic:Bahrain + {0x0c01, 1256, PG_WIN1256, "ar-EG"}, //Arabic:Egypt + {0x0801, 1256, PG_WIN1256, "ar-IQ"}, //Arabic:Iraq + {0x2c01, 1256, PG_WIN1256, "ar-JO"}, //Arabic:Jordan + {0x3401, 1256, PG_WIN1256, "ar-KW"}, //Arabic:Kuwait + {0x3001, 1256, PG_WIN1256, "ar-LB"}, //Arabic:Lebanon + {0x1001, 1256, PG_WIN1256, "ar-LY"}, //Arabic:Libya + {0x1801, 1256, PG_WIN1256, "ar-MA"}, //Arabic:Morocco + {0x2001, 1256, PG_WIN1256, "ar-OM"}, //Arabic:Oman + {0x4001, 1256, PG_WIN1256, "ar-QA"}, //Arabic:Qatar + {0x0401, 1256, PG_WIN1256, "ar-SA"}, //Arabic:Saudi Arabia + {0x2801, 1256, PG_WIN1256, "ar-SY"}, //Arabic:Syria + {0x1c01, 1256, PG_WIN1256, "ar-TN"}, //Arabic:Tunisia + {0x3801, 1256, PG_WIN1256, "ar-AE"}, //Arabic:U.A.E. + {0x2401, 1256, PG_WIN1256, "ar-YE"}, //Arabic:Yemen + /* {0x042b, 0, "hy-AM"}, // Armenian: Armenia */ + {0x082c, 1251, PG_WIN1251, "az-Cyrl-AZ"}, //Azeri:Azerbaijan(Cyrillic) + {0x042c, 1250, PG_WIN1250, "az-Latn-AZ"}, //Azeri:Azerbaijan(Latin) + {0x042d, 1252, PG_WIN1252, "eu-ES"}, //Basque:Spain + {0x0423, 1251, PG_WIN1251, "be-BY"}, //Belarusian:Belarus + {0x0402, 1251, PG_WIN1251, "bg-BG"}, //Bulgarian:Bulgaria + {0x0403, 1252, PG_WIN1252, "ca-ES"}, //Catalan:Spain + {0x0c04, 950, PG_BIG5, "zh-HK"}, //Chinese:Hong Kong SAR, PRC(Traditional) + {0x1404, 950, PG_BIG5, "zh-MO"}, //Chinese:Macao SAR(Traditional) + {0x0804, 936, PG_GBK, "zh-CN"}, //Chinese:PRC(Simplified) + {0x1004, 936, PG_GBK, "zh-SG"}, //Chinese:Singapore(Simplified) + {0x0404, 950, PG_BIG5, "zh-TW"}, //Chinese:Taiwan(Traditional) + /* {0x0827, 1257, PG_WIN1257, Classic Lithuanian: Lithuania */ + {0x041a, 1250, PG_WIN1250, "hr-HR"}, //Croatian:Croatia + {0x0405, 1250, PG_WIN1250, "cs-CZ"}, //Czech:Czech Republic + {0x0406, 1252, PG_WIN1252, "da-DK"}, //Danish:Denmark + {0x0813, 1252, PG_WIN1252, "nl-BE"}, //Dutch:Belgium + {0x0413, 1252, PG_WIN1252, "nl-NL"}, //Dutch:Netherlands + {0x0c09, 1252, PG_WIN1252, "en-AU"}, //English:Australia + {0x2809, 1252, PG_WIN1252, "en-BZ"}, //English:Belize + {0x1009, 1252, PG_WIN1252, "en-CA"}, //English:Canada + /* {0x2409, 1252, PG_WIN1252, English: Caribbean */ + {0x1809, 1252, PG_WIN1252, "en-IE"}, //English:Ireland + {0x2009, 1252, PG_WIN1252, "en-JM"}, //English:Jamaica + {0x1409, 1252, PG_WIN1252, "en-NZ"}, //English:New Zealand + {0x3409, 1252, PG_WIN1252, "en-PH"}, //English:Philippines + {0x1c09, 1252, PG_WIN1252, "en-ZA"}, //English:South Africa + {0x2c09, 1252, PG_WIN1252, "en-TT"}, //English:Trinidad + {0x0809, 1252, PG_WIN1252, "en-GB"}, //English:United Kingdom + {0x0409, 1252, PG_WIN1252, "en-US"}, //English:United States + {0x3009, 1252, PG_WIN1252, "en-ZW"}, //English:Zimbabwe + {0x0425, 1257, PG_WIN1257, "et-EE"}, //Estonian:Estonia + {0x0438, 1252, PG_WIN1252, "fo-FO"}, //Faeroese:Faeroe Islands + {0x0429, 1256, PG_WIN1256, "fa-IR"}, //Farsi:Iran + {0x040b, 1252, PG_WIN1252, "fi-FI"}, //Finnish:Finland + {0x080c, 1252, PG_WIN1252, "fr-BE"}, //French:Belgium + {0x0c0c, 1252, PG_WIN1252, "fr-CA"}, //French:Canada + {0x040c, 1252, PG_WIN1252, "fr-FR"}, //French:France + {0x140c, 1252, PG_WIN1252, "fr-LU"}, //French:Luxembourg + {0x180c, 1252, PG_WIN1252, "fr-MC"}, //French:Monaco + {0x100c, 1252, PG_WIN1252, "fr-CH"}, //French:Switzerland + {0x042f, 1251, PG_WIN1251, "mk-MK"}, //Macedonian(FYROM) + /* {0x0437, 0, "ka-GE"}, // Georgian: Georgia */ + {0x0c07, 1252, PG_WIN1252, "de-AT"}, //German:Austria + {0x0407, 1252, PG_WIN1252, "de-DE"}, //German:Germany + {0x1407, 1252, PG_WIN1252, "de-LI"}, //German:Liechtenstein + {0x1007, 1252, PG_WIN1252, "de-LU"}, //German:Luxembourg + {0x0807, 1252, PG_WIN1252, "de-CH"}, //German:Switzerland + {0x0408, 1253, PG_WIN1253, "el-GR"}, //Greek:Greece + /* {0x0447, 0, "gu-IN"}, // Gujarati: India */ + {0x040d, 1255, PG_WIN1255, "he-IL"}, //Hebrew:Israel + /* {0x0439, 0, "hi-IN"}, // Hindi: India */ + {0x040e, 1250, PG_WIN1250, "hu-HU"}, //Hungarian:Hungary + {0x040f, 1252, PG_WIN1252, "is-IS"}, //Icelandic:Iceland + {0x0421, 1252, PG_WIN1252, "id-ID"}, //Indonesian:Indonesia + {0x0410, 1252, PG_WIN1252, "it-IT"}, //Italian:Italy + {0x0810, 1252, PG_WIN1252, "it-CH"}, //Italian:Switzerland + {0x0411, 932, PG_SJIS, "ja-JP"}, //Japanese:Japan + /* {0x044b, 0, "kn-IN"}, // Kannada: India */ + /* {0x0457, 0, "kok-IN"}, // Konkani: India */ + {0x0412, 949, PG_UHC, "ko-KR"}, //Korean(Extended Wansung):Korea + {0x0440, 1251, PG_WIN1251, "ky-KG"}, //Kyrgyz:Kyrgyzstan + {0x0426, 1257, PG_WIN1257, "lv-LV"}, //Latvian:Latvia + {0x0427, 1257, PG_WIN1257, "lt-LT"}, //Lithuanian:Lithuania + {0x083e, 1252, PG_WIN1252, "ms-BN"}, //Malay:Brunei Darussalam + {0x043e, 1252, PG_WIN1252, "ms-MY"}, //Malay:Malaysia + /* {0x044e, 0, "mr-IN"}, // Marathi: India */ + {0x0450, 1251, PG_WIN1251, "mn-MN"}, //Mongolian:Mongolia + {0x0414, 1252, PG_WIN1252, "nb-NO"}, //Norwegian:Norway(Bokmà ¥ l) + {0x0814, 1252, PG_WIN1252, "nn-NO"}, //Norwegian:Norway(Nynorsk) + {0x0415, 1250, PG_WIN1250, "pl-PL"}, //Polish:Poland + {0x0416, 1252, PG_WIN1252, "pt-BR"}, //Portuguese:Brazil + {0x0816, 1252, PG_WIN1252, "pt-PT"}, //Portuguese:Portugal + /* {0x0446, 0, "pa-IN"}, // Punjabi: India */ + {0x0418, 1250, PG_WIN1250, "ro-RO"}, //Romanian:Romania + {0x0419, 1251, PG_WIN1251, "ru-RU"}, //Russian:Russia + /* {0x044f, 0, "sa-IN"}, // Sanskrit: India */ + {0x0c1a, 1251, PG_WIN1251, "sr-Cyrl-RS"}, //Serbian:Serbia(Cyrillic) + {0x081a, 1250, PG_WIN1250, "sr-Latn-RS"}, //Serbian:Serbia(Latin) + {0x041b, 1250, PG_WIN1250, "sk-SK"}, //Slovak:Slovakia + {0x0424, 1250, PG_WIN1250, "sl-SI"}, //Slovenian:Slovenia + {0x2c0a, 1252, PG_WIN1252, "es-AR"}, //Spanish:Argentina + {0x400a, 1252, PG_WIN1252, "es-BO"}, //Spanish:Bolivia + {0x340a, 1252, PG_WIN1252, "es-CL"}, //Spanish:Chile + {0x240a, 1252, PG_WIN1252, "es-CO"}, //Spanish:Colombia + {0x140a, 1252, PG_WIN1252, "es-CR"}, //Spanish:Costa Rica + {0x1c0a, 1252, PG_WIN1252, "es-DO"}, //Spanish:Dominican Republic + {0x300a, 1252, PG_WIN1252, "es-EC"}, //Spanish:Ecuador + {0x440a, 1252, PG_WIN1252, "es-SV"}, //Spanish:El Salvador + {0x100a, 1252, PG_WIN1252, "es-GT"}, //Spanish:Guatemala + {0x480a, 1252, PG_WIN1252, "es-HN"}, //Spanish:Honduras + {0x080a, 1252, PG_WIN1252, "es-MX"}, //Spanish:Mexico + {0x4c0a, 1252, PG_WIN1252, "es-NI"}, //Spanish:Nicaragua + {0x180a, 1252, PG_WIN1252, "es-PA"}, //Spanish:Panama + {0x3c0a, 1252, PG_WIN1252, "es-PY"}, //Spanish:Paraguay + {0x280a, 1252, PG_WIN1252, "es-PE"}, //Spanish:Peru + {0x500a, 1252, PG_WIN1252, "es-PR"}, //Spanish:Puerto Rico + {0x0c0a, 1252, PG_WIN1252, "es-ES"}, //Spanish:Spain(Modern Sort) + {0x040a, 1252, PG_WIN1252, "es-TRADITIONAL"}, //Spanish:Spain(International Sort) + {0x380a, 1252, PG_WIN1252, "es-UY"}, //Spanish:Uruguay + {0x200a, 1252, PG_WIN1252, "es-VE"}, //Spanish:Venezuela + {0x0441, 1252, PG_WIN1252, "sw-KE"}, //Swahili:Kenya + {0x081d, 1252, PG_WIN1252, "sv-FI"}, //Swedish:Finland + {0x041d, 1252, PG_WIN1252, "sv-SE"}, //Swedish:Sweden + {0x0444, 1251, PG_WIN1251, "tt-RU"}, //Tatar:Tatarstan + /* {0x044a, 0, "te-IN"}, // Telgu: India */ + {0x041e, 874, PG_WIN874, "th-TH"}, //Thai:Thailand + {0x041f, 1254, PG_WIN1254, "tr-TR"}, //Turkish:Turkey + {0x0422, 1251, PG_WIN1251, "uk-UA"}, //Ukrainian:Ukraine + {0x0820, 1256, PG_WIN1256, "ur-IN"}, //Urdu:India + {0x0420, 1256, PG_WIN1256, "ur-PK"}, //Urdu:Pakistan + {0x0843, 1251, PG_WIN1251, "uz-Cyrl-UZ"}, //Uzbek:Uzbekistan(Cyrillic) + {0x0443, 1250, PG_WIN1250, "uz-Latn-UZ"}, //Uzbek:Uzbekistan(Latin) + {0x042a, 1258, PG_WIN1258, "vi-VN"}, //Vietnamese:Vietnam }; #define TOTAL_LOCALES (sizeof(locales)/sizeof(locales[0])) @@ -461,15 +479,20 @@ init_default_locale(void) if (!bbf_default_locale) { const char *val = GetConfigOption("babelfishpg_tsql.default_locale", true, false); + if (val) { MemoryContext oldContext = MemoryContextSwitchTo(TopMemoryContext); + bbf_default_locale = pstrdup(val); MemoryContextSwitchTo(oldContext); } } - /* babelfishpg_tsql.default_locale should not be changed once babelfish db is initialised. */ + /* + * babelfishpg_tsql.default_locale should not be changed once babelfish db + * is initialised. + */ Assert(!bbf_default_locale || strcmp(bbf_default_locale, GetConfigOption("babelfishpg_tsql.default_locale", true, false)) == 0); return; @@ -481,9 +504,11 @@ init_server_collation_name(void) if (!server_collation_name) { const char *val = GetConfigOption("babelfishpg_tsql.server_collation_name", true, false); + if (val) { MemoryContext oldContext = MemoryContextSwitchTo(TopMemoryContext); + server_collation_name = pstrdup(val); MemoryContextSwitchTo(oldContext); } @@ -494,23 +519,24 @@ init_server_collation_name(void) int find_collation(const char *collation_name) { - int first = 0; - int last = TOTAL_COLL_COUNT - 1; - int middle = 37; /* optimization: usually it's the default collation (first + last) / 2; */ - int compare; + int first = 0; + int last = TOTAL_COLL_COUNT - 1; + int middle = 37; /* optimization: usually it's the default + * collation (first + last) / 2; */ + int compare; while (first <= last) { - compare = pg_strcasecmp(coll_infos[middle].collname, collation_name); + compare = pg_strcasecmp(coll_infos[middle].collname, collation_name); - if (compare < 0) - first = middle + 1; - else if (compare == 0) - return middle; - else - last = middle - 1; + if (compare < 0) + first = middle + 1; + else if (compare == 0) + return middle; + else + last = middle - 1; - middle = (first + last) / 2; + middle = (first + last) / 2; } return NOT_FOUND; @@ -522,8 +548,8 @@ collation_is_accent_insensitive(int collidx) if (collidx < 0 || collidx >= TOTAL_COLL_COUNT) return false; - if (coll_infos[collidx].collateflags == 0x000f || /* CI_AI */ - coll_infos[collidx].collateflags == 0x000e) /* CS_AI */ + if (coll_infos[collidx].collateflags == 0x000f || /* CI_AI */ + coll_infos[collidx].collateflags == 0x000e) /* CS_AI */ return true; return false; @@ -542,19 +568,19 @@ is_server_collation_CI_AS(void) int find_cs_as_collation(int collidx) { - int cur_collidx = collidx; + int cur_collidx = collidx; if (NOT_FOUND == collidx) - return collidx; + return collidx; while (cur_collidx < TOTAL_COLL_COUNT && coll_infos[cur_collidx].lcid == coll_infos[collidx].lcid) { - if ( coll_infos[cur_collidx].collateflags == 0x000c /* CS_AS */ || - coll_infos[cur_collidx].collateflags == 0x0220 /* BIN2 */ ) - return cur_collidx; + if (coll_infos[cur_collidx].collateflags == 0x000c /* CS_AS */ || + coll_infos[cur_collidx].collateflags == 0x0220 /* BIN2 */ ) + return cur_collidx; - cur_collidx++; + cur_collidx++; } return NOT_FOUND; @@ -563,7 +589,7 @@ find_cs_as_collation(int collidx) int find_any_collation(const char *collation_name, bool check_for_server_collation_name_guc) { - int collidx = translate_collation(collation_name, check_for_server_collation_name_guc); + int collidx = translate_collation(collation_name, check_for_server_collation_name_guc); if (NOT_FOUND == collidx) collidx = find_collation(collation_name); @@ -578,11 +604,12 @@ find_any_collation(const char *collation_name, bool check_for_server_collation_n static int translate_collation_utility(const char *collname) { - int first = 0; - int last = TOTAL_COLL_TRANSLATION_COUNT - 1; - int middle = 25; /* optimization: usually it's the default collation (first + last) / 2; */ - int idx = NOT_FOUND; - int compare; + int first = 0; + int last = TOTAL_COLL_TRANSLATION_COUNT - 1; + int middle = 25; /* optimization: usually it's the default + * collation (first + last) / 2; */ + int idx = NOT_FOUND; + int compare; while (first <= last) { @@ -601,6 +628,7 @@ translate_collation_utility(const char *collname) } return idx; } + /* * translate_collation - Returns index of babelfish collation corresponding to supplied collation_name * by looking into coll_translations array or returns NOT_FOUND. @@ -611,8 +639,12 @@ translate_collation_utility(const char *collname) int translate_collation(const char *collname, bool check_for_server_collation_name_guc) { - int idx = NOT_FOUND; - /* Special case handling for database_default and catalog_default collations which should be translated to server_collation_name. */ + int idx = NOT_FOUND; + + /* + * Special case handling for database_default and catalog_default + * collations which should be translated to server_collation_name. + */ if (!check_for_server_collation_name_guc && (pg_strcasecmp(collname, DATABASE_DEFAULT) == 0 || pg_strcasecmp(collname, CATALOG_DEFAULT) == 0)) { init_server_collation_name(); @@ -652,21 +684,21 @@ translate_bbf_collation_to_tsql_collation(const char *collname) int find_locale(const char *given_locale) { - int i; - char *normalized_locale = NULL; + int i; + char *normalized_locale = NULL; /* * Normalize given_locale before searching the locales array */ if (NULL == given_locale || - 0 == strlen(given_locale) || - strlen(given_locale) > MAX_ICU_LOCALE_LEN) + 0 == strlen(given_locale) || + strlen(given_locale) > MAX_ICU_LOCALE_LEN) { return NOT_FOUND; } else { - char *underscore_pos; + char *underscore_pos; normalized_locale = palloc0(strlen(given_locale) + 1); memcpy(normalized_locale, given_locale, strlen(given_locale)); @@ -680,7 +712,7 @@ find_locale(const char *given_locale) } - for (i=0; i < TOTAL_LOCALES; ++i) + for (i = 0; i < TOTAL_LOCALES; ++i) { if (0 == pg_strcasecmp(normalized_locale, locales[i].icu_locale)) { @@ -700,55 +732,58 @@ find_locale(const char *given_locale) int init_collid_trans_tab_internal(void) { - HASHCTL hashCtl; - Oid nspoid; + HASHCTL hashCtl; + Oid nspoid; ht_oid2collid_entry *entry; - int locale_pos = -1; - char *atsign; - char *locale; + int locale_pos = -1; + char *atsign; + char *locale; - if (TransMemoryContext == NULL) /* initialize memory context */ + if (TransMemoryContext == NULL) /* initialize memory context */ { TransMemoryContext = AllocSetContextCreateInternal(NULL, - "SQL Variant Memory Context", - ALLOCSET_DEFAULT_SIZES); + "SQL Variant Memory Context", + ALLOCSET_DEFAULT_SIZES); } - if (ht_oid2collid == NULL) /* create hash table */ + if (ht_oid2collid == NULL) /* create hash table */ { MemSet(&hashCtl, 0, sizeof(hashCtl)); hashCtl.keysize = sizeof(Oid); hashCtl.entrysize = sizeof(ht_oid2collid_entry); hashCtl.hcxt = TransMemoryContext; ht_oid2collid = hash_create("OID to Persist Collation ID Mapping", - TOTAL_COLL_COUNT, - &hashCtl, - HASH_ELEM | HASH_CONTEXT | HASH_BLOBS); + TOTAL_COLL_COUNT, + &hashCtl, + HASH_ELEM | HASH_CONTEXT | HASH_BLOBS); } nspoid = get_namespace_oid("sys", false); /* retrieve oid and setup hashtable */ - for (int i=0; ioid; ReleaseSysCache(tup); if (!OidIsValid(loid)) ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("type %s.%s is invalid!", - like_ilike_table[i].op_left_schema, like_ilike_table[i].op_left_name))); + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("type %s.%s is invalid!", + like_ilike_table[i].op_left_schema, like_ilike_table[i].op_left_name))); typename = makeTypeNameFromNameList(list_make2(makeString(like_ilike_table[i].op_right_schema), makeString(like_ilike_table[i].op_right_name))); tup = LookupTypeName(NULL, typename, NULL, true); if (!tup) - continue; /* this can happen when _PG_Init is called to verify C function before creating datatype */ + continue; /* this can happen when _PG_Init is called to + * verify C function before creating datatype */ roid = ((Form_pg_type) GETSTRUCT(tup))->oid; ReleaseSysCache(tup); if (!OidIsValid(roid)) ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("type %s.%s is invalid!", - like_ilike_table[i].op_right_schema, like_ilike_table[i].op_right_name))); + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("type %s.%s is invalid!", + like_ilike_table[i].op_right_schema, like_ilike_table[i].op_right_name))); like_ilike_table[i].like_oid = OpernameGetOprid(list_make1(makeString(like_opname)), - loid, - roid); + loid, + roid); if (OidIsValid(like_ilike_table[i].like_oid)) { entry = hash_search(ht_like2ilike, &like_ilike_table[i].like_oid, HASH_ENTER, NULL); entry->persist_id = i; } like_ilike_table[i].ilike_oid = OpernameGetOprid(list_make1(makeString(ilike_opname)), - loid, - roid); + loid, + roid); like_ilike_table[i].ilike_opfuncid = get_opcode(like_ilike_table[i].ilike_oid); } return 0; @@ -865,8 +904,8 @@ init_like_ilike_table_internal(void) like_ilike_info lookup_like_ilike_table(Oid opno) { - ht_like2ilike_entry_t *hinfo; - bool found; + ht_like2ilike_entry_t *hinfo; + bool found; if (ht_like2ilike == NULL) init_like_ilike_table_internal(); @@ -879,6 +918,7 @@ lookup_like_ilike_table(Oid opno) if (!found) { like_ilike_info invalid; + invalid.like_oid = InvalidOid; return invalid; } @@ -893,43 +933,43 @@ lookup_like_ilike_table(Oid opno) coll_info lookup_collation_table(Oid coll_oid) { - ht_oid2collid_entry *hinfo; - bool found; + ht_oid2collid_entry *hinfo; + bool found; if (ht_oid2collid == NULL) init_collid_trans_tab_internal(); if (!OidIsValid(coll_oid)) { - int collidx = get_server_collation_collidx(); + int collidx = get_server_collation_collidx(); - if (NOT_FOUND != collidx) - return coll_infos[collidx]; + if (NOT_FOUND != collidx) + return coll_infos[collidx]; } hinfo = (ht_oid2collid_entry *) hash_search(ht_oid2collid, - &coll_oid, - HASH_FIND, - &found); + &coll_oid, + HASH_FIND, + &found); /* - * TODO: Change it to Error, and reload the cache again. - * If not found, raise the error. - * For now, silently return NULL, so that we can use - * the default values + * TODO: Change it to Error, and reload the cache again. If not found, + * raise the error. For now, silently return NULL, so that we can use the + * default values */ if (!found) { - int collidx; + int collidx; + + coll_info invalid; - coll_info invalid; invalid.oid = InvalidOid; collidx = get_server_collation_collidx(); if (collidx == NOT_FOUND) ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("Encoding corresponding to default server collation could not be found."))); + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("Encoding corresponding to default server collation could not be found."))); else invalid.enc = coll_infos[collidx].enc; elog(DEBUG2, "collation oid %d not found, using default collation", coll_oid); @@ -940,7 +980,7 @@ lookup_collation_table(Oid coll_oid) } /* - * get_server_collation_collidx - + * get_server_collation_collidx - * Get the Index of default collation from coll_infos array, or return NOT_FOUND if not found */ int @@ -954,27 +994,29 @@ get_server_collation_collidx(void) } /* - * cmp_collation - return -1 if coll1 < coll2, 0 if coll1 = coll2, 1 if coll1 > coll2 + * cmp_collation - return -1 if coll1 < coll2, 0 if coll1 = coll2, 1 if coll1 > coll2 */ int8_t -cmp_collation(uint16_t coll1, uint16_t coll2){ - coll_info * coll_info1 = &coll_infos[coll1]; - coll_info * coll_info2 = &coll_infos[coll2]; - if (coll_info1->lcid < coll_info2-> lcid) +cmp_collation(uint16_t coll1, uint16_t coll2) +{ + coll_info *coll_info1 = &coll_infos[coll1]; + coll_info *coll_info2 = &coll_infos[coll2]; + + if (coll_info1->lcid < coll_info2->lcid) return -1; - else if (coll_info1->lcid > coll_info2-> lcid) + else if (coll_info1->lcid > coll_info2->lcid) return 1; - else if (coll_info1->ver < coll_info2-> ver) + else if (coll_info1->ver < coll_info2->ver) return -1; - else if (coll_info1->ver > coll_info2-> ver) + else if (coll_info1->ver > coll_info2->ver) return 1; - else if (coll_info1->style < coll_info2-> style) + else if (coll_info1->style < coll_info2->style) return -1; - else if (coll_info1->style > coll_info2-> style) + else if (coll_info1->style > coll_info2->style) return 1; - else if (coll_info1->sortid < coll_info2-> sortid) + else if (coll_info1->sortid < coll_info2->sortid) return -1; - else if (coll_info1->sortid > coll_info2-> sortid) + else if (coll_info1->sortid > coll_info2->sortid) return 1; else return 0; @@ -988,7 +1030,7 @@ Datum collation_list_internal(PG_FUNCTION_ARGS) { ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; + TupleDesc tupdesc; Tuplestorestate *tupstore; MemoryContext per_query_ctx; MemoryContext oldcontext; @@ -1036,7 +1078,7 @@ collation_list_internal(PG_FUNCTION_ARGS) /* scan all the variables in top estate */ for (int i = 0; i < TOTAL_COLL_COUNT; i++) { - coll_info *info = &coll_infos[i]; + coll_info *info = &coll_infos[i]; Datum values[7]; bool nulls[7]; @@ -1066,17 +1108,18 @@ collation_list_internal(PG_FUNCTION_ARGS) static Oid get_collation_oid_internal(char *collation_name) { - Oid nspoid; - Oid collation_oid; - int collidx; + Oid nspoid; + Oid collation_oid; + int collidx; const char *collname; if (!collation_name) return DEFAULT_COLLATION_OID; - /* The collation_name is permitted to be the name of a sql - * or windows collation that is translated into a bbf collation. - * If that's what it is then get the translated name. + /* + * The collation_name is permitted to be the name of a sql or windows + * collation that is translated into a bbf collation. If that's what it is + * then get the translated name. */ if (NOT_FOUND != (collidx = translate_collation(collation_name, false))) collname = coll_infos[collidx].collname; @@ -1085,15 +1128,15 @@ get_collation_oid_internal(char *collation_name) nspoid = get_namespace_oid("sys", false); collation_oid = GetSysCacheOid3(COLLNAMEENCNSP, Anum_pg_collation_oid, - PointerGetDatum(collname), - Int32GetDatum(-1), - ObjectIdGetDatum(nspoid)); + PointerGetDatum(collname), + Int32GetDatum(-1), + ObjectIdGetDatum(nspoid)); if (!OidIsValid(collation_oid)) collation_oid = GetSysCacheOid3(COLLNAMEENCNSP, Anum_pg_collation_oid, - PointerGetDatum(collname), - Int32GetDatum(COLL_DEFAULT_ENCODING), - ObjectIdGetDatum(nspoid)); + PointerGetDatum(collname), + Int32GetDatum(COLL_DEFAULT_ENCODING), + ObjectIdGetDatum(nspoid)); return collation_oid; } @@ -1117,7 +1160,7 @@ get_server_collation_oid_internal(bool missingOk) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("Server default collation sys.\"%s\" is not defined, using the cluster default collation", - server_collation_name))); + server_collation_name))); else { db_collation_is_CI_AS = false; @@ -1134,11 +1177,13 @@ get_server_collation_oid_internal(bool missingOk) return server_collation_oid; } -Oid BABELFISH_CLUSTER_COLLATION_OID() +Oid +BABELFISH_CLUSTER_COLLATION_OID() { if (sql_dialect == SQL_DIALECT_TSQL) { - get_server_collation_oid_internal(false); /* set and cache server_collation_oid */ + get_server_collation_oid_internal(false); /* set and cache + * server_collation_oid */ if (OidIsValid(server_collation_oid)) return server_collation_oid; @@ -1149,7 +1194,8 @@ Oid BABELFISH_CLUSTER_COLLATION_OID() /* * collation_is_CI_AS - Returns true if collation with given colloid is CI_AS. */ -bool collation_is_CI_AS(Oid colloid) +bool +collation_is_CI_AS(Oid colloid) { HeapTuple tp; char *collcollate = NULL; @@ -1184,41 +1230,45 @@ bool collation_is_CI_AS(Oid colloid) if (isnull) return false; - /* - * colStrength secondary, or level2, corresponds to a CI_AS collation, unless - * colCaseLevel=yes is also specified + /* + * colStrength secondary, or level2, corresponds to a CI_AS collation, + * unless colCaseLevel=yes is also specified */ - if(0 != strstr(lowerstr(collcollate), lowerstr("colStrength=secondary")) && /* CI_AS */ - 0 == strstr(lowerstr(collcollate), lowerstr("colCaseLevel=yes"))) /* without a colCaseLevel - not CS_AI */ + if (0 != strstr(lowerstr(collcollate), lowerstr("colStrength=secondary")) && /* CI_AS */ + 0 == strstr(lowerstr(collcollate), lowerstr("colCaseLevel=yes"))) /* without a + * colCaseLevel - not + * CS_AI */ return true; return false; } -bool has_ilike_node(Node *expr) -{ - OpExpr *op; +bool +has_ilike_node(Node *expr) +{ + OpExpr *op; + Assert(IsA(expr, OpExpr)); - + op = (OpExpr *) expr; - for(int i = 0; i < TOTAL_LIKE_OP_COUNT; i++) + for (int i = 0; i < TOTAL_LIKE_OP_COUNT; i++) { - if(strcmp(get_opname(op->opno), like_ilike_table[i].ilike_op_name) == 0) + if (strcmp(get_opname(op->opno), like_ilike_table[i].ilike_op_name) == 0) { return true; } } - return false; + return false; } Datum is_collated_ci_as_internal(PG_FUNCTION_ARGS) { - Oid colloid = PG_GET_COLLATION(); - + Oid colloid = PG_GET_COLLATION(); + if (!OidIsValid(colloid)) PG_RETURN_BOOL(false); - + if (collation_is_CI_AS(colloid)) PG_RETURN_BOOL(true); @@ -1230,7 +1280,7 @@ BabelfishTranslateCollation(const char *collname, Oid collnamespace, int32 encod { if (prev_TranslateCollation_hook) { - const char *newCollname = (*prev_TranslateCollation_hook)(collname, collnamespace, encoding); + const char *newCollname = (*prev_TranslateCollation_hook) (collname, collnamespace, encoding); if (newCollname) return newCollname; @@ -1238,11 +1288,11 @@ BabelfishTranslateCollation(const char *collname, Oid collnamespace, int32 encod if (pltsql_case_insensitive_identifiers && strcmp(collname, "c") == 0) { - return "C"; /* Special case for "C" collation */ + return "C"; /* Special case for "C" collation */ } else { - int collidx = translate_collation(collname, false); + int collidx = translate_collation(collname, false); if (collidx >= 0) { @@ -1256,7 +1306,7 @@ BabelfishTranslateCollation(const char *collname, Oid collnamespace, int32 encod bool is_valid_server_collation_name(const char *collname) { - int collidx = find_any_collation(collname, true); + int collidx = find_any_collation(collname, true); if (NOT_FOUND != collidx && !collation_is_accent_insensitive(collidx)) @@ -1265,16 +1315,18 @@ is_valid_server_collation_name(const char *collname) return false; } -Oid get_tsql_collation_oid(int persist_coll_id) +Oid +get_tsql_collation_oid(int persist_coll_id) { return coll_infos[persist_coll_id].oid; } -int get_persist_collation_id(Oid coll_oid) +int +get_persist_collation_id(Oid coll_oid) { ht_oid2collid_entry *entry; - bool found_coll; - int collidx; + bool found_coll; + int collidx; if (ht_oid2collid == NULL) init_collid_trans_tab_internal(); @@ -1291,33 +1343,33 @@ int get_persist_collation_id(Oid coll_oid) return collidx; } -bytea* +bytea * tdscollationproperty_helper(const char *collationname, const char *property) { - int collidx = find_any_collation(collationname, false); + int collidx = find_any_collation(collationname, false); + if (collidx >= 0) { - coll_info coll = coll_infos[collidx]; + coll_info coll = coll_infos[collidx]; if (strcasecmp(property, "tdscollation") == 0) { /* - * ret here is of 8 bytes - * tdscollation should return 5 bytes - * Below code converts ret into 5 bytes + * ret here is of 8 bytes tdscollation should return 5 bytes Below + * code converts ret into 5 bytes */ - int64_t ret = ((int64_t)((int64_t)coll.lcid | ((int64_t)coll.collateflags << 20) | ((int64_t)coll.sortid << 32))); - int maxlen = 5; - char *rp; - bytea *result; - svhdr_3B_t *svhdr; - bytea *bytea_data = (bytea *) palloc(maxlen + VARHDRSZ); + int64_t ret = ((int64_t) ((int64_t) coll.lcid | ((int64_t) coll.collateflags << 20) | ((int64_t) coll.sortid << 32))); + int maxlen = 5; + char *rp; + bytea *result; + svhdr_3B_t *svhdr; + bytea *bytea_data = (bytea *) palloc(maxlen + VARHDRSZ); SET_VARSIZE(bytea_data, maxlen + VARHDRSZ); rp = VARDATA(bytea_data); - memcpy(rp, (char *) &ret , maxlen); + memcpy(rp, (char *) &ret, maxlen); result = gen_sqlvariant_bytea_from_type_datum(BINARY_T, PointerGetDatum(bytea_data)); @@ -1330,16 +1382,17 @@ tdscollationproperty_helper(const char *collationname, const char *property) } } - return NULL; /* Invalid collation. */ + return NULL; /* Invalid collation. */ } int collationproperty_helper(const char *collationname, const char *property) { - int collidx = find_any_collation(collationname, false); + int collidx = find_any_collation(collationname, false); + if (collidx >= 0) { - coll_info coll = coll_infos[collidx]; + coll_info coll = coll_infos[collidx]; if (strcasecmp(property, "CodePage") == 0) return coll.code_page; @@ -1349,29 +1402,32 @@ collationproperty_helper(const char *collationname, const char *property) return coll.style; else if (strcasecmp(property, "Version") == 0) return coll.ver; + /* - * Below properties are added for internal usage with sp_describe_first_result_set - * to return correct tds_collation_id and tds_collation_sort_id fields. + * Below properties are added for internal usage with + * sp_describe_first_result_set to return correct tds_collation_id and + * tds_collation_sort_id fields. */ else if (strcasecmp(property, "CollationId") == 0) return ((coll.collateflags << 20) | coll.lcid); else if (strcasecmp(property, "SortId") == 0) return coll.sortid; else - return -1; /* Invalid property. */ + return -1; /* Invalid property. */ } else - return -1; /* Invalid collation. */ + return -1; /* Invalid collation. */ } -void BabelfishPreCreateCollation_hook( - char collprovider, - bool collisdeterministic, - int32 collencoding, - const char **pCollcollate, - const char **pCollctype, - const char *collversion - ) +void +BabelfishPreCreateCollation_hook( + char collprovider, + bool collisdeterministic, + int32 collencoding, + const char **pCollcollate, + const char **pCollctype, + const char *collversion +) { const char *collcollate = *pCollcollate; const char *collctype = *pCollctype; @@ -1382,12 +1438,12 @@ void BabelfishPreCreateCollation_hook( if (NULL != prev_PreCreateCollation_hook) { - (*prev_PreCreateCollation_hook)(collprovider, - collisdeterministic, - collencoding, - &collcollate, - &collctype, - collversion); + (*prev_PreCreateCollation_hook) (collprovider, + collisdeterministic, + collencoding, + &collcollate, + &collctype, + collversion); *pCollcollate = collcollate; *pCollctype = collctype; } @@ -1396,17 +1452,18 @@ void BabelfishPreCreateCollation_hook( if (bbf_default_locale && strlen(bbf_default_locale) > 0) { - /* If the first character of the locale is '@' and if - * a babelfishpg_tsql_default_locale override has been specified, then - * prepend the babelfishpg_tsql_default_locale to the specified locale. - * Note that since the target is a const char *, we - * cannot modify the initial string, but we can modify - * the pointer to point somewhere else. + /* + * If the first character of the locale is '@' and if a + * babelfishpg_tsql_default_locale override has been specified, then + * prepend the babelfishpg_tsql_default_locale to the specified + * locale. Note that since the target is a const char *, we cannot + * modify the initial string, but we can modify the pointer to point + * somewhere else. */ if (collcollate[0] == '@') { - size_t totallen = strlen(bbf_default_locale) + strlen(collcollate) + 1; - char *catcollcollate = palloc0(totallen); + size_t totallen = strlen(bbf_default_locale) + strlen(collcollate) + 1; + char *catcollcollate = palloc0(totallen); memcpy(catcollcollate, bbf_default_locale, strlen(bbf_default_locale)); strncat(catcollcollate, collcollate, totallen); @@ -1415,8 +1472,8 @@ void BabelfishPreCreateCollation_hook( if (collctype[0] == '@') { - size_t totallen = strlen(bbf_default_locale) + strlen(collctype) + 1; - char *catcollctype = palloc0(totallen); + size_t totallen = strlen(bbf_default_locale) + strlen(collctype) + 1; + char *catcollctype = palloc0(totallen); memcpy(catcollctype, bbf_default_locale, strlen(bbf_default_locale)); strncat(catcollctype, collcollate, totallen); @@ -1430,7 +1487,7 @@ get_oid_from_collidx(int collidx) { if (collidx > NOT_FOUND) return coll_infos[collidx].oid; - + return InvalidOid; } @@ -1472,16 +1529,17 @@ babelfish_define_type_default_collation(Oid typeNamespace) if (strcmp(get_namespace_name(typeNamespace), "sys") != 0) return DEFAULT_COLLATION_OID; - /* - * If upgrade is going on then we should use oid corresponding to + /* + * If upgrade is going on then we should use oid corresponding to * babelfishpg_tsql.restored_server_collation_name. */ - if ((babelfish_dump_restore && + if ((babelfish_dump_restore && strncmp(babelfish_dump_restore, "on", 2) == 0) && - babelfish_restored_server_collation_name) + babelfish_restored_server_collation_name) return get_collation_oid_internal(babelfish_restored_server_collation_name); - get_server_collation_oid_internal(false); /* set and cache server_collation_oid */ + get_server_collation_oid_internal(false); /* set and cache + * server_collation_oid */ Assert(OidIsValid(server_collation_oid)); @@ -1506,6 +1564,7 @@ Datum babelfish_update_server_collation_name(PG_FUNCTION_ARGS) { MemoryContext oldContext; + /* If babelfish_restored_server_collation_name is set then use it. */ if (babelfish_restored_server_collation_name == NULL) { diff --git a/contrib/babelfishpg_common/src/collation.h b/contrib/babelfishpg_common/src/collation.h index 72043d7b89..b0e44e8bc5 100644 --- a/contrib/babelfishpg_common/src/collation.h +++ b/contrib/babelfishpg_common/src/collation.h @@ -21,137 +21,141 @@ extern char *babelfish_restored_server_collation_name; typedef struct coll_translate { - const char * from_collname; - const char * to_collname; - int32_t code_page; + const char *from_collname; + const char *to_collname; + int32_t code_page; } coll_translate_t; typedef struct coll_info { - Oid oid; /* oid is only retrievable during runtime, so we have to init to 0 */ + Oid oid; /* oid is only retrievable during runtime, so + * we have to init to 0 */ const char *collname; - int32_t lcid; /* lcid */ - int32_t ver; /* Ver */ - int32_t style; /* Style */ - int32_t sortid; /* Sort id */ - int32_t collateflags; /* Collate flags, changes based on case, accent, kana, width, bin */ - int32_t code_page; /* Code Page */ - pg_enc enc; /* encoding */ + int32_t lcid; /* lcid */ + int32_t ver; /* Ver */ + int32_t style; /* Style */ + int32_t sortid; /* Sort id */ + int32_t collateflags; /* Collate flags, changes based on case, + * accent, kana, width, bin */ + int32_t code_page; /* Code Page */ + pg_enc enc; /* encoding */ } coll_info; #define MAX_ICU_LOCALE_LEN sizeof("es_TRADITIONAL") typedef struct locale_info { - int32_t lcid; /* locale identifier */ - int32_t code_page; /* default code page or 0 if Unicode-only */ - pg_enc enc; /* encoding corresponding to lcid */ - char icu_locale [MAX_ICU_LOCALE_LEN + 1]; /* See https://www.localeplanet.com/icu/ */ + int32_t lcid; /* locale identifier */ + int32_t code_page; /* default code page or 0 if Unicode-only */ + pg_enc enc; /* encoding corresponding to lcid */ + char icu_locale[MAX_ICU_LOCALE_LEN + 1]; /* See + * https://www.localeplanet.com/icu/ */ } locale_info; -typedef struct ht_oid2collid_entry { - Oid key; - uint8_t persist_id; +typedef struct ht_oid2collid_entry +{ + Oid key; + uint8_t persist_id; } ht_oid2collid_entry; typedef struct like_ilike_info { - Oid like_oid; /* oid for like operators */ - char * like_op_name; /* the operator name for LIKE */ - char * ilike_op_name; /* the operator name for corresponding LIKE */ - char * op_left_schema; /* the schema of left operand */ - char * op_left_name; /* the name of left operand */ - char * op_right_schema; /* the schema of right operand */ - char * op_right_name; /* the name of right operand */ - bool is_not_match; /* if this is a NOT LIKE operator*/ - Oid ilike_oid; /* oid for corresponding ilike operators */ - Oid ilike_opfuncid; /* oid for corresponding ILIKE func */ + Oid like_oid; /* oid for like operators */ + char *like_op_name; /* the operator name for LIKE */ + char *ilike_op_name; /* the operator name for corresponding LIKE */ + char *op_left_schema; /* the schema of left operand */ + char *op_left_name; /* the name of left operand */ + char *op_right_schema; /* the schema of right operand */ + char *op_right_name; /* the name of right operand */ + bool is_not_match; /* if this is a NOT LIKE operator */ + Oid ilike_oid; /* oid for corresponding ilike operators */ + Oid ilike_opfuncid; /* oid for corresponding ILIKE func */ } like_ilike_info; -typedef struct ht_like2ilike_entry{ - Oid key; - uint8_t persist_id; +typedef struct ht_like2ilike_entry +{ + Oid key; + uint8_t persist_id; } ht_like2ilike_entry_t; typedef struct collation_callbacks { /* Function pointers set up by the plugin */ - char* (*EncodingConversion)(const char *s, int len, int src_encoding, int dest_encoding, int *encodedByteLen); + char *(*EncodingConversion) (const char *s, int len, int src_encoding, int dest_encoding, int *encodedByteLen); - Oid (*get_server_collation_oid_internal)(bool missingOk); + Oid (*get_server_collation_oid_internal) (bool missingOk); - coll_info (*lookup_collation_table_callback) (Oid oid); + coll_info (*lookup_collation_table_callback) (Oid oid); - like_ilike_info (*lookup_like_ilike_table)(Oid opno); + like_ilike_info (*lookup_like_ilike_table) (Oid opno); - Datum (*collation_list_internal)(PG_FUNCTION_ARGS); + Datum (*collation_list_internal) (PG_FUNCTION_ARGS); - Datum (*is_collated_ci_as_internal)(PG_FUNCTION_ARGS); + Datum (*is_collated_ci_as_internal) (PG_FUNCTION_ARGS); - int (*collationproperty_helper)(const char *collationaname, const char *property); + int (*collationproperty_helper) (const char *collationaname, const char *property); - bytea* (*tdscollationproperty_helper)(const char *collationaname, const char *property); + bytea *(*tdscollationproperty_helper) (const char *collationaname, const char *property); - bool (*is_server_collation_CI_AS)(void); + bool (*is_server_collation_CI_AS) (void); - bool (*is_valid_server_collation_name)(const char *collationname); + bool (*is_valid_server_collation_name) (const char *collationname); - int (*find_locale)(const char *locale); + int (*find_locale) (const char *locale); - Oid (*get_oid_from_collidx_internal)(int collidx); + Oid (*get_oid_from_collidx_internal) (int collidx); - int (*find_cs_as_collation_internal)(int collidx); + int (*find_cs_as_collation_internal) (int collidx); - int (*find_collation_internal)(const char *collation_name); + int (*find_collation_internal) (const char *collation_name); - bool (*has_ilike_node)(Node *expr); + bool (*has_ilike_node) (Node *expr); - const char* (*translate_bbf_collation_to_tsql_collation)(const char *collname); + const char *(*translate_bbf_collation_to_tsql_collation) (const char *collname); } collation_callbacks; -extern int find_cs_as_collation(int collidx); -extern int find_any_collation(const char *collation_name, bool check_for_server_collation_name_guc); -extern Oid get_server_collation_oid_internal(bool missingOk); +extern int find_cs_as_collation(int collidx); +extern int find_any_collation(const char *collation_name, bool check_for_server_collation_name_guc); +extern Oid get_server_collation_oid_internal(bool missingOk); extern coll_info lookup_collation_table(Oid collid); extern int8_t cmp_collation(uint16_t coll1, uint16_t coll2); extern bool collation_is_CI_AS(Oid colloid); extern bool is_valid_server_collation_name(const char *collname); -extern Oid get_tsql_collation_oid(int persist_coll_id); -extern int get_persist_collation_id(Oid coll_oid); -extern int find_locale(const char *given_locale); -extern int get_server_collation_collidx(void); +extern Oid get_tsql_collation_oid(int persist_coll_id); +extern int get_persist_collation_id(Oid coll_oid); +extern int find_locale(const char *given_locale); +extern int get_server_collation_collidx(void); extern Datum collation_list_internal(PG_FUNCTION_ARGS); extern Datum is_collated_ci_as_internal(PG_FUNCTION_ARGS); -extern int collationproperty_helper(const char *collationaname, const char *property); -extern bytea* tdscollationproperty_helper(const char *collationname, const char *property); +extern int collationproperty_helper(const char *collationaname, const char *property); +extern bytea *tdscollationproperty_helper(const char *collationname, const char *property); extern bool is_server_collation_CI_AS(void); -extern int translate_collation(const char *collation_name, bool check_for_server_collation_name_guc); -extern int init_collid_trans_tab_internal(void); -extern int init_like_ilike_table_internal(void); +extern int translate_collation(const char *collation_name, bool check_for_server_collation_name_guc); +extern int init_collid_trans_tab_internal(void); +extern int init_like_ilike_table_internal(void); extern like_ilike_info lookup_like_ilike_table(Oid opno); -extern int find_collation(const char *collation_name); -extern const char* translate_bbf_collation_to_tsql_collation(const char *collname); -Oid get_oid_from_collidx(int collidx); +extern int find_collation(const char *collation_name); +extern const char *translate_bbf_collation_to_tsql_collation(const char *collname); +Oid get_oid_from_collidx(int collidx); extern bool has_ilike_node(Node *expr); -extern Oid babelfish_define_type_default_collation(Oid typeNamespace); +extern Oid babelfish_define_type_default_collation(Oid typeNamespace); extern collation_callbacks *get_collation_callbacks(void); /* Hooks defined in collation.c */ -extern Oid BABELFISH_CLUSTER_COLLATION_OID(void); +extern Oid BABELFISH_CLUSTER_COLLATION_OID(void); -extern const char * -BabelfishTranslateCollation(const char *collname, Oid collnamespace, int32 encoding); +extern const char *BabelfishTranslateCollation(const char *collname, Oid collnamespace, int32 encoding); extern void -BabelfishPreCreateCollation_hook( - char collprovider, - bool collisdeterministic, - int32 collencoding, - const char **collcollate, - const char **collctype, - const char *collversion); + BabelfishPreCreateCollation_hook( + char collprovider, + bool collisdeterministic, + int32 collencoding, + const char **collcollate, + const char **collctype, + const char *collversion); extern TranslateCollation_hook_type prev_TranslateCollation_hook; extern PreCreateCollation_hook_type prev_PreCreateCollation_hook; diff --git a/contrib/babelfishpg_common/src/datetime.c b/contrib/babelfishpg_common/src/datetime.c index f977e285f7..f0a6f34ed6 100644 --- a/contrib/babelfishpg_common/src/datetime.c +++ b/contrib/babelfishpg_common/src/datetime.c @@ -43,8 +43,8 @@ PG_FUNCTION_INFO_V1(float8_mi_datetime); PG_FUNCTION_INFO_V1(datetime_pl_datetime); PG_FUNCTION_INFO_V1(datetime_mi_datetime); -void CheckDatetimeRange(const Timestamp time); -void CheckDatetimePrecision(fsec_t fsec); +void CheckDatetimeRange(const Timestamp time); +void CheckDatetimePrecision(fsec_t fsec); Datum datetime_in_str(char *str) @@ -65,7 +65,8 @@ datetime_in_str(char *str) char workbuf[MAXDATELEN + MAXDATEFIELDS]; /* - * Set input to default '1900-01-01 00:00:00.000' if empty string encountered + * Set input to default '1900-01-01 00:00:00.000' if empty string + * encountered */ if (*str == '\0') { @@ -77,8 +78,8 @@ datetime_in_str(char *str) field, ftype, MAXDATEFIELDS, &nf); if (dterr == 0) dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz); - // dterr == 1 means that input is TIME format(e.g 12:34:59.123) - // initialize other necessary date parts and accept input format + /* dterr == 1 means that input is TIME format(e.g 12:34:59.123) */ + /* initialize other necessary date parts and accept input format */ if (dterr == 1) { tm->tm_year = 1900; @@ -114,8 +115,10 @@ datetime_in_str(char *str) dtype, str); TIMESTAMP_NOEND(result); } - /* TODO: round datetime fsec to fixed bins (e.g. .000, .003, .007) - * see: BABEL-1081 + + /* + * TODO: round datetime fsec to fixed bins (e.g. .000, .003, .007) see: + * BABEL-1081 */ CheckDatetimeRange(result); CheckDatetimePrecision(fsec); @@ -132,7 +135,8 @@ datetime_in_str(char *str) Datum datetime_in(PG_FUNCTION_ARGS) { - char *str = PG_GETARG_CSTRING(0); + char *str = PG_GETARG_CSTRING(0); + return datetime_in_str(str); } @@ -153,7 +157,7 @@ datetime_out(PG_FUNCTION_ARGS) EncodeSpecialTimestamp(timestamp, buf); else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0) { - // round fractional seconds to datetime precision + /* round fractional seconds to datetime precision */ fsec = DTROUND(fsec); EncodeDateTime(tm, fsec, false, 0, NULL, DateStyle, buf); } @@ -174,8 +178,8 @@ CheckDatetimeRange(const Timestamp time) if (!IS_VALID_DATETIME(time)) { ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("data out of range for datetime"))); + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("data out of range for datetime"))); } } @@ -188,8 +192,8 @@ CheckDatetimePrecision(fsec_t fsec) if (!IS_VALID_DT_PRECISION(fsec)) { ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("data precision out of range for datetime"))); + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("data precision out of range for datetime"))); } } @@ -222,22 +226,22 @@ time_datetime(PG_FUNCTION_ARGS) TimeADT timeVal = PG_GETARG_TIMEADT(0); Timestamp result; - struct pg_tm tt, + struct pg_tm tt, *tm = &tt; fsec_t fsec; - // Initialize default year, month, day + /* Initialize default year, month, day */ tm->tm_year = 1900; tm->tm_mon = 1; tm->tm_mday = 1; - - // Convert TimeADT type to tm + + /* Convert TimeADT type to tm */ time2tm(timeVal, tm, &fsec); if (tm2timestamp(tm, fsec, NULL, &result) != 0) - ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("data out of range for datetime"))); + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("data out of range for datetime"))); PG_RETURN_TIMESTAMP(result); } @@ -248,7 +252,7 @@ time_datetime(PG_FUNCTION_ARGS) Datum timestamp_datetime(PG_FUNCTION_ARGS) { - Timestamp result = PG_GETARG_TIMESTAMP(0); + Timestamp result = PG_GETARG_TIMESTAMP(0); CheckDatetimeRange(result); PG_RETURN_TIMESTAMP(result); @@ -303,7 +307,7 @@ datetime_varchar(PG_FUNCTION_ARGS) EncodeSpecialTimestamp(timestamp, buf); else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0) { - // round fractional seconds to datetime precision + /* round fractional seconds to datetime precision */ fsec = DTROUND(fsec); EncodeDateTime(tm, fsec, false, 0, NULL, DateStyle, buf); } @@ -323,8 +327,8 @@ datetime_varchar(PG_FUNCTION_ARGS) Datum varchar_datetime(PG_FUNCTION_ARGS) { - Datum txt = PG_GETARG_DATUM(0); - char *str = TextDatumGetCString(txt); + Datum txt = PG_GETARG_DATUM(0); + char *str = TextDatumGetCString(txt); return datetime_in_str(str); } @@ -347,7 +351,7 @@ datetime_char(PG_FUNCTION_ARGS) EncodeSpecialTimestamp(timestamp, buf); else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0) { - // round fractional seconds to datetime precision + /* round fractional seconds to datetime precision */ fsec = DTROUND(fsec); EncodeDateTime(tm, fsec, false, 0, NULL, DateStyle, buf); } @@ -367,8 +371,8 @@ datetime_char(PG_FUNCTION_ARGS) Datum char_datetime(PG_FUNCTION_ARGS) { - Datum txt = PG_GETARG_DATUM(0); - char *str = TextDatumGetCString(txt); + Datum txt = PG_GETARG_DATUM(0); + char *str = TextDatumGetCString(txt); return datetime_in_str(str); } @@ -376,17 +380,17 @@ char_datetime(PG_FUNCTION_ARGS) /* * datetime_pl_int4() * operator function for adding datetime plus int - * + * * simply add number of days to date value, while preserving the time * component */ Datum datetime_pl_int4(PG_FUNCTION_ARGS) -{ +{ Timestamp timestamp = PG_GETARG_TIMESTAMP(0); int32 days = PG_GETARG_INT32(1); Timestamp result; - Interval *input_interval; + Interval *input_interval; if (TIMESTAMP_NOT_FINITE(timestamp)) PG_RETURN_TIMESTAMP(timestamp); @@ -404,12 +408,12 @@ datetime_pl_int4(PG_FUNCTION_ARGS) /* * int4_mi_datetime() * Operator function for subtracting int minus datetime - * + * * Convert the input int32 value d to datetime(1/1/1900) + d days. - * Then add the difference between the input datetime value and the one + * Then add the difference between the input datetime value and the one * above to the default datetime value (1/1/1900). - * - * ex: + * + * ex: * d = 9, dt = '1/11/1900' * dt_left = datetime(1/1/1900) + 9 days = datetime(1/10/1900) * diff = dt_left - dt = -1 day @@ -417,27 +421,30 @@ datetime_pl_int4(PG_FUNCTION_ARGS) */ Datum int4_mi_datetime(PG_FUNCTION_ARGS) -{ +{ int32 days = PG_GETARG_INT32(0); Timestamp timestamp_right = PG_GETARG_TIMESTAMP(1); Timestamp result; Timestamp default_timestamp; Timestamp timestamp_left; - Interval *input_interval; - Interval *result_interval; + Interval *input_interval; + Interval *result_interval; if (TIMESTAMP_NOT_FINITE(timestamp_right)) PG_RETURN_TIMESTAMP(timestamp_right); /* inialize input int(days) as timestamp */ - default_timestamp = DirectFunctionCall6(make_timestamp, 1900, 1, 1, 0, 0,0); + default_timestamp = DirectFunctionCall6(make_timestamp, 1900, 1, 1, 0, 0, 0); input_interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, days, 0, 0, 0); timestamp_left = DirectFunctionCall2(timestamp_pl_interval, default_timestamp, PointerGetDatum(input_interval)); /* calculate timestamp diff */ result_interval = (Interval *) DirectFunctionCall2(timestamp_mi, timestamp_left, timestamp_right); - /* if the diff between left and right timestamps is positive, then we add the interval. else, subtract */ + /* + * if the diff between left and right timestamps is positive, then we add + * the interval. else, subtract + */ result = DirectFunctionCall2(timestamp_pl_interval, default_timestamp, PointerGetDatum(result_interval)); CheckDatetimeRange(result); @@ -450,9 +457,10 @@ int4_mi_datetime(PG_FUNCTION_ARGS) */ Datum int4_pl_datetime(PG_FUNCTION_ARGS) -{ +{ int32 days = PG_GETARG_INT32(0); Timestamp timestamp = PG_GETARG_TIMESTAMP(1); + PG_RETURN_TIMESTAMP(DirectFunctionCall2(datetime_pl_int4, timestamp, days)); } @@ -462,9 +470,10 @@ int4_pl_datetime(PG_FUNCTION_ARGS) */ Datum datetime_mi_int4(PG_FUNCTION_ARGS) -{ +{ Timestamp timestamp = PG_GETARG_TIMESTAMP(0); int32 days = PG_GETARG_INT32(1); + PG_RETURN_TIMESTAMP(DirectFunctionCall2(datetime_pl_int4, timestamp, -days)); } @@ -472,19 +481,20 @@ datetime_mi_int4(PG_FUNCTION_ARGS) /* * datetime_pl_float8() * operator function for adding datetime plus float - * + * * simply add number of days/secs to date value, while preserving the time * component */ Datum datetime_pl_float8(PG_FUNCTION_ARGS) -{ +{ Timestamp timestamp = PG_GETARG_TIMESTAMP(0); double days = PG_GETARG_FLOAT8(1); - double day_whole, day_fract; - Interval *input_interval; + double day_whole, + day_fract; + Interval *input_interval; Timestamp result; - + if (TIMESTAMP_NOT_FINITE(timestamp)) PG_RETURN_TIMESTAMP(timestamp); @@ -492,7 +502,7 @@ datetime_pl_float8(PG_FUNCTION_ARGS) day_fract = modf(days, &day_whole); /* make interval */ - input_interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, (int32) day_whole, 0, 0, Float8GetDatum(SECS_PER_DAY*day_fract)); + input_interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, (int32) day_whole, 0, 0, Float8GetDatum(SECS_PER_DAY * day_fract)); /* add interval */ result = DirectFunctionCall2(timestamp_pl_interval, timestamp, PointerGetDatum(input_interval)); @@ -505,22 +515,23 @@ datetime_pl_float8(PG_FUNCTION_ARGS) /* * float8_mi_datetime() * Operator function for subtracting float8 minus datetime - * + * * Convert the input float8 value d to datetime(1/1/1900) + d days. - * Then add the difference between the input datetime value and the one + * Then add the difference between the input datetime value and the one * above to the default datetime value (1/1/1900). */ Datum float8_mi_datetime(PG_FUNCTION_ARGS) -{ +{ double days = PG_GETARG_FLOAT8(0); Timestamp timestamp_right = PG_GETARG_TIMESTAMP(1); - double day_whole, day_fract; + double day_whole, + day_fract; Timestamp result; Timestamp default_timestamp; Timestamp timestamp_left; - Interval *input_interval; - Interval *result_interval; + Interval *input_interval; + Interval *result_interval; if (TIMESTAMP_NOT_FINITE(timestamp_right)) PG_RETURN_TIMESTAMP(timestamp_right); @@ -529,17 +540,20 @@ float8_mi_datetime(PG_FUNCTION_ARGS) day_fract = modf(days, &day_whole); /* make interval */ - input_interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, (int32) day_whole, 0, 0, Float8GetDatum(SECS_PER_DAY*day_fract)); + input_interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, (int32) day_whole, 0, 0, Float8GetDatum(SECS_PER_DAY * day_fract)); /* inialize input int(days) as timestamp */ - default_timestamp = DirectFunctionCall6(make_timestamp, 1900, 1, 1, 0, 0,0); + default_timestamp = DirectFunctionCall6(make_timestamp, 1900, 1, 1, 0, 0, 0); timestamp_left = DirectFunctionCall2(timestamp_pl_interval, default_timestamp, PointerGetDatum(input_interval)); /* calculate timestamp diff */ result_interval = (Interval *) DirectFunctionCall2(timestamp_mi, timestamp_left, timestamp_right); - /* if the diff between left and right timestamps is positive, then we add the interval. else, subtract */ + /* + * if the diff between left and right timestamps is positive, then we add + * the interval. else, subtract + */ result = DirectFunctionCall2(timestamp_pl_interval, default_timestamp, PointerGetDatum(result_interval)); @@ -553,13 +567,14 @@ float8_mi_datetime(PG_FUNCTION_ARGS) */ Datum float8_pl_datetime(PG_FUNCTION_ARGS) -{ +{ double days = PG_GETARG_FLOAT8(0); Timestamp timestamp = PG_GETARG_TIMESTAMP(1); - double day_whole, day_fract; - Interval *input_interval; + double day_whole, + day_fract; + Interval *input_interval; Timestamp result; - + if (TIMESTAMP_NOT_FINITE(timestamp)) PG_RETURN_TIMESTAMP(timestamp); @@ -567,7 +582,7 @@ float8_pl_datetime(PG_FUNCTION_ARGS) day_fract = modf(days, &day_whole); /* make interval */ - input_interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, (int32) day_whole, 0, 0, Float8GetDatum(SECS_PER_DAY*day_fract)); + input_interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, (int32) day_whole, 0, 0, Float8GetDatum(SECS_PER_DAY * day_fract)); /* add interval */ result = DirectFunctionCall2(timestamp_pl_interval, timestamp, PointerGetDatum(input_interval)); @@ -582,13 +597,14 @@ float8_pl_datetime(PG_FUNCTION_ARGS) */ Datum datetime_mi_float8(PG_FUNCTION_ARGS) -{ +{ Timestamp timestamp = PG_GETARG_TIMESTAMP(0); double days = PG_GETARG_FLOAT8(1); - double day_whole, day_fract; - Interval *input_interval; + double day_whole, + day_fract; + Interval *input_interval; Timestamp result; - + if (TIMESTAMP_NOT_FINITE(timestamp)) PG_RETURN_TIMESTAMP(timestamp); @@ -596,7 +612,7 @@ datetime_mi_float8(PG_FUNCTION_ARGS) day_fract = modf(days, &day_whole); /* make interval */ - input_interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, (int32) day_whole, 0, 0, Float8GetDatum(SECS_PER_DAY*day_fract)); + input_interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, (int32) day_whole, 0, 0, Float8GetDatum(SECS_PER_DAY * day_fract)); /* subtract interval */ @@ -612,8 +628,9 @@ datetime_mi_float8(PG_FUNCTION_ARGS) Timestamp initializeToDefaultDatetime(void) { - Timestamp result; - struct pg_tm tt, *tm = &tt; + Timestamp result; + struct pg_tm tt, + *tm = &tt; tm->tm_year = 1900; tm->tm_mon = 1; @@ -623,19 +640,22 @@ initializeToDefaultDatetime(void) tm2timestamp(tm, 0, NULL, &result); return result; -} +} Datum datetime_pl_datetime(PG_FUNCTION_ARGS) { - Timestamp timestamp1 = PG_GETARG_TIMESTAMP(0); - Timestamp timestamp2 = PG_GETARG_TIMESTAMP(1); - Timestamp diff; - Timestamp result; + Timestamp timestamp1 = PG_GETARG_TIMESTAMP(0); + Timestamp timestamp2 = PG_GETARG_TIMESTAMP(1); + Timestamp diff; + Timestamp result; - /* calculate interval from timestamp2. It should be calculated as the difference from 1900-01-01 00:00:00 (default datetime) */ + /* + * calculate interval from timestamp2. It should be calculated as the + * difference from 1900-01-01 00:00:00 (default datetime) + */ diff = timestamp2 - initializeToDefaultDatetime(); - + /* add interval */ result = timestamp1 + diff; @@ -646,14 +666,17 @@ datetime_pl_datetime(PG_FUNCTION_ARGS) Datum datetime_mi_datetime(PG_FUNCTION_ARGS) { - Timestamp timestamp1 = PG_GETARG_TIMESTAMP(0); - Timestamp timestamp2 = PG_GETARG_TIMESTAMP(1); - Timestamp diff; - Timestamp result; + Timestamp timestamp1 = PG_GETARG_TIMESTAMP(0); + Timestamp timestamp2 = PG_GETARG_TIMESTAMP(1); + Timestamp diff; + Timestamp result; - /* calculate interval from timestamp2. It should be calculated as the difference from 1900-01-01 00:00:00 (default datetime) */ + /* + * calculate interval from timestamp2. It should be calculated as the + * difference from 1900-01-01 00:00:00 (default datetime) + */ diff = timestamp2 - initializeToDefaultDatetime(); - + /* subtract interval */ result = timestamp1 - diff; diff --git a/contrib/babelfishpg_common/src/datetime.h b/contrib/babelfishpg_common/src/datetime.h index 6a021e05c1..73110ae1aa 100644 --- a/contrib/babelfishpg_common/src/datetime.h +++ b/contrib/babelfishpg_common/src/datetime.h @@ -14,7 +14,7 @@ #define DT_PREC_INV 1000 #define DTROUND(j) ((((int) (j / DT_PREC_INV)) * DT_PREC_INV)) -/* TODO: round datetime fsec to fixed bins (e.g. .000, .003, .007) +/* TODO: round datetime fsec to fixed bins (e.g. .000, .003, .007) * see: BABEL-1081 */ diff --git a/contrib/babelfishpg_common/src/datetime2.c b/contrib/babelfishpg_common/src/datetime2.c index 3dc12e8137..f8ffd8ce2e 100644 --- a/contrib/babelfishpg_common/src/datetime2.c +++ b/contrib/babelfishpg_common/src/datetime2.c @@ -34,7 +34,7 @@ PG_FUNCTION_INFO_V1(char_datetime2); static void AdjustDatetime2ForTypmod(Timestamp *time, int32 typmod); static Datum datetime2_in_str(char *str, int32 typmod); -void CheckDatetime2Range(const Timestamp time); +void CheckDatetime2Range(const Timestamp time); /* datetime2_in_str() * Convert a string to internal form. @@ -69,10 +69,10 @@ datetime2_in_str(char *str, int32 typmod) field, ftype, MAXDATEFIELDS, &nf); if (dterr == 0) dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz); - - /* - * dterr == 1 means that input is TIME format(e.g 12:34:59.123) - * initialize other necessary date parts and accept input format + + /* + * dterr == 1 means that input is TIME format(e.g 12:34:59.123) initialize + * other necessary date parts and accept input format */ if (dterr == 1) { @@ -85,12 +85,12 @@ datetime2_in_str(char *str, int32 typmod) if (dterr != 0) DateTimeParseError(dterr, str, "datetime2"); - /* - * Caps upper limit on fractional seconds(999999 microseconds) so - * that the upper boundary for datetime2 is not exceeded when - * the Date and Time parts are at the upper value limit + /* + * Caps upper limit on fractional seconds(999999 microseconds) so that the + * upper boundary for datetime2 is not exceeded when the Date and Time + * parts are at the upper value limit */ - if ((fsec == USECS_PER_SEC) && + if ((fsec == USECS_PER_SEC) && (tm->tm_year == 9999) && (tm->tm_mon == 12) && (tm->tm_mday == 31) && @@ -125,7 +125,7 @@ datetime2_in_str(char *str, int32 typmod) dtype, str); TIMESTAMP_NOEND(result); } - AdjustDatetime2ForTypmod(&result, typmod); + AdjustDatetime2ForTypmod(&result, typmod); CheckDatetime2Range(result); PG_RETURN_TIMESTAMP(result); @@ -139,17 +139,17 @@ datetime2_in_str(char *str, int32 typmod) Datum datetime2_in(PG_FUNCTION_ARGS) { - char *str = PG_GETARG_CSTRING(0); - #ifdef NOT_USED + char *str = PG_GETARG_CSTRING(0); +#ifdef NOT_USED Oid typelem = PG_GETARG_OID(1); - #endif - int32 typmod = PG_GETARG_INT32(2); +#endif + int32 typmod = PG_GETARG_INT32(2); return datetime2_in_str(str, typmod); } /* AdjustDatetime2ForTypmod() - * round off a datetime2 to suit given typmod + * round off a datetime2 to suit given typmod */ static void AdjustDatetime2ForTypmod(Timestamp *time, int32 typmod) @@ -188,7 +188,7 @@ AdjustDatetime2ForTypmod(Timestamp *time, int32 typmod) INT64CONST(0) }; - int64 adjustedTime; + int64 adjustedTime; if (!TIMESTAMP_NOT_FINITE(*time) && (typmod != -1)) @@ -200,17 +200,18 @@ AdjustDatetime2ForTypmod(Timestamp *time, int32 typmod) typmod, 0, MAX_DATETIME2_PRECISION))); if (*time >= INT64CONST(0)) - { + { adjustedTime = ((*time + TimestampOffsets[typmod]) / TimestampScales[typmod]) * TimestampScales[typmod]; /* Make sure typmod doesn't push datetime2 out of range */ if (adjustedTime < END_DATETIME2) *time = adjustedTime; - /* - * If applying typmod pushes datetime2 out of range, simply + + /* + * If applying typmod pushes datetime2 out of range, simply * truncate fractional seconds to typmod precision */ - else + else { *time = (*time / TimestampScales[typmod]) * TimestampScales[typmod]; } @@ -233,8 +234,8 @@ CheckDatetime2Range(const Timestamp time) if (!IS_VALID_DATETIME2(time)) { ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("data out of range for datetime2"))); + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("data out of range for datetime2"))); } } @@ -266,22 +267,22 @@ time_datetime2(PG_FUNCTION_ARGS) TimeADT timeVal = PG_GETARG_TIMEADT(0); Timestamp result; - struct pg_tm tt, + struct pg_tm tt, *tm = &tt; fsec_t fsec; - + /* Initialize default year, month, day */ tm->tm_year = 1900; tm->tm_mon = 1; tm->tm_mday = 1; - + /* Convert TimeADT type to tm */ time2tm(timeVal, tm, &fsec); if (tm2timestamp(tm, fsec, NULL, &result) != 0) - ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("data out of range for datetime2"))); + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("data out of range for datetime2"))); PG_RETURN_TIMESTAMP(result); } @@ -292,7 +293,8 @@ time_datetime2(PG_FUNCTION_ARGS) Datum timestamp_datetime2(PG_FUNCTION_ARGS) { - Timestamp result = PG_GETARG_TIMESTAMP(0); + Timestamp result = PG_GETARG_TIMESTAMP(0); + CheckDatetime2Range(result); PG_RETURN_TIMESTAMP(result); } @@ -335,9 +337,9 @@ timestamptz_datetime2(PG_FUNCTION_ARGS) Datum datetime2_scale(PG_FUNCTION_ARGS) { - Timestamp result = PG_GETARG_TIMESTAMP(0); + Timestamp result = PG_GETARG_TIMESTAMP(0); int32 typmod = PG_GETARG_INT32(1); - + AdjustDatetime2ForTypmod(&result, typmod); PG_RETURN_TIMESTAMP(result); } @@ -377,8 +379,8 @@ datetime2_varchar(PG_FUNCTION_ARGS) Datum varchar_datetime2(PG_FUNCTION_ARGS) { - Datum txt = PG_GETARG_DATUM(0); - char *str = TextDatumGetCString(txt); + Datum txt = PG_GETARG_DATUM(0); + char *str = TextDatumGetCString(txt); return datetime2_in_str(str, MAX_TIMESTAMP_PRECISION); } @@ -418,11 +420,8 @@ datetime2_char(PG_FUNCTION_ARGS) Datum char_datetime2(PG_FUNCTION_ARGS) { - Datum txt = PG_GETARG_DATUM(0); - char *str = TextDatumGetCString(txt); + Datum txt = PG_GETARG_DATUM(0); + char *str = TextDatumGetCString(txt); return datetime2_in_str(str, MAX_TIMESTAMP_PRECISION); } - - - diff --git a/contrib/babelfishpg_common/src/datetime2.h b/contrib/babelfishpg_common/src/datetime2.h index c19d8d1ed1..2f07e1fb72 100644 --- a/contrib/babelfishpg_common/src/datetime2.h +++ b/contrib/babelfishpg_common/src/datetime2.h @@ -20,4 +20,4 @@ /* Range-check a datetime */ #define IS_VALID_DATETIME2(t) (MIN_DATETIME2 <= (t) && (t) < END_DATETIME2) -#endif /* PLTSQL_DATETIME2_H */ \ No newline at end of file +#endif /* PLTSQL_DATETIME2_H */ diff --git a/contrib/babelfishpg_common/src/datetimeoffset.c b/contrib/babelfishpg_common/src/datetimeoffset.c index cbe6ab6552..312da22007 100644 --- a/contrib/babelfishpg_common/src/datetimeoffset.c +++ b/contrib/babelfishpg_common/src/datetimeoffset.c @@ -20,9 +20,9 @@ #include "datetime.h" static void AdjustDatetimeoffsetForTypmod(Timestamp *time, int32 typmod); -static void CheckDatetimeoffsetRange(const tsql_datetimeoffset* df); -static int datetimeoffset_cmp_internal(tsql_datetimeoffset* df1, tsql_datetimeoffset* df2); -static void datetimeoffset_timestamp_internal(const tsql_datetimeoffset *df, Timestamp* time); +static void CheckDatetimeoffsetRange(const tsql_datetimeoffset *df); +static int datetimeoffset_cmp_internal(tsql_datetimeoffset *df1, tsql_datetimeoffset *df2); +static void datetimeoffset_timestamp_internal(const tsql_datetimeoffset *df, Timestamp *time); static void EncodeDatetimeoffsetTimezone(char *str, int tz, int style); PG_FUNCTION_INFO_V1(datetimeoffset_in); @@ -79,8 +79,8 @@ datetimeoffset_in(PG_FUNCTION_ARGS) Oid typelem = PG_GETARG_OID(1); #endif int32 typmod = PG_GETARG_INT32(2); - tsql_datetimeoffset* datetimeoffset; - Timestamp tsql_ts; + tsql_datetimeoffset *datetimeoffset; + Timestamp tsql_ts; fsec_t fsec; struct pg_tm tt, *tm = &tt; @@ -92,14 +92,17 @@ datetimeoffset_in(PG_FUNCTION_ARGS) int ftype[MAXDATEFIELDS]; char workbuf[MAXDATELEN + MAXDATEFIELDS]; - datetimeoffset = (tsql_datetimeoffset *)palloc(DATETIMEOFFSET_LEN); + datetimeoffset = (tsql_datetimeoffset *) palloc(DATETIMEOFFSET_LEN); - /* Set input to default '1900-01-01 00:00:00.* 00:00' if empty string encountered */ - if (*str == '\0') + /* + * Set input to default '1900-01-01 00:00:00.* 00:00' if empty string + * encountered + */ + if (*str == '\0') { tsql_ts = initializeToDefaultDatetime(); AdjustDatetimeoffsetForTypmod(&tsql_ts, typmod); - datetimeoffset->tsql_ts = (int64)tsql_ts; + datetimeoffset->tsql_ts = (int64) tsql_ts; datetimeoffset->tsql_tz = 0; PG_RETURN_DATETIMEOFFSET(datetimeoffset); } @@ -109,8 +112,8 @@ datetimeoffset_in(PG_FUNCTION_ARGS) if (dterr == 0) dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz); - // dterr == 1 means that input is TIME format(e.g 12:34:59.123) - // initialize other necessary date parts and accept input format + /* dterr == 1 means that input is TIME format(e.g 12:34:59.123) */ + /* initialize other necessary date parts and accept input format */ if (dterr == 1) { tm->tm_year = 1900; @@ -121,7 +124,7 @@ datetimeoffset_in(PG_FUNCTION_ARGS) if (dterr != 0) DateTimeParseError(dterr, str, "timestamp with time zone"); - datetimeoffset->tsql_tz = (int16)(tz/60); + datetimeoffset->tsql_tz = (int16) (tz / 60); tz = 0; switch (dtype) { @@ -150,7 +153,7 @@ datetimeoffset_in(PG_FUNCTION_ARGS) TIMESTAMP_NOEND(tsql_ts); } AdjustDatetimeoffsetForTypmod(&tsql_ts, typmod); - datetimeoffset->tsql_ts = (int64)tsql_ts; + datetimeoffset->tsql_ts = (int64) tsql_ts; CheckDatetimeoffsetRange(datetimeoffset); PG_RETURN_DATETIMEOFFSET(datetimeoffset); @@ -162,13 +165,13 @@ datetimeoffset_in(PG_FUNCTION_ARGS) Datum datetimeoffset_out(PG_FUNCTION_ARGS) { - tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(0); + tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(0); char *result; struct pg_tm tt, *tm = &tt; fsec_t fsec; char buf[MAXDATELEN + 1]; - Timestamp timestamp; + Timestamp timestamp; timestamp = df->tsql_ts; if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0) @@ -195,7 +198,7 @@ datetimeoffset_recv(PG_FUNCTION_ARGS) Oid typelem = PG_GETARG_OID(1); #endif int32 typmod = PG_GETARG_INT32(2); - tsql_datetimeoffset *result; + tsql_datetimeoffset *result; result = (tsql_datetimeoffset *) palloc(DATETIMEOFFSET_LEN); @@ -220,7 +223,7 @@ datetimeoffset_recv(PG_FUNCTION_ARGS) Datum datetimeoffset_send(PG_FUNCTION_ARGS) { - tsql_datetimeoffset *datetimeoffset = PG_GETARG_DATETIMEOFFSET(0); + tsql_datetimeoffset *datetimeoffset = PG_GETARG_DATETIMEOFFSET(0); StringInfoData buffer; pq_begintypsend(&buffer); @@ -232,19 +235,20 @@ datetimeoffset_send(PG_FUNCTION_ARGS) /* cast datetimeoffset to timestamp internal representation */ static void -datetimeoffset_timestamp_internal(const tsql_datetimeoffset *df, Timestamp* time) +datetimeoffset_timestamp_internal(const tsql_datetimeoffset *df, Timestamp *time) { - *time = df->tsql_ts + (int64)df->tsql_tz * SECS_PER_MINUTE * USECS_PER_SEC; + *time = df->tsql_ts + (int64) df->tsql_tz * SECS_PER_MINUTE * USECS_PER_SEC; } /* * This function converts datetimeoffset to timestamp and do the comparision. */ static int -datetimeoffset_cmp_internal(tsql_datetimeoffset* df1, tsql_datetimeoffset* df2) +datetimeoffset_cmp_internal(tsql_datetimeoffset *df1, tsql_datetimeoffset *df2) { - Timestamp t1; - Timestamp t2; + Timestamp t1; + Timestamp t2; + datetimeoffset_timestamp_internal(df1, &t1); datetimeoffset_timestamp_internal(df2, &t2); @@ -310,6 +314,7 @@ datetimeoffset_cmp(PG_FUNCTION_ARGS) { tsql_datetimeoffset *df1 = PG_GETARG_DATETIMEOFFSET(0); tsql_datetimeoffset *df2 = PG_GETARG_DATETIMEOFFSET(1); + PG_RETURN_INT32(datetimeoffset_cmp_internal(df1, df2)); } @@ -351,19 +356,19 @@ datetimeoffset_pl_interval(PG_FUNCTION_ARGS) tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(0); Interval *span = PG_GETARG_INTERVAL_P(1); tsql_datetimeoffset *result = (tsql_datetimeoffset *) palloc(DATETIMEOFFSET_LEN); - Timestamp tmp = df->tsql_ts; + Timestamp tmp = df->tsql_ts; int tz; if (span->month != 0) { struct pg_tm tt, - *tm = &tt; + *tm = &tt; fsec_t fsec; if (timestamp2tm(tmp, &tz, tm, &fsec, NULL, NULL) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("datetimeoffset out of range"))); + errmsg("datetimeoffset out of range"))); tm->tm_mon += span->month; if (tm->tm_mon > MONTHS_PER_YEAR) @@ -385,20 +390,20 @@ datetimeoffset_pl_interval(PG_FUNCTION_ARGS) if (tm2timestamp(tm, fsec, &tz, &tmp) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("datetimeoffset out of range"))); + errmsg("datetimeoffset out of range"))); } if (span->day != 0) { struct pg_tm tt, - *tm = &tt; + *tm = &tt; fsec_t fsec; int julian; if (timestamp2tm(tmp, &tz, tm, &fsec, NULL, NULL) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("datetimeoffset out of range"))); + errmsg("datetimeoffset out of range"))); /* Add days by converting to and from Julian */ julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + span->day; @@ -408,7 +413,7 @@ datetimeoffset_pl_interval(PG_FUNCTION_ARGS) if (tm2timestamp(tm, fsec, &tz, &tmp) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("datetimeoffset out of range"))); + errmsg("datetimeoffset out of range"))); } tmp += span->time; @@ -451,8 +456,8 @@ datetimeoffset_mi(PG_FUNCTION_ARGS) { tsql_datetimeoffset *df1 = PG_GETARG_DATETIMEOFFSET(0); tsql_datetimeoffset *df2 = PG_GETARG_DATETIMEOFFSET(1); - Timestamp t1; - Timestamp t2; + Timestamp t1; + Timestamp t2; Interval *result; datetimeoffset_timestamp_internal(df1, &t1); @@ -476,7 +481,8 @@ Datum datetimeoffset_hash(PG_FUNCTION_ARGS) { tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(0); - return hash_any((unsigned char *)df, DATETIMEOFFSET_LEN); + + return hash_any((unsigned char *) df, DATETIMEOFFSET_LEN); } /* smalldatetime_datetimeoffset() @@ -485,8 +491,8 @@ datetimeoffset_hash(PG_FUNCTION_ARGS) Datum smalldatetime_datetimeoffset(PG_FUNCTION_ARGS) { - Timestamp time = PG_GETARG_TIMESTAMP(0); - tsql_datetimeoffset* result; + Timestamp time = PG_GETARG_TIMESTAMP(0); + tsql_datetimeoffset *result; result = (tsql_datetimeoffset *) palloc(DATETIMEOFFSET_LEN); result->tsql_ts = time; @@ -503,7 +509,8 @@ Datum datetimeoffset_smalldatetime(PG_FUNCTION_ARGS) { tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(0); - Timestamp result; + Timestamp result; + datetimeoffset_timestamp_internal(df, &result); CheckSmalldatetimeRange(result); AdjustTimestampForSmallDatetime(&result); @@ -517,8 +524,8 @@ datetimeoffset_smalldatetime(PG_FUNCTION_ARGS) Datum datetime_datetimeoffset(PG_FUNCTION_ARGS) { - Timestamp time = PG_GETARG_TIMESTAMP(0); - tsql_datetimeoffset* result; + Timestamp time = PG_GETARG_TIMESTAMP(0); + tsql_datetimeoffset *result; result = (tsql_datetimeoffset *) palloc(DATETIMEOFFSET_LEN); result->tsql_ts = time; @@ -535,7 +542,8 @@ Datum datetimeoffset_datetime(PG_FUNCTION_ARGS) { tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(0); - Timestamp result; + Timestamp result; + datetimeoffset_timestamp_internal(df, &result); CheckDatetimeRange(result); @@ -548,8 +556,8 @@ datetimeoffset_datetime(PG_FUNCTION_ARGS) Datum datetime2_datetimeoffset(PG_FUNCTION_ARGS) { - Timestamp time = PG_GETARG_TIMESTAMP(0); - tsql_datetimeoffset* result; + Timestamp time = PG_GETARG_TIMESTAMP(0); + tsql_datetimeoffset *result; result = (tsql_datetimeoffset *) palloc(DATETIMEOFFSET_LEN); result->tsql_ts = time; @@ -566,7 +574,8 @@ Datum datetimeoffset_datetime2(PG_FUNCTION_ARGS) { tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(0); - Timestamp result; + Timestamp result; + datetimeoffset_timestamp_internal(df, &result); CheckDatetime2Range(result); @@ -579,8 +588,8 @@ datetimeoffset_datetime2(PG_FUNCTION_ARGS) Datum timestamp_datetimeoffset(PG_FUNCTION_ARGS) { - Timestamp time = PG_GETARG_TIMESTAMP(0); - tsql_datetimeoffset* result; + Timestamp time = PG_GETARG_TIMESTAMP(0); + tsql_datetimeoffset *result; result = (tsql_datetimeoffset *) palloc(DATETIMEOFFSET_LEN); result->tsql_ts = time; @@ -597,7 +606,8 @@ Datum datetimeoffset_timestamp(PG_FUNCTION_ARGS) { tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(0); - Timestamp result; + Timestamp result; + datetimeoffset_timestamp_internal(df, &result); PG_RETURN_TIMESTAMP(result); @@ -610,10 +620,10 @@ Datum date_datetimeoffset(PG_FUNCTION_ARGS) { DateADT dateVal = PG_GETARG_DATEADT(0); - tsql_datetimeoffset* result; + tsql_datetimeoffset *result; result = (tsql_datetimeoffset *) palloc(DATETIMEOFFSET_LEN); - result->tsql_ts = (int64)dateVal * USECS_PER_DAY; + result->tsql_ts = (int64) dateVal * USECS_PER_DAY; result->tsql_tz = 0; CheckDatetimeoffsetRange(result); @@ -627,9 +637,9 @@ Datum datetimeoffset_date(PG_FUNCTION_ARGS) { tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(0); - Timestamp time; - struct pg_tm tt, - *tm = &tt; + Timestamp time; + struct pg_tm tt, + *tm = &tt; fsec_t fsec; int tz; DateADT result; @@ -638,7 +648,7 @@ datetimeoffset_date(PG_FUNCTION_ARGS) if (timestamp2tm(time, &tz, tm, &fsec, NULL, NULL) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("datetimeoffset out of range"))); + errmsg("datetimeoffset out of range"))); result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE; @@ -652,7 +662,7 @@ Datum datetimeoffset_time(PG_FUNCTION_ARGS) { tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(0); - Timestamp time; + Timestamp time; TimeADT result; datetimeoffset_timestamp_internal(df, &time); @@ -703,6 +713,7 @@ Datum get_datetimeoffset_tzoffset_internal(PG_FUNCTION_ARGS) { tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(0); + PG_RETURN_INT16(-df->tsql_tz); } @@ -711,10 +722,14 @@ get_datetimeoffset_tzoffset_internal(PG_FUNCTION_ARGS) * for 0001-01-01 through 9999-12-31 */ static void -CheckDatetimeoffsetRange(const tsql_datetimeoffset* df) +CheckDatetimeoffsetRange(const tsql_datetimeoffset *df) { - Timestamp time; - /* the lower bound and uppbound stands for 0001-01-01 00:00:00 and 10000-01-01 00:00:00 */ + Timestamp time; + + /* + * the lower bound and uppbound stands for 0001-01-01 00:00:00 and + * 10000-01-01 00:00:00 + */ static const int64 lower_bound = -63082281600000000; static const int64 upper_bound = 252455616000000000; @@ -722,8 +737,8 @@ CheckDatetimeoffsetRange(const tsql_datetimeoffset* df) if (time < lower_bound || time >= upper_bound) { ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("data out of range for datetimeoffset"))); + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("data out of range for datetimeoffset"))); } } @@ -796,11 +811,11 @@ EncodeDatetimeoffsetTimezone(char *str, int tz, int style) { int hour, min; - char *tmp; + char *tmp; min = abs(tz); hour = min / MINS_PER_HOUR; - min = min % MINS_PER_HOUR; + min = min % MINS_PER_HOUR; /* point tmp to '\0' */ tmp = str + strlen(str); *tmp++ = ' '; diff --git a/contrib/babelfishpg_common/src/datetimeoffset.h b/contrib/babelfishpg_common/src/datetimeoffset.h index ae1c9d8e55..7b45a533af 100644 --- a/contrib/babelfishpg_common/src/datetimeoffset.h +++ b/contrib/babelfishpg_common/src/datetimeoffset.h @@ -25,8 +25,8 @@ extern void CheckDatetimeRange(const Timestamp time); extern void CheckDatetime2Range(const Timestamp time); typedef struct tsql_datetimeoffset { - int64 tsql_ts; - int16 tsql_tz; + int64 tsql_ts; + int16 tsql_tz; } tsql_datetimeoffset; /* fmgr interface macros */ diff --git a/contrib/babelfishpg_common/src/encoding/encoding.h b/contrib/babelfishpg_common/src/encoding/encoding.h index f00111e2e0..51fecf6404 100644 --- a/contrib/babelfishpg_common/src/encoding/encoding.h +++ b/contrib/babelfishpg_common/src/encoding/encoding.h @@ -5,29 +5,29 @@ extern char *encoding_conv_util(const char *s, int len, int src_encoding, int de /* Functions in src/encoding/mb/conv.c */ -extern int TsqlUtfToLocal(const unsigned char *utf, int len, - unsigned char *iso, - const pg_mb_radix_tree *map, - const pg_utf_to_local_combined *cmap, int cmapsize, - utf_local_conversion_func conv_func, - int encoding); +extern int TsqlUtfToLocal(const unsigned char *utf, int len, + unsigned char *iso, + const pg_mb_radix_tree *map, + const pg_utf_to_local_combined *cmap, int cmapsize, + utf_local_conversion_func conv_func, + int encoding); -extern int TsqlLocalToUtf(const unsigned char *iso, int len, - unsigned char *utf, - const pg_mb_radix_tree *map, - const pg_local_to_utf_combined *cmap, int cmapsize, - utf_local_conversion_func conv_func, - int encoding); +extern int TsqlLocalToUtf(const unsigned char *iso, int len, + unsigned char *utf, + const pg_mb_radix_tree *map, + const pg_local_to_utf_combined *cmap, int cmapsize, + utf_local_conversion_func conv_func, + int encoding); /* Functions in src/encoding/mb/conversion_procs */ -extern int utf8_to_win(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); -extern int utf8_to_big5(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); -extern int utf8_to_gbk(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); -extern int utf8_to_uhc(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); -extern int utf8_to_sjis(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); +extern int utf8_to_win(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); +extern int utf8_to_big5(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); +extern int utf8_to_gbk(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); +extern int utf8_to_uhc(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); +extern int utf8_to_sjis(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); -extern int win_to_utf8(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); -extern int big5_to_utf8(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *dest, int len); -extern int gbk_to_utf8(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); -extern int uhc_to_utf8(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); -extern int sjis_to_utf8(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); \ No newline at end of file +extern int win_to_utf8(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); +extern int big5_to_utf8(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *dest, int len); +extern int gbk_to_utf8(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); +extern int uhc_to_utf8(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); +extern int sjis_to_utf8(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); diff --git a/contrib/babelfishpg_common/src/encoding/encoding_utils.c b/contrib/babelfishpg_common/src/encoding/encoding_utils.c index 5372c88615..de87675c59 100644 --- a/contrib/babelfishpg_common/src/encoding/encoding_utils.c +++ b/contrib/babelfishpg_common/src/encoding/encoding_utils.c @@ -13,7 +13,7 @@ static unsigned char *do_encoding_conversion(unsigned char *src, int len, int sr /* * Convert server encoding to any encoding or vice-versa. - * + * * s: input string encoded in server's encoding * len: byte length of input string s * src_encoding: encoding from which input string should be encoded to dest_encoding @@ -29,12 +29,12 @@ encoding_conv_util(const char *s, int len, int src_encoding, int dest_encoding, *encodedByteLen = len; return (char *) s; /* empty string is always valid */ } - + return (char *) do_encoding_conversion((unsigned char *) s, - len, - src_encoding, - dest_encoding, - encodedByteLen); + len, + src_encoding, + dest_encoding, + encodedByteLen); } /* @@ -43,7 +43,7 @@ encoding_conv_util(const char *s, int len, int src_encoding, int dest_encoding, */ static unsigned char * do_encoding_conversion(unsigned char *src, int len, - int src_encoding, int dest_encoding, int *encodedByteLen) + int src_encoding, int dest_encoding, int *encodedByteLen) { unsigned char *result; @@ -75,6 +75,7 @@ do_encoding_conversion(unsigned char *src, int len, if (!IsTransactionState()) /* shouldn't happen */ elog(ERROR, "cannot perform encoding conversion outside a transaction"); + /* * Allocate space for conversion result, being wary of integer overflow. * @@ -99,19 +100,19 @@ do_encoding_conversion(unsigned char *src, int len, { switch (dest_encoding) { - case PG_BIG5: + case PG_BIG5: *encodedByteLen = utf8_to_big5(src_encoding, dest_encoding, src, result, len); break; - case PG_GBK: + case PG_GBK: *encodedByteLen = utf8_to_gbk(src_encoding, dest_encoding, src, result, len); break; - case PG_UHC: + case PG_UHC: *encodedByteLen = utf8_to_uhc(src_encoding, dest_encoding, src, result, len); break; - case PG_SJIS: + case PG_SJIS: *encodedByteLen = utf8_to_sjis(src_encoding, dest_encoding, src, result, len); break; - default: + default: *encodedByteLen = utf8_to_win(src_encoding, dest_encoding, src, result, len); break; } @@ -137,6 +138,7 @@ do_encoding_conversion(unsigned char *src, int len, break; } } + /* * If the result is large, it's worth repalloc'ing to release any extra * space we asked for. The cutoff here is somewhat arbitrary, but we @@ -157,4 +159,4 @@ do_encoding_conversion(unsigned char *src, int len, } return result; -} \ No newline at end of file +} diff --git a/contrib/babelfishpg_common/src/encoding/mb/conv.c b/contrib/babelfishpg_common/src/encoding/mb/conv.c index ddc8816d70..087a408b0f 100644 --- a/contrib/babelfishpg_common/src/encoding/mb/conv.c +++ b/contrib/babelfishpg_common/src/encoding/mb/conv.c @@ -196,23 +196,23 @@ pg_mb_radix_conv(const pg_mb_radix_tree *rt, * For each character, the cmap (if provided) is consulted first; if no match, * the map is consulted next; if still no match, the conv_func (if provided) * is applied. An error is raised if no match is found. - * + * * Returns byte length of result string encoded in desired encoding * * See pg_wchar.h for more details about the data structures used here. */ int TsqlUtfToLocal(const unsigned char *utf, int len, - unsigned char *iso, - const pg_mb_radix_tree *map, - const pg_utf_to_local_combined *cmap, int cmapsize, - utf_local_conversion_func conv_func, - int encoding) + unsigned char *iso, + const pg_mb_radix_tree *map, + const pg_utf_to_local_combined *cmap, int cmapsize, + utf_local_conversion_func conv_func, + int encoding) { - uint32 iutf; - int l; - const pg_utf_to_local_combined *cp; - int encodedByteLen = 0; + uint32 iutf; + int l; + const pg_utf_to_local_combined *cp; + int encodedByteLen = 0; if (!PG_VALID_ENCODING(encoding)) ereport(ERROR, @@ -362,8 +362,8 @@ TsqlUtfToLocal(const unsigned char *utf, int len, } /* - * TSQL puts question mark '?' - * if it can not recognize the UTF8 byte or byte sequence + * TSQL puts question mark '?' if it can not recognize the UTF8 byte + * or byte sequence */ iso = store_coded_char(iso, '?', &encodedByteLen); } @@ -378,16 +378,16 @@ TsqlUtfToLocal(const unsigned char *utf, int len, int TsqlLocalToUtf(const unsigned char *iso, int len, - unsigned char *utf, - const pg_mb_radix_tree *map, - const pg_local_to_utf_combined *cmap, int cmapsize, - utf_local_conversion_func conv_func, - int encoding) + unsigned char *utf, + const pg_mb_radix_tree *map, + const pg_local_to_utf_combined *cmap, int cmapsize, + utf_local_conversion_func conv_func, + int encoding) { uint32 iiso; int l; const pg_local_to_utf_combined *cp; - int encodedByteLen = 0; + int encodedByteLen = 0; if (!PG_VALID_ENCODING(encoding)) ereport(ERROR, @@ -483,8 +483,10 @@ TsqlLocalToUtf(const unsigned char *iso, int len, } } - /* If there doesnt exisiting any conversion scheme for any character in string - raise an error stating failed to translate this character */ + /* + * If there doesnt exisiting any conversion scheme for any character + * in string raise an error stating failed to translate this character + */ iso -= l; report_untranslatable_char(encoding, PG_UTF8, (const char *) iso, len); @@ -497,4 +499,4 @@ TsqlLocalToUtf(const unsigned char *iso, int len, *utf = '\0'; return encodedByteLen; -} \ No newline at end of file +} diff --git a/contrib/babelfishpg_common/src/encoding/mb/conversion_procs/utf8_and_big5/utf8_and_big5.c b/contrib/babelfishpg_common/src/encoding/mb/conversion_procs/utf8_and_big5/utf8_and_big5.c index c8ee770879..bc0f28deeb 100644 --- a/contrib/babelfishpg_common/src/encoding/mb/conversion_procs/utf8_and_big5/utf8_and_big5.c +++ b/contrib/babelfishpg_common/src/encoding/mb/conversion_procs/utf8_and_big5/utf8_and_big5.c @@ -7,7 +7,7 @@ #include "src/encoding/encoding.h" /* ---------- - * utf8_to_big5: + * utf8_to_big5: * src_encoding, -- source encoding id * dest_encoding, -- destination encoding id * src, -- source string (null terminated C string) @@ -20,18 +20,18 @@ int utf8_to_big5(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *dest, int len) { return TsqlUtfToLocal(src, len, dest, - &big5_from_unicode_tree, - NULL, 0, - NULL, - PG_BIG5); + &big5_from_unicode_tree, + NULL, 0, + NULL, + PG_BIG5); } int big5_to_utf8(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *dest, int len) { return TsqlLocalToUtf(src, len, dest, - &big5_to_unicode_tree, - NULL, 0, - NULL, - PG_BIG5); + &big5_to_unicode_tree, + NULL, 0, + NULL, + PG_BIG5); } diff --git a/contrib/babelfishpg_common/src/encoding/mb/conversion_procs/utf8_and_gbk/utf8_and_gbk.c b/contrib/babelfishpg_common/src/encoding/mb/conversion_procs/utf8_and_gbk/utf8_and_gbk.c index 45f024e243..6534e8681c 100644 --- a/contrib/babelfishpg_common/src/encoding/mb/conversion_procs/utf8_and_gbk/utf8_and_gbk.c +++ b/contrib/babelfishpg_common/src/encoding/mb/conversion_procs/utf8_and_gbk/utf8_and_gbk.c @@ -7,7 +7,7 @@ #include "src/encoding/encoding.h" /* ---------- - * utf8_to_gbk: + * utf8_to_gbk: * src_encoding, -- source encoding id * dest_encoding, -- destination encoding id * src, -- source string (null terminated C string) @@ -20,18 +20,18 @@ int utf8_to_gbk(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *dest, int len) { return TsqlUtfToLocal(src, len, dest, - &gbk_from_unicode_tree, - NULL, 0, - NULL, - PG_GBK); + &gbk_from_unicode_tree, + NULL, 0, + NULL, + PG_GBK); } int gbk_to_utf8(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *dest, int len) { return TsqlLocalToUtf(src, len, dest, - &gbk_to_unicode_tree, - NULL, 0, - NULL, - PG_GBK); -} \ No newline at end of file + &gbk_to_unicode_tree, + NULL, 0, + NULL, + PG_GBK); +} diff --git a/contrib/babelfishpg_common/src/encoding/mb/conversion_procs/utf8_and_sjis/utf8_and_sjis.c b/contrib/babelfishpg_common/src/encoding/mb/conversion_procs/utf8_and_sjis/utf8_and_sjis.c index fcd567d7e2..9949e6fa03 100644 --- a/contrib/babelfishpg_common/src/encoding/mb/conversion_procs/utf8_and_sjis/utf8_and_sjis.c +++ b/contrib/babelfishpg_common/src/encoding/mb/conversion_procs/utf8_and_sjis/utf8_and_sjis.c @@ -7,7 +7,7 @@ #include "src/encoding/encoding.h" /* ---------- - * utf8_to_sjis: + * utf8_to_sjis: * src_encoding, -- source encoding id * dest_encoding, -- destination encoding id * src, -- source string (null terminated C string) @@ -20,18 +20,18 @@ int utf8_to_sjis(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *dest, int len) { return TsqlUtfToLocal(src, len, dest, - &sjis_from_unicode_tree, - NULL, 0, - NULL, - PG_SJIS); + &sjis_from_unicode_tree, + NULL, 0, + NULL, + PG_SJIS); } int sjis_to_utf8(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *dest, int len) { return TsqlLocalToUtf(src, len, dest, - &sjis_to_unicode_tree, - NULL, 0, - NULL, - PG_SJIS); -} \ No newline at end of file + &sjis_to_unicode_tree, + NULL, 0, + NULL, + PG_SJIS); +} diff --git a/contrib/babelfishpg_common/src/encoding/mb/conversion_procs/utf8_and_uhc/utf8_and_uhc.c b/contrib/babelfishpg_common/src/encoding/mb/conversion_procs/utf8_and_uhc/utf8_and_uhc.c index 970cdab88d..e75ed173aa 100644 --- a/contrib/babelfishpg_common/src/encoding/mb/conversion_procs/utf8_and_uhc/utf8_and_uhc.c +++ b/contrib/babelfishpg_common/src/encoding/mb/conversion_procs/utf8_and_uhc/utf8_and_uhc.c @@ -7,7 +7,7 @@ #include "src/encoding/encoding.h" /* ---------- - * utf8_to_uhc: + * utf8_to_uhc: * src_encoding, -- source encoding id * dest_encoding, -- destination encoding id * src, -- source string (null terminated C string) @@ -20,18 +20,18 @@ int utf8_to_uhc(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *dest, int len) { return TsqlUtfToLocal(src, len, dest, - &uhc_from_unicode_tree, - NULL, 0, - NULL, - PG_UHC); + &uhc_from_unicode_tree, + NULL, 0, + NULL, + PG_UHC); } int uhc_to_utf8(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *dest, int len) { return TsqlLocalToUtf(src, len, dest, - &uhc_to_unicode_tree, - NULL, 0, - NULL, - PG_UHC); + &uhc_to_unicode_tree, + NULL, 0, + NULL, + PG_UHC); } diff --git a/contrib/babelfishpg_common/src/encoding/mb/conversion_procs/utf8_and_win/utf8_and_win.c b/contrib/babelfishpg_common/src/encoding/mb/conversion_procs/utf8_and_win/utf8_and_win.c index 37e481ddc6..ea508dec00 100644 --- a/contrib/babelfishpg_common/src/encoding/mb/conversion_procs/utf8_and_win/utf8_and_win.c +++ b/contrib/babelfishpg_common/src/encoding/mb/conversion_procs/utf8_and_win/utf8_and_win.c @@ -48,7 +48,7 @@ static const pg_conv_map maps[] = { }; /* ---------- - * utf8_to_win: + * utf8_to_win: * src_encoding, -- source encoding id * dest_encoding, -- destination encoding id * src, -- source string (null terminated C string) @@ -58,7 +58,7 @@ static const pg_conv_map maps[] = { * ---------- */ int -utf8_to_win(int src_encoding, int dest_encoding, const unsigned char *src,unsigned char *dest, int len) +utf8_to_win(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *dest, int len) { int i; @@ -67,10 +67,10 @@ utf8_to_win(int src_encoding, int dest_encoding, const unsigned char *src,unsign if (dest_encoding == maps[i].encoding) { return TsqlUtfToLocal(src, len, dest, - maps[i].map2, - NULL, 0, - NULL, - dest_encoding); + maps[i].map2, + NULL, 0, + NULL, + dest_encoding); } } @@ -83,7 +83,7 @@ utf8_to_win(int src_encoding, int dest_encoding, const unsigned char *src,unsign } int -win_to_utf8(int src_encoding, int dest_encoding, const unsigned char *src,unsigned char *dest, int len) +win_to_utf8(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *dest, int len) { int i; @@ -92,10 +92,10 @@ win_to_utf8(int src_encoding, int dest_encoding, const unsigned char *src,unsign if (src_encoding == maps[i].encoding) { return TsqlLocalToUtf(src, len, dest, - maps[i].map1, - NULL, 0, - NULL, - src_encoding); + maps[i].map1, + NULL, 0, + NULL, + src_encoding); } } diff --git a/contrib/babelfishpg_common/src/instr.c b/contrib/babelfishpg_common/src/instr.c index 37b3c60b44..95ce111651 100644 --- a/contrib/babelfishpg_common/src/instr.c +++ b/contrib/babelfishpg_common/src/instr.c @@ -11,8 +11,7 @@ init_instr(void) instr_plugin **rendezvous; rendezvous = (instr_plugin **) find_rendezvous_variable("PLtsql_instr_plugin"); - + if (rendezvous && *rendezvous) instr_plugin_ptr = *rendezvous; -} - +} diff --git a/contrib/babelfishpg_common/src/instr.h b/contrib/babelfishpg_common/src/instr.h index a859b4ae00..b8779827fe 100644 --- a/contrib/babelfishpg_common/src/instr.h +++ b/contrib/babelfishpg_common/src/instr.h @@ -6,8 +6,8 @@ typedef struct instr_plugin { /* Function pointers set up by the plugin */ - void (*instr_increment_metric) (int metric); - bool (*instr_increment_func_metric) (const char *funcName); + void (*instr_increment_metric) (int metric); + bool (*instr_increment_func_metric) (const char *funcName); } instr_plugin; extern instr_plugin *instr_plugin_ptr; @@ -23,7 +23,8 @@ extern void init_instr(void); }) /* copy from pltsql_instr.h */ -typedef enum PgTsqlInstrMetricType { +typedef enum PgTsqlInstrMetricType +{ INSTR_START = -1, INSTR_TSQL_ALTER_COLUMN, @@ -328,7 +329,7 @@ typedef enum PgTsqlInstrMetricType { INSTR_TSQL_BINARYFLOAT4, INSTR_TSQL_BINARYFLOAT8, INSTR_TSQL_VARBINARY_COMPARE, - + INSTR_TSQL_SMALLDATETIMEIN, INSTR_TSQL_TIME2SMALLDATETIME, INSTR_TSQL_DATE2SMALLDATETIME, @@ -437,7 +438,7 @@ typedef enum PgTsqlInstrMetricType { INSTR_UNSUPPORTED_TSQL_PROCID, INSTR_TSQL_VERSION, INSTR_TSQL_SERVERNAME, - + INSTR_UNSUPPORTED_TSQL_OPTION_ROWCOUNT, INSTR_TSQL_FETCH_STATUS, @@ -469,6 +470,6 @@ typedef enum PgTsqlInstrMetricType { INSTR_UNSUPPORTED_TSQL_ISOLATION_LEVEL_SERIALIZABLE, INSTR_TSQL_COUNT -} PgTsqlInstrMetricType; +} PgTsqlInstrMetricType; #endif diff --git a/contrib/babelfishpg_common/src/numeric.c b/contrib/babelfishpg_common/src/numeric.c index 448fd8f2d1..f7cda093a0 100644 --- a/contrib/babelfishpg_common/src/numeric.c +++ b/contrib/babelfishpg_common/src/numeric.c @@ -289,7 +289,7 @@ typedef struct NumericVar current; NumericVar stop; NumericVar step; -} generate_series_numeric_fctx; +} generate_series_numeric_fctx; /* ---------- @@ -303,7 +303,7 @@ typedef struct bool estimating; /* true if estimating cardinality */ hyperLogLogState abbr_card; /* cardinality estimator */ -} NumericSortSupport; +} NumericSortSupport; /* ---------- @@ -345,7 +345,7 @@ typedef struct NumericSumAccum bool have_carry_space; int32 *pos_digits; int32 *neg_digits; -} NumericSumAccum; +} NumericSumAccum; /* @@ -413,7 +413,7 @@ PG_FUNCTION_INFO_V1(int4int2_avg); static void alloc_var(NumericVar *var, int ndigits); static void free_var(NumericVar *var); static const char *set_var_from_str(const char *str, const char *cp, - NumericVar *dest); + NumericVar *dest); static Numeric make_result(const NumericVar *var); static void strip_var(NumericVar *var); @@ -752,8 +752,9 @@ strip_var(NumericVar *var) Numeric tsql_set_var_from_str_wrapper(const char *str) { - NumericVar value; - Numeric res; + NumericVar value; + Numeric res; + init_var(&value); set_var_from_str(str, str, &value); res = make_result(&value); @@ -786,7 +787,7 @@ set_var_from_num(Numeric num, NumericVar *dest) * tsql_round_var * * This function is similar to round_var, - * but we check if rounding up will cause an overflow + * but we check if rounding up will cause an overflow */ static void tsql_round_var(NumericVar *var, int rscale) @@ -804,8 +805,8 @@ tsql_round_var(NumericVar *var, int rscale) /* checking numeric overflow for TSQL */ if (rscale < 0) { - int integral_digits = di - DEC_DIGITS; - int leading_digits = digits[0]; + int integral_digits = di - DEC_DIGITS; + int leading_digits = digits[0]; static const int32 timescales[DEC_DIGITS] = { 1000, 100, @@ -813,19 +814,19 @@ tsql_round_var(NumericVar *var, int rscale) 1, }; - for(int i = 0; i < DEC_DIGITS; i++) + for (int i = 0; i < DEC_DIGITS; i++) { - if(leading_digits >= timescales[i]) + if (leading_digits >= timescales[i]) { - integral_digits += (4-i); + integral_digits += (4 - i); break; } } - /* Overflow when rounding up*/ + /* Overflow when rounding up */ if (integral_digits == 0) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("value overflows for numeric format"))); + errmsg("value overflows for numeric format"))); /* should lose all digits */ else if (integral_digits < 0) di = -1; @@ -929,8 +930,9 @@ tsql_numeric_round(PG_FUNCTION_ARGS) int32 scale; Numeric res; NumericVar arg; + /* when num or scale is NULL, return NULL */ - if(PG_ARGISNULL(0) || PG_ARGISNULL(1)) + if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) PG_RETURN_NULL(); num = PG_GETARG_NUMERIC(0); @@ -971,7 +973,7 @@ tsql_numeric_round(PG_FUNCTION_ARGS) /* * tsql_numeric_round() - - * + * * Directly call numeric_trunc() or * call tsql_numeric_round() when 'function' is 0 or null */ @@ -979,32 +981,33 @@ Datum tsql_numeric_trunc(PG_FUNCTION_ARGS) { Numeric num; - int32 scale ; + int32 scale; + /* when num or scale is NULL, return NULL */ - if(PG_ARGISNULL(0) || PG_ARGISNULL(1)) + if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) PG_RETURN_NULL(); num = PG_GETARG_NUMERIC(0); scale = PG_GETARG_INT32(1); - if(PG_ARGISNULL(2) || PG_GETARG_INT32(2) == 0) + if (PG_ARGISNULL(2) || PG_GETARG_INT32(2) == 0) return DirectFunctionCall2(tsql_numeric_round, - NumericGetDatum(num), - Int32GetDatum(scale)); - + NumericGetDatum(num), + Int32GetDatum(scale)); + return DirectFunctionCall2(numeric_trunc, - NumericGetDatum(num), - Int32GetDatum(scale)); + NumericGetDatum(num), + Int32GetDatum(scale)); } -/* +/* * Get Precision & Scale from Numeric Value */ int32_t tsql_numeric_get_typmod(Numeric num) { - int32_t scale = NUMERIC_DSCALE(num); - int32_t weight = NUMERIC_WEIGHT(num); - int32_t precision; + int32_t scale = NUMERIC_DSCALE(num); + int32_t weight = NUMERIC_WEIGHT(num); + int32_t precision; if (weight >= 0) { @@ -1014,14 +1017,15 @@ tsql_numeric_get_typmod(Numeric num) 10, 1, }; - int leading_digits = NUMERIC_DIGITS(num)[0]; + int leading_digits = NUMERIC_DIGITS(num)[0]; + precision = weight * DEC_DIGITS + scale; - for(int i = 0; i < DEC_DIGITS; i++) + for (int i = 0; i < DEC_DIGITS; i++) { - if(leading_digits >= timescales[i]) + if (leading_digits >= timescales[i]) { - precision += (4-i); + precision += (4 - i); break; } } @@ -1030,10 +1034,10 @@ tsql_numeric_get_typmod(Numeric num) /* weight < 0 means the integral part of the number is 0 */ precision = 1 + scale; - return (((precision & 0xFFFF) << 16 ) | (scale & 0xFFFF)) + VARHDRSZ; + return (((precision & 0xFFFF) << 16) | (scale & 0xFFFF)) + VARHDRSZ; } -/* +/* * Final function to be used by SUM(BIGINT) aggregate */ Datum @@ -1042,26 +1046,27 @@ bigint_sum(PG_FUNCTION_ARGS) return bigint_poly_aggr_final(fcinfo, TSQL_SUM); } -/* +/* * Final function to be used by SUM(INT),SUM(SMALLINT),SUM(TINYINT) aggregates */ Datum int4int2_sum(PG_FUNCTION_ARGS) { - int64 result; - if (PG_ARGISNULL(0)) + int64 result; + + if (PG_ARGISNULL(0)) { PG_RETURN_NULL(); } else { - result = PG_GETARG_INT64(0); + result = PG_GETARG_INT64(0); if (unlikely(result < PG_INT32_MIN || result > PG_INT32_MAX)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("Arithmetic overflow error converting expression to data type int."))); + errmsg("Arithmetic overflow error converting expression to data type int."))); PG_RETURN_INT32((int32) result); } @@ -1073,36 +1078,36 @@ typedef struct Int8TransTypeData int64 sum; } Int8TransTypeData; -/* +/* * Final function to be used by AVGINT),AVG(SMALLINT),AVG(TINYINT) aggregates */ Datum int4int2_avg(PG_FUNCTION_ARGS) { - ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); + ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0); Int8TransTypeData *transdata; if (ARR_HASNULL(transarray) || - ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData)) - ereport(ERROR, - (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), - errmsg("expected 2-element int8 array"))); + ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData)) + ereport(ERROR, + (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), + errmsg("expected 2-element int8 array"))); transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray); - + /* SQL defines AVG of no values to be NULL */ if (transdata->count == 0) PG_RETURN_NULL(); - + if (unlikely(transdata->sum < PG_INT32_MIN || transdata->sum > PG_INT32_MAX)) { - ereport(ERROR,(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("Arithmetic overflow error converting expression to data type int."))); + ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("Arithmetic overflow error converting expression to data type int."))); } PG_RETURN_INT32((int32) transdata->sum / transdata->count); } -/* +/* * Final function to be used by AVG(BIGINT) aggregate */ Datum diff --git a/contrib/babelfishpg_common/src/smalldatetime.c b/contrib/babelfishpg_common/src/smalldatetime.c index 7515b3a67d..d9f1e16a14 100644 --- a/contrib/babelfishpg_common/src/smalldatetime.c +++ b/contrib/babelfishpg_common/src/smalldatetime.c @@ -41,8 +41,8 @@ PG_FUNCTION_INFO_V1(float8_mi_smalldatetime); PG_FUNCTION_INFO_V1(smalldatetime_pl_smalldatetime); PG_FUNCTION_INFO_V1(smalldatetime_mi_smalldatetime); -void AdjustTimestampForSmallDatetime(Timestamp *time); -void CheckSmalldatetimeRange(const Timestamp time); +void AdjustTimestampForSmallDatetime(Timestamp *time); +void CheckSmalldatetimeRange(const Timestamp time); static Datum smalldatetime_in_str(char *str); /* smalldatetime_in_str() @@ -79,11 +79,11 @@ smalldatetime_in_str(char *str) dterr = ParseDateTime(str, workbuf, sizeof(workbuf), field, ftype, MAXDATEFIELDS, &nf); - + if (dterr == 0) dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz); - // dterr == 1 means that input is TIME format(e.g 12:34:59.123) - // initialize other necessary date parts and accept input format + /* dterr == 1 means that input is TIME format(e.g 12:34:59.123) */ + /* initialize other necessary date parts and accept input format */ if (dterr == 1) { tm->tm_year = 1900; @@ -134,7 +134,7 @@ smalldatetime_in_str(char *str) Datum smalldatetime_in(PG_FUNCTION_ARGS) { - char *str = PG_GETARG_CSTRING(0); + char *str = PG_GETARG_CSTRING(0); return smalldatetime_in_str(str); } @@ -145,14 +145,18 @@ smalldatetime_in(PG_FUNCTION_ARGS) void CheckSmalldatetimeRange(const Timestamp time) { - /* the lower bound and uppbound stands for 1899-12-31 23:59:29.999 and 2079-06-06 23:59:29.999 */ + /* + * the lower bound and uppbound stands for 1899-12-31 23:59:29.999 and + * 2079-06-06 23:59:29.999 + */ static const int64 lower_bound = -3155673630001000; static const int64 upper_bound = 2506636769999000; + if (time < lower_bound || time >= upper_bound) { ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("data out of range for smalldatetime"))); + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("data out of range for smalldatetime"))); } } @@ -164,32 +168,32 @@ void AdjustTimestampForSmallDatetime(Timestamp *time) { static const int64 SmallDatetimeRoundsThresould[2] = { - 29999000, - 30001000 - }; - - if (*time >= INT64CONST(0)) - { - if( *time % USECS_PER_MINUTE >= SmallDatetimeRoundsThresould[0]) - { - *time = *time / USECS_PER_MINUTE * USECS_PER_MINUTE + USECS_PER_MINUTE; - } - else - { - *time = *time / USECS_PER_MINUTE * USECS_PER_MINUTE; - } - } - else - { - if( (-(*time)) % USECS_PER_MINUTE <= SmallDatetimeRoundsThresould[1]) - { - *time = *time / USECS_PER_MINUTE * USECS_PER_MINUTE; - } - else - { - *time = *time / USECS_PER_MINUTE * USECS_PER_MINUTE - USECS_PER_MINUTE; - } - } + 29999000, + 30001000 + }; + + if (*time >= INT64CONST(0)) + { + if (*time % USECS_PER_MINUTE >= SmallDatetimeRoundsThresould[0]) + { + *time = *time / USECS_PER_MINUTE * USECS_PER_MINUTE + USECS_PER_MINUTE; + } + else + { + *time = *time / USECS_PER_MINUTE * USECS_PER_MINUTE; + } + } + else + { + if ((-(*time)) % USECS_PER_MINUTE <= SmallDatetimeRoundsThresould[1]) + { + *time = *time / USECS_PER_MINUTE * USECS_PER_MINUTE; + } + else + { + *time = *time / USECS_PER_MINUTE * USECS_PER_MINUTE - USECS_PER_MINUTE; + } + } } /* time_smalldatetime() @@ -201,23 +205,23 @@ time_smalldatetime(PG_FUNCTION_ARGS) TimeADT timeVal = PG_GETARG_TIMEADT(0); Timestamp result; - struct pg_tm tt, - *tm = &tt; + struct pg_tm tt, + *tm = &tt; fsec_t fsec; - // Initialize default year, month, day to 1900-01-01 + /* Initialize default year, month, day to 1900-01-01 */ tm->tm_year = 1900; tm->tm_mon = 1; tm->tm_mday = 1; - // Convert TimeADT type to tm + /* Convert TimeADT type to tm */ time2tm(timeVal, tm, &fsec); if (tm2timestamp(tm, fsec, NULL, &result) != 0) - ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("data out of range for smalldatetime"))); - + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("data out of range for smalldatetime"))); + AdjustTimestampForSmallDatetime(&result); PG_RETURN_TIMESTAMP(result); @@ -249,7 +253,7 @@ date_smalldatetime(PG_FUNCTION_ARGS) Datum timestamp_smalldatetime(PG_FUNCTION_ARGS) { - Timestamp result = PG_GETARG_TIMESTAMP(0); + Timestamp result = PG_GETARG_TIMESTAMP(0); CheckSmalldatetimeRange(result); AdjustTimestampForSmallDatetime(&result); @@ -266,7 +270,7 @@ timestamptz_smalldatetime(PG_FUNCTION_ARGS) Timestamp result; struct pg_tm tt, - *tm = &tt; + *tm = &tt; fsec_t fsec; int tz; @@ -323,8 +327,8 @@ smalldatetime_varchar(PG_FUNCTION_ARGS) Datum varchar_smalldatetime(PG_FUNCTION_ARGS) { - Datum txt = PG_GETARG_DATUM(0); - char *str = TextDatumGetCString(txt); + Datum txt = PG_GETARG_DATUM(0); + char *str = TextDatumGetCString(txt); return smalldatetime_in_str(str); } @@ -364,8 +368,8 @@ smalldatetime_char(PG_FUNCTION_ARGS) Datum char_smalldatetime(PG_FUNCTION_ARGS) { - Datum txt = PG_GETARG_DATUM(0); - char *str = TextDatumGetCString(txt); + Datum txt = PG_GETARG_DATUM(0); + char *str = TextDatumGetCString(txt); return smalldatetime_in_str(str); } @@ -373,17 +377,17 @@ char_smalldatetime(PG_FUNCTION_ARGS) /* * smalldatetime_pl_int4() * operator function for adding smalldatetime plus int - * + * * simply add number of days to date value, while preserving the time * component */ Datum smalldatetime_pl_int4(PG_FUNCTION_ARGS) -{ +{ Timestamp timestamp = PG_GETARG_TIMESTAMP(0); int32 days = PG_GETARG_INT32(1); Timestamp result; - Interval *input_interval; + Interval *input_interval; if (TIMESTAMP_NOT_FINITE(timestamp)) PG_RETURN_TIMESTAMP(timestamp); @@ -401,12 +405,12 @@ smalldatetime_pl_int4(PG_FUNCTION_ARGS) /* * int4_mi_smalldatetime() * Operator function for subtracting int minus smalldatetime - * + * * Convert the input int32 value d to smalldatetime(1/1/1900) + d days. - * Then add the difference between the input smalldatetime value and the one + * Then add the difference between the input smalldatetime value and the one * above to the default smalldatetime value (1/1/1900). - * - * ex: + * + * ex: * d = 9, dt = '1/11/1900' * dt_left = smalldatetime(1/1/1900) + 9 days = smalldatetime(1/10/1900) * diff = dt_left - dt = -1 day @@ -414,27 +418,30 @@ smalldatetime_pl_int4(PG_FUNCTION_ARGS) */ Datum int4_mi_smalldatetime(PG_FUNCTION_ARGS) -{ +{ int32 days = PG_GETARG_INT32(0); Timestamp timestamp_right = PG_GETARG_TIMESTAMP(1); Timestamp result; Timestamp default_timestamp; Timestamp timestamp_left; - Interval *input_interval; - Interval *result_interval; + Interval *input_interval; + Interval *result_interval; if (TIMESTAMP_NOT_FINITE(timestamp_right)) PG_RETURN_TIMESTAMP(timestamp_right); /* inialize input int(days) as timestamp */ - default_timestamp = DirectFunctionCall6(make_timestamp, 1900, 1, 1, 0, 0,0); + default_timestamp = DirectFunctionCall6(make_timestamp, 1900, 1, 1, 0, 0, 0); input_interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, days, 0, 0, 0); timestamp_left = DirectFunctionCall2(timestamp_pl_interval, default_timestamp, PointerGetDatum(input_interval)); /* calculate timestamp diff */ result_interval = (Interval *) DirectFunctionCall2(timestamp_mi, timestamp_left, timestamp_right); - /* if the diff between left and right timestamps is positive, then we add the interval. else, subtract */ + /* + * if the diff between left and right timestamps is positive, then we add + * the interval. else, subtract + */ result = DirectFunctionCall2(timestamp_pl_interval, default_timestamp, PointerGetDatum(result_interval)); CheckSmalldatetimeRange(result); @@ -447,9 +454,10 @@ int4_mi_smalldatetime(PG_FUNCTION_ARGS) */ Datum int4_pl_smalldatetime(PG_FUNCTION_ARGS) -{ +{ int32 days = PG_GETARG_INT32(0); Timestamp timestamp = PG_GETARG_TIMESTAMP(1); + PG_RETURN_TIMESTAMP(DirectFunctionCall2(smalldatetime_pl_int4, timestamp, days)); } @@ -459,9 +467,10 @@ int4_pl_smalldatetime(PG_FUNCTION_ARGS) */ Datum smalldatetime_mi_int4(PG_FUNCTION_ARGS) -{ +{ Timestamp timestamp = PG_GETARG_TIMESTAMP(0); int32 days = PG_GETARG_INT32(1); + PG_RETURN_TIMESTAMP(DirectFunctionCall2(smalldatetime_pl_int4, timestamp, -days)); } @@ -469,26 +478,28 @@ smalldatetime_mi_int4(PG_FUNCTION_ARGS) /* * smalldatetime_pl_float8() * operator function for adding smalldatetime plus float - * + * * simply add number of days/secs to date value, while preserving the time * component */ Datum smalldatetime_pl_float8(PG_FUNCTION_ARGS) -{ +{ Timestamp timestamp = PG_GETARG_TIMESTAMP(0); double days = PG_GETARG_FLOAT8(1); - double day_whole, day_fract, sec_whole; - Interval *input_interval; + double day_whole, + day_fract, + sec_whole; + Interval *input_interval; Timestamp result; - + if (TIMESTAMP_NOT_FINITE(timestamp)) PG_RETURN_TIMESTAMP(timestamp); /* split day into whole and fractional parts */ day_fract = modf(days, &day_whole); - day_fract = modf(SECS_PER_DAY*day_fract, &sec_whole); - // fsec_whole = TSROUND(TS_PREC_INV*sec_fract); + day_fract = modf(SECS_PER_DAY * day_fract, &sec_whole); + /* fsec_whole = TSROUND(TS_PREC_INV*sec_fract); */ /* make interval */ input_interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, (int32) day_whole, 0, 0, Float8GetDatum(sec_whole)); @@ -504,40 +515,45 @@ smalldatetime_pl_float8(PG_FUNCTION_ARGS) /* * float8_mi_smalldatetime() * Operator function for subtracting float8 minus smalldatetime - * + * * Convert the input float8 value d to smalldatetime(1/1/1900) + d days. - * Then add the difference between the input smalldatetime value and the one + * Then add the difference between the input smalldatetime value and the one * above to the default smalldatetime value (1/1/1900). */ Datum float8_mi_smalldatetime(PG_FUNCTION_ARGS) -{ +{ double days = PG_GETARG_FLOAT8(0); Timestamp timestamp_right = PG_GETARG_TIMESTAMP(1); - double day_whole, day_fract, sec_whole; + double day_whole, + day_fract, + sec_whole; Timestamp result; Timestamp default_timestamp; Timestamp timestamp_left; - Interval *input_interval; - Interval *result_interval; + Interval *input_interval; + Interval *result_interval; if (TIMESTAMP_NOT_FINITE(timestamp_right)) PG_RETURN_TIMESTAMP(timestamp_right); /* split day into whole and fractional parts */ day_fract = modf(days, &day_whole); - day_fract = modf(SECS_PER_DAY*day_fract, &sec_whole); + day_fract = modf(SECS_PER_DAY * day_fract, &sec_whole); /* inialize input int(days) as timestamp */ - default_timestamp = DirectFunctionCall6(make_timestamp, 1900, 1, 1, 0, 0,0); + default_timestamp = DirectFunctionCall6(make_timestamp, 1900, 1, 1, 0, 0, 0); input_interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, (int32) day_whole, 0, 0, Float8GetDatum(sec_whole)); timestamp_left = DirectFunctionCall2(timestamp_pl_interval, default_timestamp, PointerGetDatum(input_interval)); /* calculate timestamp diff */ result_interval = (Interval *) DirectFunctionCall2(timestamp_mi, timestamp_left, timestamp_right); - /* if the diff between left and right timestamps is positive, then we add the interval. else, subtract */ + /* + * if the diff between left and right timestamps is positive, then we add + * the interval. else, subtract + */ result = DirectFunctionCall2(timestamp_pl_interval, default_timestamp, PointerGetDatum(result_interval)); @@ -551,19 +567,21 @@ float8_mi_smalldatetime(PG_FUNCTION_ARGS) */ Datum float8_pl_smalldatetime(PG_FUNCTION_ARGS) -{ +{ double days = PG_GETARG_FLOAT8(0); Timestamp timestamp = PG_GETARG_TIMESTAMP(1); - double day_whole, day_fract, sec_whole; - Interval *input_interval; + double day_whole, + day_fract, + sec_whole; + Interval *input_interval; Timestamp result; - + if (TIMESTAMP_NOT_FINITE(timestamp)) PG_RETURN_TIMESTAMP(timestamp); /* split day into whole and fractional parts */ day_fract = modf(days, &day_whole); - day_fract = modf(SECS_PER_DAY*day_fract, &sec_whole); + day_fract = modf(SECS_PER_DAY * day_fract, &sec_whole); /* make interval */ input_interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, (int32) day_whole, 0, 0, Float8GetDatum(sec_whole)); @@ -581,19 +599,21 @@ float8_pl_smalldatetime(PG_FUNCTION_ARGS) */ Datum smalldatetime_mi_float8(PG_FUNCTION_ARGS) -{ +{ Timestamp timestamp = PG_GETARG_TIMESTAMP(0); double days = PG_GETARG_FLOAT8(1); - double day_whole, day_fract, sec_whole; - Interval *input_interval; + double day_whole, + day_fract, + sec_whole; + Interval *input_interval; Timestamp result; - + if (TIMESTAMP_NOT_FINITE(timestamp)) PG_RETURN_TIMESTAMP(timestamp); /* split day into whole and fractional parts */ day_fract = modf(days, &day_whole); - day_fract = modf(SECS_PER_DAY*day_fract, &sec_whole); + day_fract = modf(SECS_PER_DAY * day_fract, &sec_whole); /* make interval */ input_interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, (int32) day_whole, 0, 0, Float8GetDatum(sec_whole)); @@ -609,14 +629,17 @@ smalldatetime_mi_float8(PG_FUNCTION_ARGS) Datum smalldatetime_pl_smalldatetime(PG_FUNCTION_ARGS) { - Timestamp timestamp1 = PG_GETARG_TIMESTAMP(0); - Timestamp timestamp2 = PG_GETARG_TIMESTAMP(1); - Timestamp diff; - Timestamp result; + Timestamp timestamp1 = PG_GETARG_TIMESTAMP(0); + Timestamp timestamp2 = PG_GETARG_TIMESTAMP(1); + Timestamp diff; + Timestamp result; - /* calculate interval from timestamp2. It should be calculated as the difference from 1900-01-01 00:00:00 (default datetime) */ + /* + * calculate interval from timestamp2. It should be calculated as the + * difference from 1900-01-01 00:00:00 (default datetime) + */ diff = timestamp2 - initializeToDefaultDatetime(); - + /* add interval */ result = timestamp1 + diff; @@ -627,14 +650,17 @@ smalldatetime_pl_smalldatetime(PG_FUNCTION_ARGS) Datum smalldatetime_mi_smalldatetime(PG_FUNCTION_ARGS) { - Timestamp timestamp1 = PG_GETARG_TIMESTAMP(0); - Timestamp timestamp2 = PG_GETARG_TIMESTAMP(1); - Timestamp diff; - Timestamp result; + Timestamp timestamp1 = PG_GETARG_TIMESTAMP(0); + Timestamp timestamp2 = PG_GETARG_TIMESTAMP(1); + Timestamp diff; + Timestamp result; - /* calculate interval from timestamp2. It should be calculated as the difference from 1900-01-01 00:00:00 (default datetime) */ + /* + * calculate interval from timestamp2. It should be calculated as the + * difference from 1900-01-01 00:00:00 (default datetime) + */ diff = timestamp2 - initializeToDefaultDatetime(); - + /* subtract interval */ result = timestamp1 - diff; diff --git a/contrib/babelfishpg_common/src/sqlvariant.c b/contrib/babelfishpg_common/src/sqlvariant.c index 19f0ba4548..fc7f376d24 100644 --- a/contrib/babelfishpg_common/src/sqlvariant.c +++ b/contrib/babelfishpg_common/src/sqlvariant.c @@ -64,50 +64,50 @@ extern HTAB *ht_oid2collid; Datum sqlvariantin(PG_FUNCTION_ARGS) { - char *str = PG_GETARG_CSTRING(0); - Oid typelem = PG_GETARG_OID(1); - int32 atttypmod = PG_GETARG_INT32(2); - bytea *result; - text *data_val; - size_t data_size; - size_t total_size; - type_info_t type_info = get_tsql_type_info(VARCHAR_T); - Oid type = type_info.oid; /* hardcoded varchar */ - uint8_t svhdr_size = type_info.svhdr_size; - Oid input_func; - Oid typIOParam; - svhdr_5B_t *svhdr; - - getTypeInputInfo(type, &input_func, &typIOParam); - /* evalute input fuction */ - data_val = (text*) OidInputFunctionCall(input_func, str, typelem, atttypmod); - - /* Copy Data */ - data_size = VARSIZE_ANY(data_val); - if (SV_CAN_USE_SHORT_VALENA(data_size, svhdr_size)) - { - total_size = VARHDRSZ_SHORT + svhdr_size + data_size; - result = (bytea *) palloc(total_size); - SET_VARSIZE_SHORT(result, total_size); - } - else - { - total_size = VARHDRSZ + svhdr_size + data_size; - result = (bytea *) palloc(total_size); - SET_VARSIZE(result, total_size); - } - memcpy(SV_DATA(result, svhdr_size), data_val, data_size); - - /* Set Metadata */ - svhdr = SV_HDR_5B(result); - SV_SET_METADATA(svhdr, VARCHAR_T, HDR_VER); /* hardcode as VARCHAR */ - svhdr->typmod = VARSIZE_ANY_EXHDR(data_val); - svhdr->collid = get_server_collation_collidx(); - - // Cleanup - pfree(data_val); - - PG_RETURN_BYTEA_P(result); + char *str = PG_GETARG_CSTRING(0); + Oid typelem = PG_GETARG_OID(1); + int32 atttypmod = PG_GETARG_INT32(2); + bytea *result; + text *data_val; + size_t data_size; + size_t total_size; + type_info_t type_info = get_tsql_type_info(VARCHAR_T); + Oid type = type_info.oid; /* hardcoded varchar */ + uint8_t svhdr_size = type_info.svhdr_size; + Oid input_func; + Oid typIOParam; + svhdr_5B_t *svhdr; + + getTypeInputInfo(type, &input_func, &typIOParam); + /* evalute input fuction */ + data_val = (text *) OidInputFunctionCall(input_func, str, typelem, atttypmod); + + /* Copy Data */ + data_size = VARSIZE_ANY(data_val); + if (SV_CAN_USE_SHORT_VALENA(data_size, svhdr_size)) + { + total_size = VARHDRSZ_SHORT + svhdr_size + data_size; + result = (bytea *) palloc(total_size); + SET_VARSIZE_SHORT(result, total_size); + } + else + { + total_size = VARHDRSZ + svhdr_size + data_size; + result = (bytea *) palloc(total_size); + SET_VARSIZE(result, total_size); + } + memcpy(SV_DATA(result, svhdr_size), data_val, data_size); + + /* Set Metadata */ + svhdr = SV_HDR_5B(result); + SV_SET_METADATA(svhdr, VARCHAR_T, HDR_VER); /* hardcode as VARCHAR */ + svhdr->typmod = VARSIZE_ANY_EXHDR(data_val); + svhdr->collid = get_server_collation_collidx(); + + /* Cleanup */ + pfree(data_val); + + PG_RETURN_BYTEA_P(result); } /* @@ -118,29 +118,29 @@ sqlvariantin(PG_FUNCTION_ARGS) Datum sqlvariantout(PG_FUNCTION_ARGS) { - char *result = NULL; - bytea *vlena = PG_GETARG_BYTEA_PP(0); - uint8_t type_code = SV_GET_TYPCODE_PTR(vlena); - type_info_t type_info = get_tsql_type_info(type_code); - Oid type = (Oid) type_info.oid; - uint8_t svhdr_size = type_info.svhdr_size; - Oid output_func; - bool typIsVarlena; - size_t data_len = VARSIZE_ANY_EXHDR(vlena) - svhdr_size; - Datum *output_datum = palloc0(SIZEOF_DATUM); - - if (!get_typbyval(type)) /* pass by reference */ - *output_datum = SV_DATUM(vlena, svhdr_size); - else /* pass by value */ - { - memcpy(output_datum, SV_DATUM_PTR(vlena, svhdr_size), data_len); - } + char *result = NULL; + bytea *vlena = PG_GETARG_BYTEA_PP(0); + uint8_t type_code = SV_GET_TYPCODE_PTR(vlena); + type_info_t type_info = get_tsql_type_info(type_code); + Oid type = (Oid) type_info.oid; + uint8_t svhdr_size = type_info.svhdr_size; + Oid output_func; + bool typIsVarlena; + size_t data_len = VARSIZE_ANY_EXHDR(vlena) - svhdr_size; + Datum *output_datum = palloc0(SIZEOF_DATUM); + + if (!get_typbyval(type)) /* pass by reference */ + *output_datum = SV_DATUM(vlena, svhdr_size); + else /* pass by value */ + { + memcpy(output_datum, SV_DATUM_PTR(vlena, svhdr_size), data_len); + } - getTypeOutputInfo(type, &output_func, &typIsVarlena); - result = OidOutputFunctionCall(output_func, *output_datum); + getTypeOutputInfo(type, &output_func, &typIsVarlena); + result = OidOutputFunctionCall(output_func, *output_datum); - PG_FREE_IF_COPY(vlena, 0); - PG_RETURN_CSTRING(result); + PG_FREE_IF_COPY(vlena, 0); + PG_RETURN_CSTRING(result); } /* @@ -150,37 +150,37 @@ sqlvariantout(PG_FUNCTION_ARGS) Datum sqlvariantrecv(PG_FUNCTION_ARGS) { - StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); - bytea *result; - int nbytes; + StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); + bytea *result; + int nbytes; INSTR_METRIC_INC(INSTR_TSQL_SQLVARIANT_RECV); - nbytes = buf->len - buf->cursor; + nbytes = buf->len - buf->cursor; - if (SV_CAN_USE_SHORT_VALENA(nbytes, 0)) - { - result = (bytea *) palloc(nbytes + VARHDRSZ_SHORT); - SET_VARSIZE_SHORT(result, nbytes + VARHDRSZ_SHORT); - } - else - { - result = (bytea *) palloc(nbytes + VARHDRSZ); - SET_VARSIZE(result, nbytes + VARHDRSZ); - } + if (SV_CAN_USE_SHORT_VALENA(nbytes, 0)) + { + result = (bytea *) palloc(nbytes + VARHDRSZ_SHORT); + SET_VARSIZE_SHORT(result, nbytes + VARHDRSZ_SHORT); + } + else + { + result = (bytea *) palloc(nbytes + VARHDRSZ); + SET_VARSIZE(result, nbytes + VARHDRSZ); + } - pq_copymsgbytes(buf, VARDATA_ANY(result), nbytes); - PG_RETURN_BYTEA_P(result); + pq_copymsgbytes(buf, VARDATA_ANY(result), nbytes); + PG_RETURN_BYTEA_P(result); } Datum sqlvariantsend(PG_FUNCTION_ARGS) { - bytea *vlena = PG_GETARG_BYTEA_P_COPY(0); + bytea *vlena = PG_GETARG_BYTEA_P_COPY(0); INSTR_METRIC_INC(INSTR_TSQL_SQLVARIANT_SEND); - PG_RETURN_BYTEA_P(vlena); + PG_RETURN_BYTEA_P(vlena); } /* Helper functions */ @@ -190,186 +190,188 @@ static Datum get_int_sv_datum(int32_t value); Datum get_varchar128_sv_datum(const char *value) { - size_t len = strlen(value); - bytea *result; - svhdr_5B_t *svhdr; - size_t sv_size; - uint8_t svhdr_size = get_tsql_type_info(VARCHAR_T).svhdr_size; + size_t len = strlen(value); + bytea *result; + svhdr_5B_t *svhdr; + size_t sv_size; + uint8_t svhdr_size = get_tsql_type_info(VARCHAR_T).svhdr_size; - /* return varchar(128) */ - sv_size = VARHDRSZ + svhdr_size + VARHDRSZ + len; - result = palloc(sv_size); - SET_VARSIZE(result, sv_size); - SET_VARSIZE(SV_DATA(result, svhdr_size), VARHDRSZ + len); - memcpy(VARDATA(SV_DATA(result, svhdr_size)), value, len); + /* return varchar(128) */ + sv_size = VARHDRSZ + svhdr_size + VARHDRSZ + len; + result = palloc(sv_size); + SET_VARSIZE(result, sv_size); + SET_VARSIZE(SV_DATA(result, svhdr_size), VARHDRSZ + len); + memcpy(VARDATA(SV_DATA(result, svhdr_size)), value, len); - /* Header */ - svhdr = SV_HDR_5B(result); - SV_SET_METADATA(svhdr, VARCHAR_T, HDR_VER); - svhdr->typmod = len; /* Actual Data Length */ - svhdr->collid = get_server_collation_collidx(); + /* Header */ + svhdr = SV_HDR_5B(result); + SV_SET_METADATA(svhdr, VARCHAR_T, HDR_VER); + svhdr->typmod = len; /* Actual Data Length */ + svhdr->collid = get_server_collation_collidx(); - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } Datum get_int_sv_datum(int32_t value) { - bytea *result; - svhdr_1B_t *svhdr; - uint8_t svhdr_size = get_tsql_type_info(INT_T).svhdr_size; + bytea *result; + svhdr_1B_t *svhdr; + uint8_t svhdr_size = get_tsql_type_info(INT_T).svhdr_size; - result = palloc(VARHDRSZ_SHORT + svhdr_size + sizeof(int32_t)); - SET_VARSIZE_SHORT(result, VARHDRSZ_SHORT + svhdr_size + sizeof(int32_t)); - *(int32_t *)(SV_DATA(result, svhdr_size)) = value; + result = palloc(VARHDRSZ_SHORT + svhdr_size + sizeof(int32_t)); + SET_VARSIZE_SHORT(result, VARHDRSZ_SHORT + svhdr_size + sizeof(int32_t)); + *(int32_t *) (SV_DATA(result, svhdr_size)) = value; - svhdr = SV_HDR_1B(result); - SV_SET_METADATA(svhdr, INT_T, HDR_VER); + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, INT_T, HDR_VER); - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } /* Helper functions for CAST and COMPARE */ -static Datum do_cast(Oid source_type, Oid target_type, Datum value, int32_t typmod, Oid coll, - CoercionContext cc, bool *cast_by_relabel); +static Datum do_cast(Oid source_type, Oid target_type, Datum value, int32_t typmod, Oid coll, + CoercionContext cc, bool *cast_by_relabel); static Datum compare_value(char *oprname, Oid type, Datum d1, Datum d2, Oid coll); -static Datum gen_type_datum_from_sqlvariant_bytea(bytea *sv, uint8_t target_typcode, int32_t typmod, Oid coll); +static Datum gen_type_datum_from_sqlvariant_bytea(bytea *sv, uint8_t target_typcode, int32_t typmod, Oid coll); /* only called from the same type family */ -Datum do_compare(char *oprname, bytea *arg1, bytea *arg2, Oid fncollation); +Datum do_compare(char *oprname, bytea *arg1, bytea *arg2, Oid fncollation); -Datum comp_time(char * oprname, uint16_t t1, uint16_t t2); +Datum comp_time(char *oprname, uint16_t t1, uint16_t t2); Datum compare_value(char *oprname, Oid type, Datum d1, Datum d2, Oid coll) { - Operator operator; - Oid oprcode; + Operator operator; + Oid oprcode; - operator = compatible_oper(NULL, list_make1(makeString(oprname)), type, type, false, -1); - oprcode = oprfuncid(operator); - ReleaseSysCache(operator); + operator = compatible_oper(NULL, list_make1(makeString(oprname)), type, type, false, -1); + oprcode = oprfuncid(operator); + ReleaseSysCache(operator); - return OidFunctionCall2Coll(oprcode, coll, d1, d2); + return OidFunctionCall2Coll(oprcode, coll, d1, d2); } Datum do_cast(Oid source_type, Oid target_type, Datum value, int32_t typmod, Oid coll, - CoercionContext ccontext, bool *cast_by_relabel) -{ - Oid funcid; - CoercionPathType path; - Oid typioparam; - bool isVarlena; - path = find_coercion_pathway(target_type, source_type, ccontext, &funcid); - - - switch (path){ - case COERCION_PATH_FUNC: - *cast_by_relabel = false; - return OidFunctionCall3Coll(funcid, coll, value, (Datum) typmod, (Datum) ccontext == COERCION_EXPLICIT); - break; - case COERCION_PATH_COERCEVIAIO: - *cast_by_relabel = false; - if (TypeCategory(source_type) == TYPCATEGORY_STRING) - { - getTypeInputInfo(target_type, &funcid, &typioparam); - return OidInputFunctionCall(funcid, TextDatumGetCString(value), typioparam, typmod); - } - else - { - getTypeOutputInfo(source_type, &funcid, &isVarlena); - return CStringGetTextDatum(OidOutputFunctionCall(funcid, value)); - } - break; - case COERCION_PATH_RELABELTYPE: - *cast_by_relabel = true; - return value; - break; - default: - *cast_by_relabel = false; - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("unable to cast from internal type %s to %s", - format_type_be(source_type), format_type_be(target_type)))); - } - return value; + CoercionContext ccontext, bool *cast_by_relabel) +{ + Oid funcid; + CoercionPathType path; + Oid typioparam; + bool isVarlena; + + path = find_coercion_pathway(target_type, source_type, ccontext, &funcid); + + + switch (path) + { + case COERCION_PATH_FUNC: + *cast_by_relabel = false; + return OidFunctionCall3Coll(funcid, coll, value, (Datum) typmod, (Datum) ccontext == COERCION_EXPLICIT); + break; + case COERCION_PATH_COERCEVIAIO: + *cast_by_relabel = false; + if (TypeCategory(source_type) == TYPCATEGORY_STRING) + { + getTypeInputInfo(target_type, &funcid, &typioparam); + return OidInputFunctionCall(funcid, TextDatumGetCString(value), typioparam, typmod); + } + else + { + getTypeOutputInfo(source_type, &funcid, &isVarlena); + return CStringGetTextDatum(OidOutputFunctionCall(funcid, value)); + } + break; + case COERCION_PATH_RELABELTYPE: + *cast_by_relabel = true; + return value; + break; + default: + *cast_by_relabel = false; + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("unable to cast from internal type %s to %s", + format_type_be(source_type), format_type_be(target_type)))); + } + return value; } bytea * gen_sqlvariant_bytea_from_type_datum(size_t typcode, Datum data) { - type_info_t type_info = get_tsql_type_info(typcode); - Oid typoid = type_info.oid; - int8_t svhdr_size = type_info.svhdr_size; - int16_t typlen = get_typlen(typoid); - size_t data_len; - - bytea *result; - size_t result_len; - - if (IS_STRING_TYPE(typcode) || IS_BINARY_TYPE(typcode) || typcode == NUMERIC_T) /* varlena datatype */ - { - data_len = VARSIZE_ANY(data); - if (SV_CAN_USE_SHORT_VALENA(data_len, svhdr_size)) - { - result_len = VARHDRSZ_SHORT + svhdr_size + data_len; - result = palloc(result_len); - SET_VARSIZE_SHORT(result, result_len); - } - else - { - result_len = VARHDRSZ + svhdr_size + data_len; - result = palloc(result_len); - SET_VARSIZE(result, result_len); - } - /* Copy Data */ - memcpy(SV_DATA(result, svhdr_size), (bytea *) DatumGetPointer(data), data_len); - } - else /* fixed length datatype */ - { - result_len = VARHDRSZ_SHORT + svhdr_size + typlen; - result = palloc(result_len); - SET_VARSIZE_SHORT(result, result_len); - - if (typlen <= SIZEOF_DATUM) /* pass by value */ - memcpy(SV_DATA(result, svhdr_size), &data, typlen); - else - memcpy(SV_DATA(result, svhdr_size), (bytea *) DatumGetPointer(data), typlen); - } - - return result; + type_info_t type_info = get_tsql_type_info(typcode); + Oid typoid = type_info.oid; + int8_t svhdr_size = type_info.svhdr_size; + int16_t typlen = get_typlen(typoid); + size_t data_len; + + bytea *result; + size_t result_len; + + if (IS_STRING_TYPE(typcode) || IS_BINARY_TYPE(typcode) || typcode == NUMERIC_T) /* varlena datatype */ + { + data_len = VARSIZE_ANY(data); + if (SV_CAN_USE_SHORT_VALENA(data_len, svhdr_size)) + { + result_len = VARHDRSZ_SHORT + svhdr_size + data_len; + result = palloc(result_len); + SET_VARSIZE_SHORT(result, result_len); + } + else + { + result_len = VARHDRSZ + svhdr_size + data_len; + result = palloc(result_len); + SET_VARSIZE(result, result_len); + } + /* Copy Data */ + memcpy(SV_DATA(result, svhdr_size), (bytea *) DatumGetPointer(data), data_len); + } + else /* fixed length datatype */ + { + result_len = VARHDRSZ_SHORT + svhdr_size + typlen; + result = palloc(result_len); + SET_VARSIZE_SHORT(result, result_len); + + if (typlen <= SIZEOF_DATUM) /* pass by value */ + memcpy(SV_DATA(result, svhdr_size), &data, typlen); + else + memcpy(SV_DATA(result, svhdr_size), (bytea *) DatumGetPointer(data), typlen); + } + + return result; } Datum gen_type_datum_from_sqlvariant_bytea(bytea *sv, uint8_t target_typcode, int32_t typmod, Oid coll) { - uint8_t typcode = SV_GET_TYPCODE_PTR(sv); - type_info_t type_info = get_tsql_type_info(typcode); - Oid type_oid = (Oid) type_info.oid; - uint8_t svhdr_size = type_info.svhdr_size; - Oid target_oid = (Oid) get_tsql_type_info(target_typcode).oid; - Datum *target_datum = palloc0(SIZEOF_DATUM); - size_t data_len = VARSIZE_ANY_EXHDR(sv) - svhdr_size; - bool cast_by_relabel; - - if (!get_typbyval(type_oid)) /* Pass by reference */ - *target_datum = SV_DATUM(sv, svhdr_size); - else /* Pass by value */ - { - memcpy(target_datum, SV_DATUM_PTR(sv, svhdr_size), data_len); - } + uint8_t typcode = SV_GET_TYPCODE_PTR(sv); + type_info_t type_info = get_tsql_type_info(typcode); + Oid type_oid = (Oid) type_info.oid; + uint8_t svhdr_size = type_info.svhdr_size; + Oid target_oid = (Oid) get_tsql_type_info(target_typcode).oid; + Datum *target_datum = palloc0(SIZEOF_DATUM); + size_t data_len = VARSIZE_ANY_EXHDR(sv) - svhdr_size; + bool cast_by_relabel; + + if (!get_typbyval(type_oid)) /* Pass by reference */ + *target_datum = SV_DATUM(sv, svhdr_size); + else /* Pass by value */ + { + memcpy(target_datum, SV_DATUM_PTR(sv, svhdr_size), data_len); + } - set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + set_config_option("babelfishpg_tsql.sql_dialect", "tsql", + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); - if (typcode == target_typcode) - return *target_datum; - else - return do_cast(type_oid, target_oid, *target_datum, typmod, coll, COERCION_EXPLICIT, &cast_by_relabel); + if (typcode == target_typcode) + return *target_datum; + else + return do_cast(type_oid, target_oid, *target_datum, typmod, coll, COERCION_EXPLICIT, &cast_by_relabel); } /* @@ -378,117 +380,124 @@ gen_type_datum_from_sqlvariant_bytea(bytea *sv, uint8_t target_typcode, int32_t * other date & time types */ Datum -comp_time(char * oprname, uint16_t t1, uint16_t t2) +comp_time(char *oprname, uint16_t t1, uint16_t t2) { - /* - * Notice: THIS IS NOT A GENERATL COMPARISON FUNCTION - * Assumption : 1 and ONLY 1 of t1,t2 is of TIME_T - */ - if (pg_strncasecmp(oprname, "<>", 2) == 0) - PG_RETURN_BOOL(true); - else if (pg_strncasecmp(oprname, ">", 1) == 0) /* including >= */ - PG_RETURN_BOOL(t1 != TIME_T && t2 == TIME_T); - else if (pg_strncasecmp(oprname, "<", 1) == 0) /* including <= */ - PG_RETURN_BOOL(t1 == TIME_T && t2 != TIME_T); - else /* (pg_strncasecmp(oprname, "=", 2) == 0) */ - PG_RETURN_BOOL(false); + /* + * Notice: THIS IS NOT A GENERATL COMPARISON FUNCTION Assumption : 1 and + * ONLY 1 of t1,t2 is of TIME_T + */ + if (pg_strncasecmp(oprname, "<>", 2) == 0) + PG_RETURN_BOOL(true); + else if (pg_strncasecmp(oprname, ">", 1) == 0) /* including >= */ + PG_RETURN_BOOL(t1 != TIME_T && t2 == TIME_T); + else if (pg_strncasecmp(oprname, "<", 1) == 0) /* including <= */ + PG_RETURN_BOOL(t1 == TIME_T && t2 != TIME_T); + else /* (pg_strncasecmp(oprname, "=", 2) == 0) */ + PG_RETURN_BOOL(false); } Datum do_compare(char *oprname, bytea *arg1, bytea *arg2, Oid fncollation) { - uint8_t type_code1 = SV_GET_TYPCODE_PTR(arg1); - uint8_t type_code2 = SV_GET_TYPCODE_PTR(arg2); - type_info_t type_info1 = get_tsql_type_info(type_code1); - type_info_t type_info2 = get_tsql_type_info(type_code2); - Oid type_oid1 = (Oid) type_info1.oid; - Oid type_oid2 = (Oid) type_info2.oid; - uint8_t svhdr_size1 = type_info1.svhdr_size; - uint8_t svhdr_size2 = type_info2.svhdr_size; - bool d1_pass_by_ref = get_typbyval(type_oid1) == false; - bool d2_pass_by_ref = get_typbyval(type_oid2) == false; - size_t data_len1 = VARSIZE_ANY_EXHDR(arg1) - svhdr_size1; - size_t data_len2 = VARSIZE_ANY_EXHDR(arg2) - svhdr_size2; - Datum d1 = 0; - Datum d2 = 0; - if (d1_pass_by_ref) - d1 = SV_DATUM(arg1, svhdr_size1); - else - memcpy(&d1, SV_DATUM_PTR(arg1, svhdr_size1), data_len1); - if (d2_pass_by_ref) - d2 = SV_DATUM(arg2, svhdr_size2); - else - memcpy(&d2, SV_DATUM_PTR(arg2, svhdr_size2), data_len2); - - set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); - - /* Check Type Code */ - if (type_code1 == type_code2) /* same type */ - { - if (IS_STRING_TYPE(type_code1)) /* handle string with different collation */ - { - svhdr_5B_t *str_header1 = SV_HDR_5B(arg1); - svhdr_5B_t *str_header2 = SV_HDR_5B(arg2); - if (str_header1->collid != str_header2->collid) { - int8_t coll_cmp_result = cmp_collation(str_header1->collid, str_header2->collid); - if (pg_strncasecmp(oprname, "<>", 2) == 0) - PG_RETURN_BOOL(true); - else if (pg_strncasecmp(oprname, ">", 1) == 0) /* including >= */ - PG_RETURN_BOOL(coll_cmp_result > 0); - else if (pg_strncasecmp(oprname, "<", 1) == 0) /* including <= */ - PG_RETURN_BOOL(coll_cmp_result < 0); - else /* (pg_strncasecmp(oprname, "=", 1) == 0) */ - PG_RETURN_BOOL(false); - } - } - return compare_value(oprname, type_oid1, d1, d2, fncollation); - } - else /* implicit cast within type family */ - { - Datum temp_datum; - Datum result; - Operator direct_cmp; - Oid oprcode; - bool cast_by_relabel; - - // handle sql_variant specific cases - if (type_code1 == TIME_T || type_code2 == TIME_T) - return comp_time(oprname, type_code1, type_code2); - - // find direct comparisions without casting - direct_cmp = compatible_oper(NULL, list_make1(makeString(oprname)), - type_oid1, type_oid2, true, -1); - if (direct_cmp) - { - oprcode = oprfuncid(direct_cmp); - ReleaseSysCache(direct_cmp); - return OidFunctionCall2Coll(oprcode, fncollation, d1, d2); - } - - // do implicit cast - // typmod is not considered during a implicit cast comparison - if (type_code1 < type_code2) /* CAST arg2 to arg1 */ - { - temp_datum = do_cast(type_oid2, type_oid1, d2, -1, fncollation, COERCION_IMPLICIT, &cast_by_relabel); - result = compare_value(oprname, type_oid1, d1, temp_datum, fncollation); - if (d1_pass_by_ref && !cast_by_relabel) /* delete temporary variable */ - pfree((char *) temp_datum); - - return result; - } - else /* CAST arg1 to arg2 */ - { - temp_datum = do_cast(type_oid1, type_oid2, d1, -1, fncollation, COERCION_IMPLICIT, &cast_by_relabel); - result = compare_value(oprname, type_oid2, temp_datum, d2, fncollation); - if (d2_pass_by_ref && !cast_by_relabel) /* delete temporary variable */ - pfree((char *) temp_datum); - - return result; - } - } + uint8_t type_code1 = SV_GET_TYPCODE_PTR(arg1); + uint8_t type_code2 = SV_GET_TYPCODE_PTR(arg2); + type_info_t type_info1 = get_tsql_type_info(type_code1); + type_info_t type_info2 = get_tsql_type_info(type_code2); + Oid type_oid1 = (Oid) type_info1.oid; + Oid type_oid2 = (Oid) type_info2.oid; + uint8_t svhdr_size1 = type_info1.svhdr_size; + uint8_t svhdr_size2 = type_info2.svhdr_size; + bool d1_pass_by_ref = get_typbyval(type_oid1) == false; + bool d2_pass_by_ref = get_typbyval(type_oid2) == false; + size_t data_len1 = VARSIZE_ANY_EXHDR(arg1) - svhdr_size1; + size_t data_len2 = VARSIZE_ANY_EXHDR(arg2) - svhdr_size2; + Datum d1 = 0; + Datum d2 = 0; + + if (d1_pass_by_ref) + d1 = SV_DATUM(arg1, svhdr_size1); + else + memcpy(&d1, SV_DATUM_PTR(arg1, svhdr_size1), data_len1); + if (d2_pass_by_ref) + d2 = SV_DATUM(arg2, svhdr_size2); + else + memcpy(&d2, SV_DATUM_PTR(arg2, svhdr_size2), data_len2); + + set_config_option("babelfishpg_tsql.sql_dialect", "tsql", + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + + /* Check Type Code */ + if (type_code1 == type_code2) /* same type */ + { + if (IS_STRING_TYPE(type_code1)) /* handle string with different + * collation */ + { + svhdr_5B_t *str_header1 = SV_HDR_5B(arg1); + svhdr_5B_t *str_header2 = SV_HDR_5B(arg2); + + if (str_header1->collid != str_header2->collid) + { + int8_t coll_cmp_result = cmp_collation(str_header1->collid, str_header2->collid); + + if (pg_strncasecmp(oprname, "<>", 2) == 0) + PG_RETURN_BOOL(true); + else if (pg_strncasecmp(oprname, ">", 1) == 0) /* including >= */ + PG_RETURN_BOOL(coll_cmp_result > 0); + else if (pg_strncasecmp(oprname, "<", 1) == 0) /* including <= */ + PG_RETURN_BOOL(coll_cmp_result < 0); + else /* (pg_strncasecmp(oprname, "=", 1) == 0) */ + PG_RETURN_BOOL(false); + } + } + return compare_value(oprname, type_oid1, d1, d2, fncollation); + } + else /* implicit cast within type family */ + { + Datum temp_datum; + Datum result; + Operator direct_cmp; + Oid oprcode; + bool cast_by_relabel; + + /* handle sql_variant specific cases */ + if (type_code1 == TIME_T || type_code2 == TIME_T) + return comp_time(oprname, type_code1, type_code2); + + /* find direct comparisions without casting */ + direct_cmp = compatible_oper(NULL, list_make1(makeString(oprname)), + type_oid1, type_oid2, true, -1); + if (direct_cmp) + { + oprcode = oprfuncid(direct_cmp); + ReleaseSysCache(direct_cmp); + return OidFunctionCall2Coll(oprcode, fncollation, d1, d2); + } + + /* do implicit cast */ + /* typmod is not considered during a implicit cast comparison */ + if (type_code1 < type_code2) /* CAST arg2 to arg1 */ + { + temp_datum = do_cast(type_oid2, type_oid1, d2, -1, fncollation, COERCION_IMPLICIT, &cast_by_relabel); + result = compare_value(oprname, type_oid1, d1, temp_datum, fncollation); + if (d1_pass_by_ref && !cast_by_relabel) /* delete temporary + * variable */ + pfree((char *) temp_datum); + + return result; + } + else /* CAST arg1 to arg2 */ + { + temp_datum = do_cast(type_oid1, type_oid2, d1, -1, fncollation, COERCION_IMPLICIT, &cast_by_relabel); + result = compare_value(oprname, type_oid2, temp_datum, d2, fncollation); + if (d2_pass_by_ref && !cast_by_relabel) /* delete temporary + * variable */ + pfree((char *) temp_datum); + + return result; + } + } } @@ -524,361 +533,364 @@ PG_FUNCTION_INFO_V1(uniqueidentifier2sqlvariant); Datum datetime2sqlvariant(PG_FUNCTION_ARGS) { - Datum data = PG_GETARG_DATUM(0); - bytea *result = gen_sqlvariant_bytea_from_type_datum(DATETIME_T, data); - svhdr_1B_t *svhdr; + Datum data = PG_GETARG_DATUM(0); + bytea *result = gen_sqlvariant_bytea_from_type_datum(DATETIME_T, data); + svhdr_1B_t *svhdr; - /* Type Specific Header */ - svhdr = SV_HDR_1B(result); - SV_SET_METADATA(svhdr, DATETIME_T, HDR_VER); + /* Type Specific Header */ + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, DATETIME_T, HDR_VER); - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } Datum datetime22sqlvariant(PG_FUNCTION_ARGS) { - Datum data = PG_GETARG_DATUM(0); - bytea *result = gen_sqlvariant_bytea_from_type_datum(DATETIME2_T, data); - svhdr_2B_t *svhdr; + Datum data = PG_GETARG_DATUM(0); + bytea *result = gen_sqlvariant_bytea_from_type_datum(DATETIME2_T, data); + svhdr_2B_t *svhdr; - /* Type Specific Header */ - svhdr = SV_HDR_2B(result); - SV_SET_METADATA(svhdr, DATETIME2_T, HDR_VER); - svhdr->typmod = -1; + /* Type Specific Header */ + svhdr = SV_HDR_2B(result); + SV_SET_METADATA(svhdr, DATETIME2_T, HDR_VER); + svhdr->typmod = -1; - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } Datum smalldatetime2sqlvariant(PG_FUNCTION_ARGS) { - Datum data = PG_GETARG_DATUM(0); - bytea *result = gen_sqlvariant_bytea_from_type_datum(SMALLDATETIME_T, data); - svhdr_1B_t *svhdr; + Datum data = PG_GETARG_DATUM(0); + bytea *result = gen_sqlvariant_bytea_from_type_datum(SMALLDATETIME_T, data); + svhdr_1B_t *svhdr; - /* Type Specific Header */ - svhdr = SV_HDR_1B(result); - SV_SET_METADATA(svhdr, SMALLDATETIME_T, HDR_VER); + /* Type Specific Header */ + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, SMALLDATETIME_T, HDR_VER); - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } Datum datetimeoffset2sqlvariant(PG_FUNCTION_ARGS) { - Datum data = PG_GETARG_DATUM(0); - bytea *result = gen_sqlvariant_bytea_from_type_datum(DATETIMEOFFSET_T, data); - svhdr_2B_t *svhdr; + Datum data = PG_GETARG_DATUM(0); + bytea *result = gen_sqlvariant_bytea_from_type_datum(DATETIMEOFFSET_T, data); + svhdr_2B_t *svhdr; - /* Type Specific Header */ - svhdr = SV_HDR_2B(result); - SV_SET_METADATA(svhdr, DATETIMEOFFSET_T, HDR_VER); - svhdr->typmod = -1; + /* Type Specific Header */ + svhdr = SV_HDR_2B(result); + SV_SET_METADATA(svhdr, DATETIMEOFFSET_T, HDR_VER); + svhdr->typmod = -1; - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } Datum date2sqlvariant(PG_FUNCTION_ARGS) { - Datum data = PG_GETARG_DATUM(0); - bytea *result = gen_sqlvariant_bytea_from_type_datum(DATE_T, data); - svhdr_1B_t *svhdr; + Datum data = PG_GETARG_DATUM(0); + bytea *result = gen_sqlvariant_bytea_from_type_datum(DATE_T, data); + svhdr_1B_t *svhdr; - /* Type Specific Header */ - svhdr = SV_HDR_1B(result); - SV_SET_METADATA(svhdr, DATE_T, HDR_VER); + /* Type Specific Header */ + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, DATE_T, HDR_VER); - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } Datum time2sqlvariant(PG_FUNCTION_ARGS) { - Datum data = PG_GETARG_DATUM(0); - bytea *result = gen_sqlvariant_bytea_from_type_datum(TIME_T, data); - svhdr_2B_t *svhdr; + Datum data = PG_GETARG_DATUM(0); + bytea *result = gen_sqlvariant_bytea_from_type_datum(TIME_T, data); + svhdr_2B_t *svhdr; - /* Type Specific Header */ - svhdr = SV_HDR_2B(result); - SV_SET_METADATA(svhdr, TIME_T, HDR_VER); - svhdr->typmod = -1; + /* Type Specific Header */ + svhdr = SV_HDR_2B(result); + SV_SET_METADATA(svhdr, TIME_T, HDR_VER); + svhdr->typmod = -1; - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } /* Approximate numerics */ Datum float2sqlvariant(PG_FUNCTION_ARGS) { - Datum data = PG_GETARG_DATUM(0); - bytea *result = gen_sqlvariant_bytea_from_type_datum(FLOAT_T, data); - svhdr_1B_t *svhdr; + Datum data = PG_GETARG_DATUM(0); + bytea *result = gen_sqlvariant_bytea_from_type_datum(FLOAT_T, data); + svhdr_1B_t *svhdr; - /* Type Specific Header */ - svhdr = SV_HDR_1B(result); - SV_SET_METADATA(svhdr, FLOAT_T, HDR_VER); + /* Type Specific Header */ + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, FLOAT_T, HDR_VER); - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } Datum real2sqlvariant(PG_FUNCTION_ARGS) { - Datum data = PG_GETARG_DATUM(0); - bytea *result = gen_sqlvariant_bytea_from_type_datum(REAL_T, data); - svhdr_1B_t *svhdr; + Datum data = PG_GETARG_DATUM(0); + bytea *result = gen_sqlvariant_bytea_from_type_datum(REAL_T, data); + svhdr_1B_t *svhdr; - /* Type Specific Header */ - svhdr = SV_HDR_1B(result); - SV_SET_METADATA(svhdr, REAL_T, HDR_VER); + /* Type Specific Header */ + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, REAL_T, HDR_VER); - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } /* Exact numerics */ Datum numeric2sqlvariant(PG_FUNCTION_ARGS) { - Numeric num = PG_GETARG_NUMERIC(0); - bytea *result = gen_sqlvariant_bytea_from_type_datum(NUMERIC_T, NumericGetDatum(num)); - svhdr_3B_t *svhdr; - int16_t precision; - int16_t scale; - int32_t typmod_container; + Numeric num = PG_GETARG_NUMERIC(0); + bytea *result = gen_sqlvariant_bytea_from_type_datum(NUMERIC_T, NumericGetDatum(num)); + svhdr_3B_t *svhdr; + int16_t precision; + int16_t scale; + int32_t typmod_container; - /* Type Specific Header */ - svhdr = SV_HDR_3B(result); - SV_SET_METADATA(svhdr, NUMERIC_T, HDR_VER); - - /* tsql_numeric_get_typmod() returns 32bit int. need to convert it to 16bit*/ - typmod_container = tsql_numeric_get_typmod(num); - if (typmod_container != -1) - { - precision = ((typmod_container - VARHDRSZ) >> 16) & 0xFF; - scale = (typmod_container - VARHDRSZ) & 0xFF; - svhdr->typmod = (precision << 8) | scale; - } - else - { - svhdr->typmod = -1; - } + /* Type Specific Header */ + svhdr = SV_HDR_3B(result); + SV_SET_METADATA(svhdr, NUMERIC_T, HDR_VER); + + /* + * tsql_numeric_get_typmod() returns 32bit int. need to convert it to + * 16bit + */ + typmod_container = tsql_numeric_get_typmod(num); + if (typmod_container != -1) + { + precision = ((typmod_container - VARHDRSZ) >> 16) & 0xFF; + scale = (typmod_container - VARHDRSZ) & 0xFF; + svhdr->typmod = (precision << 8) | scale; + } + else + { + svhdr->typmod = -1; + } - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } Datum money2sqlvariant(PG_FUNCTION_ARGS) { - Datum data = PG_GETARG_DATUM(0); - bytea *result = gen_sqlvariant_bytea_from_type_datum(MONEY_T, data); - svhdr_1B_t *svhdr; + Datum data = PG_GETARG_DATUM(0); + bytea *result = gen_sqlvariant_bytea_from_type_datum(MONEY_T, data); + svhdr_1B_t *svhdr; - /* Type Specific Header */ - svhdr = SV_HDR_1B(result); - SV_SET_METADATA(svhdr, MONEY_T, HDR_VER); + /* Type Specific Header */ + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, MONEY_T, HDR_VER); - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } Datum smallmoney2sqlvariant(PG_FUNCTION_ARGS) { - Datum data = PG_GETARG_DATUM(0); - bytea *result = gen_sqlvariant_bytea_from_type_datum(SMALLMONEY_T, data); - svhdr_1B_t *svhdr; + Datum data = PG_GETARG_DATUM(0); + bytea *result = gen_sqlvariant_bytea_from_type_datum(SMALLMONEY_T, data); + svhdr_1B_t *svhdr; - /* Type Specific Header */ - svhdr = SV_HDR_1B(result); - SV_SET_METADATA(svhdr, SMALLMONEY_T, HDR_VER); + /* Type Specific Header */ + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, SMALLMONEY_T, HDR_VER); - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } Datum bigint2sqlvariant(PG_FUNCTION_ARGS) { - Datum data = PG_GETARG_DATUM(0); - bytea *result = gen_sqlvariant_bytea_from_type_datum(BIGINT_T, data); - svhdr_1B_t *svhdr; + Datum data = PG_GETARG_DATUM(0); + bytea *result = gen_sqlvariant_bytea_from_type_datum(BIGINT_T, data); + svhdr_1B_t *svhdr; - /* Type Specific Header */ - svhdr = SV_HDR_1B(result); - SV_SET_METADATA(svhdr, BIGINT_T, HDR_VER); + /* Type Specific Header */ + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, BIGINT_T, HDR_VER); - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } Datum int2sqlvariant(PG_FUNCTION_ARGS) { - Datum data = PG_GETARG_DATUM(0); - bytea *result = gen_sqlvariant_bytea_from_type_datum(INT_T, data); - svhdr_1B_t *svhdr; + Datum data = PG_GETARG_DATUM(0); + bytea *result = gen_sqlvariant_bytea_from_type_datum(INT_T, data); + svhdr_1B_t *svhdr; - /* Type Specific Header */ - svhdr = SV_HDR_1B(result); - SV_SET_METADATA(svhdr, INT_T, HDR_VER); + /* Type Specific Header */ + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, INT_T, HDR_VER); - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } Datum smallint2sqlvariant(PG_FUNCTION_ARGS) { - Datum data = PG_GETARG_DATUM(0); - bytea *result = gen_sqlvariant_bytea_from_type_datum(SMALLINT_T, data); - svhdr_1B_t *svhdr; + Datum data = PG_GETARG_DATUM(0); + bytea *result = gen_sqlvariant_bytea_from_type_datum(SMALLINT_T, data); + svhdr_1B_t *svhdr; - /* Type Specific Header */ - svhdr = SV_HDR_1B(result); - SV_SET_METADATA(svhdr, SMALLINT_T, HDR_VER); + /* Type Specific Header */ + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, SMALLINT_T, HDR_VER); - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } Datum tinyint2sqlvariant(PG_FUNCTION_ARGS) { - Datum data = PG_GETARG_DATUM(0); - bytea *result = gen_sqlvariant_bytea_from_type_datum(TINYINT_T, data); - svhdr_1B_t *svhdr; + Datum data = PG_GETARG_DATUM(0); + bytea *result = gen_sqlvariant_bytea_from_type_datum(TINYINT_T, data); + svhdr_1B_t *svhdr; - /* Type Specific Header */ - svhdr = SV_HDR_1B(result); - SV_SET_METADATA(svhdr, TINYINT_T, HDR_VER); + /* Type Specific Header */ + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, TINYINT_T, HDR_VER); - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } Datum bit2sqlvariant(PG_FUNCTION_ARGS) { - Datum data = PG_GETARG_DATUM(0); - bytea *result = gen_sqlvariant_bytea_from_type_datum(BIT_T, data); - svhdr_1B_t *svhdr; + Datum data = PG_GETARG_DATUM(0); + bytea *result = gen_sqlvariant_bytea_from_type_datum(BIT_T, data); + svhdr_1B_t *svhdr; - /* Type Specific Header */ - svhdr = SV_HDR_1B(result); - SV_SET_METADATA(svhdr, BIT_T, HDR_VER); + /* Type Specific Header */ + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, BIT_T, HDR_VER); - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } /* Character strings */ Datum varchar2sqlvariant(PG_FUNCTION_ARGS) { - VarChar *vch = PG_GETARG_VARCHAR_PP(0); - Oid coll = PG_GET_COLLATION(); - bytea *result = gen_sqlvariant_bytea_from_type_datum(VARCHAR_T, PointerGetDatum(vch)); - svhdr_5B_t *svhdr; + VarChar *vch = PG_GETARG_VARCHAR_PP(0); + Oid coll = PG_GET_COLLATION(); + bytea *result = gen_sqlvariant_bytea_from_type_datum(VARCHAR_T, PointerGetDatum(vch)); + svhdr_5B_t *svhdr; - /* Type Specific Header */ - svhdr = SV_HDR_5B(result); - SV_SET_METADATA(svhdr, VARCHAR_T, HDR_VER); - svhdr->typmod = VARSIZE_ANY_EXHDR(vch); - svhdr->collid = get_persist_collation_id(coll); + /* Type Specific Header */ + svhdr = SV_HDR_5B(result); + SV_SET_METADATA(svhdr, VARCHAR_T, HDR_VER); + svhdr->typmod = VARSIZE_ANY_EXHDR(vch); + svhdr->collid = get_persist_collation_id(coll); - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } Datum nvarchar2sqlvariant(PG_FUNCTION_ARGS) { - VarChar *vch = PG_GETARG_VARCHAR_PP(0); - Oid coll = PG_GET_COLLATION(); - bytea *result = gen_sqlvariant_bytea_from_type_datum(NVARCHAR_T, PointerGetDatum(vch)); - svhdr_5B_t *svhdr; + VarChar *vch = PG_GETARG_VARCHAR_PP(0); + Oid coll = PG_GET_COLLATION(); + bytea *result = gen_sqlvariant_bytea_from_type_datum(NVARCHAR_T, PointerGetDatum(vch)); + svhdr_5B_t *svhdr; - /* Type Specific Header */ - svhdr = SV_HDR_5B(result); - SV_SET_METADATA(svhdr, NVARCHAR_T, HDR_VER); - svhdr->typmod = VARSIZE_ANY_EXHDR(vch); - svhdr->collid = get_persist_collation_id(coll); + /* Type Specific Header */ + svhdr = SV_HDR_5B(result); + SV_SET_METADATA(svhdr, NVARCHAR_T, HDR_VER); + svhdr->typmod = VARSIZE_ANY_EXHDR(vch); + svhdr->collid = get_persist_collation_id(coll); - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } Datum char2sqlvariant(PG_FUNCTION_ARGS) { - BpChar *bpch = PG_GETARG_BPCHAR_PP(0); - Oid coll = PG_GET_COLLATION(); - bytea *result = gen_sqlvariant_bytea_from_type_datum(CHAR_T, PointerGetDatum(bpch)); - svhdr_5B_t *svhdr; + BpChar *bpch = PG_GETARG_BPCHAR_PP(0); + Oid coll = PG_GET_COLLATION(); + bytea *result = gen_sqlvariant_bytea_from_type_datum(CHAR_T, PointerGetDatum(bpch)); + svhdr_5B_t *svhdr; - /* Type Specific Header */ - svhdr = SV_HDR_5B(result); - SV_SET_METADATA(svhdr, CHAR_T, HDR_VER); - svhdr->typmod = VARSIZE_ANY_EXHDR(bpch); - svhdr->collid = get_persist_collation_id(coll); + /* Type Specific Header */ + svhdr = SV_HDR_5B(result); + SV_SET_METADATA(svhdr, CHAR_T, HDR_VER); + svhdr->typmod = VARSIZE_ANY_EXHDR(bpch); + svhdr->collid = get_persist_collation_id(coll); - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } Datum nchar2sqlvariant(PG_FUNCTION_ARGS) { - BpChar *bpch = PG_GETARG_BPCHAR_PP(0); - Oid coll = PG_GET_COLLATION(); - bytea *result = gen_sqlvariant_bytea_from_type_datum(NCHAR_T, PointerGetDatum(bpch)); - svhdr_5B_t *svhdr; + BpChar *bpch = PG_GETARG_BPCHAR_PP(0); + Oid coll = PG_GET_COLLATION(); + bytea *result = gen_sqlvariant_bytea_from_type_datum(NCHAR_T, PointerGetDatum(bpch)); + svhdr_5B_t *svhdr; - /* Type Specific Header */ - svhdr = SV_HDR_5B(result); - SV_SET_METADATA(svhdr, NCHAR_T, HDR_VER); - svhdr->typmod = VARSIZE_ANY_EXHDR(bpch); - svhdr->collid = get_persist_collation_id(coll); + /* Type Specific Header */ + svhdr = SV_HDR_5B(result); + SV_SET_METADATA(svhdr, NCHAR_T, HDR_VER); + svhdr->typmod = VARSIZE_ANY_EXHDR(bpch); + svhdr->collid = get_persist_collation_id(coll); - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } /* Binary strings */ Datum bbfvarbinary2sqlvariant(PG_FUNCTION_ARGS) { - bytea *bt = PG_GETARG_BYTEA_PP(0); - bytea *result = gen_sqlvariant_bytea_from_type_datum(VARBINARY_T, PointerGetDatum(bt)); - svhdr_3B_t *svhdr; + bytea *bt = PG_GETARG_BYTEA_PP(0); + bytea *result = gen_sqlvariant_bytea_from_type_datum(VARBINARY_T, PointerGetDatum(bt)); + svhdr_3B_t *svhdr; - /* Type Specific Header */ - svhdr = SV_HDR_3B(result); - SV_SET_METADATA(svhdr, VARBINARY_T, HDR_VER); - svhdr->typmod = VARSIZE_ANY_EXHDR(bt); + /* Type Specific Header */ + svhdr = SV_HDR_3B(result); + SV_SET_METADATA(svhdr, VARBINARY_T, HDR_VER); + svhdr->typmod = VARSIZE_ANY_EXHDR(bt); - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } Datum bbfbinary2sqlvariant(PG_FUNCTION_ARGS) { - bytea *bt = PG_GETARG_BYTEA_PP(0); - bytea *result = gen_sqlvariant_bytea_from_type_datum(BINARY_T, PointerGetDatum(bt)); - svhdr_3B_t *svhdr; + bytea *bt = PG_GETARG_BYTEA_PP(0); + bytea *result = gen_sqlvariant_bytea_from_type_datum(BINARY_T, PointerGetDatum(bt)); + svhdr_3B_t *svhdr; - /* Type Specific Header */ - svhdr = SV_HDR_3B(result); - SV_SET_METADATA(svhdr, BINARY_T, HDR_VER); - svhdr->typmod = VARSIZE_ANY_EXHDR(bt); + /* Type Specific Header */ + svhdr = SV_HDR_3B(result); + SV_SET_METADATA(svhdr, BINARY_T, HDR_VER); + svhdr->typmod = VARSIZE_ANY_EXHDR(bt); - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } Datum uniqueidentifier2sqlvariant(PG_FUNCTION_ARGS) { - Datum data = PG_GETARG_DATUM(0); - bytea *result = gen_sqlvariant_bytea_from_type_datum(UNIQUEIDENTIFIER_T, data); - svhdr_1B_t *svhdr; + Datum data = PG_GETARG_DATUM(0); + bytea *result = gen_sqlvariant_bytea_from_type_datum(UNIQUEIDENTIFIER_T, data); + svhdr_1B_t *svhdr; - /* Type Specific Header */ - svhdr = SV_HDR_1B(result); - SV_SET_METADATA(svhdr, UNIQUEIDENTIFIER_T, HDR_VER); + /* Type Specific Header */ + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, UNIQUEIDENTIFIER_T, HDR_VER); - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } @@ -914,217 +926,217 @@ PG_FUNCTION_INFO_V1(sqlvariant2uniqueidentifier); Datum sqlvariant2timestamp(PG_FUNCTION_ARGS) { - bytea *sv = PG_GETARG_BYTEA_PP(0); - Oid coll = PG_GET_COLLATION(); - Timestamp result; + bytea *sv = PG_GETARG_BYTEA_PP(0); + Oid coll = PG_GET_COLLATION(); + Timestamp result; - result = DatumGetTimestamp(gen_type_datum_from_sqlvariant_bytea(sv, DATETIME_T, -1, coll)); + result = DatumGetTimestamp(gen_type_datum_from_sqlvariant_bytea(sv, DATETIME_T, -1, coll)); - PG_RETURN_TIMESTAMP(result); + PG_RETURN_TIMESTAMP(result); } Datum sqlvariant2datetime2(PG_FUNCTION_ARGS) { - bytea *sv = PG_GETARG_BYTEA_PP(0); - Oid coll = PG_GET_COLLATION(); - Timestamp result; + bytea *sv = PG_GETARG_BYTEA_PP(0); + Oid coll = PG_GET_COLLATION(); + Timestamp result; - result = DatumGetTimestamp(gen_type_datum_from_sqlvariant_bytea(sv, DATETIME2_T, -1, coll)); + result = DatumGetTimestamp(gen_type_datum_from_sqlvariant_bytea(sv, DATETIME2_T, -1, coll)); - PG_RETURN_TIMESTAMP(result); + PG_RETURN_TIMESTAMP(result); } Datum sqlvariant2datetimeoffset(PG_FUNCTION_ARGS) { - bytea *sv = PG_GETARG_BYTEA_PP(0); - Oid coll = PG_GET_COLLATION(); - tsql_datetimeoffset *result; + bytea *sv = PG_GETARG_BYTEA_PP(0); + Oid coll = PG_GET_COLLATION(); + tsql_datetimeoffset *result; - result = DatumGetDatetimeoffset(gen_type_datum_from_sqlvariant_bytea(sv, DATETIMEOFFSET_T, -1, coll)); + result = DatumGetDatetimeoffset(gen_type_datum_from_sqlvariant_bytea(sv, DATETIMEOFFSET_T, -1, coll)); - PG_RETURN_DATETIMEOFFSET(result); + PG_RETURN_DATETIMEOFFSET(result); } Datum sqlvariant2date(PG_FUNCTION_ARGS) { - bytea *sv = PG_GETARG_BYTEA_PP(0); - Oid coll = PG_GET_COLLATION(); - DateADT result; + bytea *sv = PG_GETARG_BYTEA_PP(0); + Oid coll = PG_GET_COLLATION(); + DateADT result; - result = DatumGetDateADT(gen_type_datum_from_sqlvariant_bytea(sv, DATE_T, -1, coll)); + result = DatumGetDateADT(gen_type_datum_from_sqlvariant_bytea(sv, DATE_T, -1, coll)); - PG_RETURN_DATEADT(result); + PG_RETURN_DATEADT(result); } Datum sqlvariant2time(PG_FUNCTION_ARGS) { - bytea *sv = PG_GETARG_BYTEA_PP(0); - Oid coll = PG_GET_COLLATION(); - TimeADT result; + bytea *sv = PG_GETARG_BYTEA_PP(0); + Oid coll = PG_GET_COLLATION(); + TimeADT result; - result = DatumGetTimeADT(gen_type_datum_from_sqlvariant_bytea(sv, TIME_T, -1, coll)); + result = DatumGetTimeADT(gen_type_datum_from_sqlvariant_bytea(sv, TIME_T, -1, coll)); - PG_RETURN_TIMEADT(result); + PG_RETURN_TIMEADT(result); } Datum sqlvariant2float(PG_FUNCTION_ARGS) { - bytea *sv = PG_GETARG_BYTEA_PP(0); - Oid coll = PG_GET_COLLATION(); - double result; + bytea *sv = PG_GETARG_BYTEA_PP(0); + Oid coll = PG_GET_COLLATION(); + double result; - result = DatumGetFloat8(gen_type_datum_from_sqlvariant_bytea(sv, FLOAT_T, -1, coll)); + result = DatumGetFloat8(gen_type_datum_from_sqlvariant_bytea(sv, FLOAT_T, -1, coll)); - PG_RETURN_FLOAT8(result); + PG_RETURN_FLOAT8(result); } Datum sqlvariant2real(PG_FUNCTION_ARGS) { - bytea *sv = PG_GETARG_BYTEA_PP(0); - Oid coll = PG_GET_COLLATION(); - float result; + bytea *sv = PG_GETARG_BYTEA_PP(0); + Oid coll = PG_GET_COLLATION(); + float result; - result = DatumGetFloat4(gen_type_datum_from_sqlvariant_bytea(sv, REAL_T, -1, coll)); + result = DatumGetFloat4(gen_type_datum_from_sqlvariant_bytea(sv, REAL_T, -1, coll)); - PG_RETURN_FLOAT4(result); + PG_RETURN_FLOAT4(result); } Datum sqlvariant2numeric(PG_FUNCTION_ARGS) { - bytea *sv = PG_GETARG_BYTEA_PP(0); - Oid coll = PG_GET_COLLATION(); - Numeric result; + bytea *sv = PG_GETARG_BYTEA_PP(0); + Oid coll = PG_GET_COLLATION(); + Numeric result; - result = DatumGetNumeric(gen_type_datum_from_sqlvariant_bytea(sv, NUMERIC_T, -1, coll)); + result = DatumGetNumeric(gen_type_datum_from_sqlvariant_bytea(sv, NUMERIC_T, -1, coll)); - PG_RETURN_NUMERIC(result); + PG_RETURN_NUMERIC(result); } Datum sqlvariant2fixeddecimal(PG_FUNCTION_ARGS) { - bytea *sv = PG_GETARG_BYTEA_PP(0); - Oid coll = PG_GET_COLLATION(); - int64 result; + bytea *sv = PG_GETARG_BYTEA_PP(0); + Oid coll = PG_GET_COLLATION(); + int64 result; - result = DatumGetInt64(gen_type_datum_from_sqlvariant_bytea(sv, MONEY_T, -1, coll)); + result = DatumGetInt64(gen_type_datum_from_sqlvariant_bytea(sv, MONEY_T, -1, coll)); - PG_RETURN_INT64(result); + PG_RETURN_INT64(result); } Datum sqlvariant2bigint(PG_FUNCTION_ARGS) { - bytea *sv = PG_GETARG_BYTEA_PP(0); - Oid coll = PG_GET_COLLATION(); - int64 result; + bytea *sv = PG_GETARG_BYTEA_PP(0); + Oid coll = PG_GET_COLLATION(); + int64 result; - result = DatumGetInt64(gen_type_datum_from_sqlvariant_bytea(sv, BIGINT_T, -1, coll)); + result = DatumGetInt64(gen_type_datum_from_sqlvariant_bytea(sv, BIGINT_T, -1, coll)); - PG_RETURN_INT64(result); + PG_RETURN_INT64(result); } Datum sqlvariant2int(PG_FUNCTION_ARGS) { - bytea *sv = PG_GETARG_BYTEA_PP(0); - Oid coll = PG_GET_COLLATION(); - int32 result; + bytea *sv = PG_GETARG_BYTEA_PP(0); + Oid coll = PG_GET_COLLATION(); + int32 result; - result = DatumGetInt32(gen_type_datum_from_sqlvariant_bytea(sv, INT_T, -1, coll)); + result = DatumGetInt32(gen_type_datum_from_sqlvariant_bytea(sv, INT_T, -1, coll)); - PG_RETURN_INT32(result); + PG_RETURN_INT32(result); } Datum sqlvariant2smallint(PG_FUNCTION_ARGS) { - bytea *sv = PG_GETARG_BYTEA_PP(0); - Oid coll = PG_GET_COLLATION(); - int16 result; + bytea *sv = PG_GETARG_BYTEA_PP(0); + Oid coll = PG_GET_COLLATION(); + int16 result; - result = DatumGetInt16(gen_type_datum_from_sqlvariant_bytea(sv, SMALLINT_T, -1, coll)); + result = DatumGetInt16(gen_type_datum_from_sqlvariant_bytea(sv, SMALLINT_T, -1, coll)); - PG_RETURN_INT16(result); + PG_RETURN_INT16(result); } Datum sqlvariant2bit(PG_FUNCTION_ARGS) { - bytea *sv = PG_GETARG_BYTEA_PP(0); - Oid coll = PG_GET_COLLATION(); - bool result; + bytea *sv = PG_GETARG_BYTEA_PP(0); + Oid coll = PG_GET_COLLATION(); + bool result; - result = DatumGetBool(gen_type_datum_from_sqlvariant_bytea(sv, BIT_T, -1, coll)); + result = DatumGetBool(gen_type_datum_from_sqlvariant_bytea(sv, BIT_T, -1, coll)); - PG_RETURN_BOOL(result); + PG_RETURN_BOOL(result); } Datum sqlvariant2varchar(PG_FUNCTION_ARGS) { - bytea *sv = PG_GETARG_BYTEA_PP(0); - Oid coll = PG_GET_COLLATION(); - VarChar *result; + bytea *sv = PG_GETARG_BYTEA_PP(0); + Oid coll = PG_GET_COLLATION(); + VarChar *result; - result = DatumGetVarCharP(gen_type_datum_from_sqlvariant_bytea(sv, VARCHAR_T, -1, coll)); + result = DatumGetVarCharP(gen_type_datum_from_sqlvariant_bytea(sv, VARCHAR_T, -1, coll)); - PG_RETURN_VARCHAR_P(result); + PG_RETURN_VARCHAR_P(result); } Datum sqlvariant2char(PG_FUNCTION_ARGS) { - bytea *sv = PG_GETARG_BYTEA_PP(0); - Oid coll = PG_GET_COLLATION(); - BpChar *result; + bytea *sv = PG_GETARG_BYTEA_PP(0); + Oid coll = PG_GET_COLLATION(); + BpChar *result; - result = DatumGetBpCharP(gen_type_datum_from_sqlvariant_bytea(sv, CHAR_T, -1, coll)); + result = DatumGetBpCharP(gen_type_datum_from_sqlvariant_bytea(sv, CHAR_T, -1, coll)); - PG_RETURN_BPCHAR_P(result); + PG_RETURN_BPCHAR_P(result); } Datum sqlvariant2bbfvarbinary(PG_FUNCTION_ARGS) { - bytea *sv = PG_GETARG_BYTEA_PP(0); - Oid coll = PG_GET_COLLATION(); - bytea *result; + bytea *sv = PG_GETARG_BYTEA_PP(0); + Oid coll = PG_GET_COLLATION(); + bytea *result; - result = DatumGetByteaP(gen_type_datum_from_sqlvariant_bytea(sv, VARBINARY_T, -1, coll)); + result = DatumGetByteaP(gen_type_datum_from_sqlvariant_bytea(sv, VARBINARY_T, -1, coll)); - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } Datum sqlvariant2bbfbinary(PG_FUNCTION_ARGS) { - bytea *sv = PG_GETARG_BYTEA_PP(0); - Oid coll = PG_GET_COLLATION(); - bytea *result; + bytea *sv = PG_GETARG_BYTEA_PP(0); + Oid coll = PG_GET_COLLATION(); + bytea *result; - result = DatumGetByteaP(gen_type_datum_from_sqlvariant_bytea(sv, BINARY_T, -1, coll)); + result = DatumGetByteaP(gen_type_datum_from_sqlvariant_bytea(sv, BINARY_T, -1, coll)); - PG_RETURN_BYTEA_P(result); + PG_RETURN_BYTEA_P(result); } Datum sqlvariant2uniqueidentifier(PG_FUNCTION_ARGS) { - bytea *sv = PG_GETARG_BYTEA_PP(0); - Oid coll = PG_GET_COLLATION(); - pg_uuid_t *result; + bytea *sv = PG_GETARG_BYTEA_PP(0); + Oid coll = PG_GET_COLLATION(); + pg_uuid_t *result; - result = DatumGetUUIDP(gen_type_datum_from_sqlvariant_bytea(sv, UNIQUEIDENTIFIER_T, -1, coll)); + result = DatumGetUUIDP(gen_type_datum_from_sqlvariant_bytea(sv, UNIQUEIDENTIFIER_T, -1, coll)); - PG_RETURN_UUID_P(result); + PG_RETURN_UUID_P(result); } /* @@ -1134,13 +1146,13 @@ sqlvariant2uniqueidentifier(PG_FUNCTION_ARGS) PG_FUNCTION_INFO_V1(sql_variant_property); typedef enum sv_property { - SV_PROPERTY_BASETYPE, - SV_PROPERTY_PRECISION, - SV_PROPERTY_SCALE, - SV_PROPERTY_TOTALBYTES, - SV_PROPERTY_COLLATION, - SV_PROPERTY_MAXLENGTH, - SV_PROPERTY_INVALID + SV_PROPERTY_BASETYPE, + SV_PROPERTY_PRECISION, + SV_PROPERTY_SCALE, + SV_PROPERTY_TOTALBYTES, + SV_PROPERTY_COLLATION, + SV_PROPERTY_MAXLENGTH, + SV_PROPERTY_INVALID } sv_property_t; static sv_property_t get_property_type(const char *arg, int len); @@ -1153,379 +1165,381 @@ static Datum get_max_length(bytea *sv_value); sv_property_t get_property_type(const char *arg, int len) { - /* Incase sensitive match, No prefix/suffix spaces handling */ - if (pg_strncasecmp(arg, "basetype", len) == 0) - return SV_PROPERTY_BASETYPE; - else if (pg_strncasecmp(arg, "precision", len) == 0) - return SV_PROPERTY_PRECISION; - else if (pg_strncasecmp(arg, "scale", len) == 0) - return SV_PROPERTY_SCALE; - else if (pg_strncasecmp(arg, "totalbytes", len) == 0) - return SV_PROPERTY_TOTALBYTES; - else if (pg_strncasecmp(arg, "collation", len) == 0) - return SV_PROPERTY_COLLATION; - else if (pg_strncasecmp(arg, "maxlength", len) == 0) - return SV_PROPERTY_MAXLENGTH; - else - return SV_PROPERTY_INVALID; + /* Incase sensitive match, No prefix/suffix spaces handling */ + if (pg_strncasecmp(arg, "basetype", len) == 0) + return SV_PROPERTY_BASETYPE; + else if (pg_strncasecmp(arg, "precision", len) == 0) + return SV_PROPERTY_PRECISION; + else if (pg_strncasecmp(arg, "scale", len) == 0) + return SV_PROPERTY_SCALE; + else if (pg_strncasecmp(arg, "totalbytes", len) == 0) + return SV_PROPERTY_TOTALBYTES; + else if (pg_strncasecmp(arg, "collation", len) == 0) + return SV_PROPERTY_COLLATION; + else if (pg_strncasecmp(arg, "maxlength", len) == 0) + return SV_PROPERTY_MAXLENGTH; + else + return SV_PROPERTY_INVALID; } Datum get_base_type(bytea *sv_value) { - uint8_t type_code = SV_GET_TYPCODE_PTR(sv_value); - const char *type_name = get_tsql_type_info(type_code).tsql_typname; + uint8_t type_code = SV_GET_TYPCODE_PTR(sv_value); + const char *type_name = get_tsql_type_info(type_code).tsql_typname; - return get_varchar128_sv_datum(type_name); + return get_varchar128_sv_datum(type_name); } Datum get_precision(bytea *sv_value) { - uint8_t type_code = SV_GET_TYPCODE_PTR(sv_value); - uint8_t svhdr_size = get_tsql_type_info(type_code).svhdr_size; - int16_t typmod; - int precision; - svhdr_2B_t *svhdr_2b; - svhdr_3B_t *svhdr_3b; - svhdr_5B_t *svhdr_5b; - - switch(svhdr_size) - { - case 2: - svhdr_2b = SV_HDR_2B(sv_value); - typmod = svhdr_2b->typmod; - break; - case 3: - svhdr_3b = SV_HDR_3B(sv_value); - typmod = svhdr_3b->typmod; - break; - case 5: - svhdr_5b = SV_HDR_5B(sv_value); - typmod = svhdr_5b->typmod; - break; - default: - typmod = 0; - } - - - switch(type_code) - { - case DATETIME2_T: - if (typmod == -1) - precision = 27; - else if (typmod == 0) - precision = 19; - else - precision = typmod + 20; - break; - case DATETIMEOFFSET_T: - if (typmod == -1) - precision = 34; - else if (typmod == 0) - precision = 26; - else - precision = typmod + 27; - break; - case DATETIME_T: - precision = 23; - break; - case SMALLDATETIME_T: - precision = 16; - break; - case DATE_T: - precision = 10; - break; - case TIME_T: - if (typmod == -1) - precision = 16; - else if (typmod == 0) - precision = 8; - else - precision = typmod + 9; - break; - case FLOAT_T: - precision = 53; - break; - case REAL_T: - precision = 24; - break; - case NUMERIC_T: - if (typmod == -1) - precision = 18; - else - precision = (typmod >> 8) & 0xFF; - break; - break; - case MONEY_T: - precision = 19; - break; - case SMALLMONEY_T: - precision = 10; - break; - case BIGINT_T: - precision = 19; - break; - case INT_T: - precision = 10; - break; - case SMALLINT_T: - precision = 5; - break; - case TINYINT_T: - precision = 3; - break; - case BIT_T: - precision = 1; - break; - case NVARCHAR_T: - case NCHAR_T: - case VARCHAR_T: - case CHAR_T: - case VARBINARY_T: - case BINARY_T: - case UNIQUEIDENTIFIER_T: - precision = 0; - break; - default: - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH ), - errmsg("Unknown Internal data type code %d", type_code))); - } - - return get_int_sv_datum(precision); + uint8_t type_code = SV_GET_TYPCODE_PTR(sv_value); + uint8_t svhdr_size = get_tsql_type_info(type_code).svhdr_size; + int16_t typmod; + int precision; + svhdr_2B_t *svhdr_2b; + svhdr_3B_t *svhdr_3b; + svhdr_5B_t *svhdr_5b; + + switch (svhdr_size) + { + case 2: + svhdr_2b = SV_HDR_2B(sv_value); + typmod = svhdr_2b->typmod; + break; + case 3: + svhdr_3b = SV_HDR_3B(sv_value); + typmod = svhdr_3b->typmod; + break; + case 5: + svhdr_5b = SV_HDR_5B(sv_value); + typmod = svhdr_5b->typmod; + break; + default: + typmod = 0; + } + + + switch (type_code) + { + case DATETIME2_T: + if (typmod == -1) + precision = 27; + else if (typmod == 0) + precision = 19; + else + precision = typmod + 20; + break; + case DATETIMEOFFSET_T: + if (typmod == -1) + precision = 34; + else if (typmod == 0) + precision = 26; + else + precision = typmod + 27; + break; + case DATETIME_T: + precision = 23; + break; + case SMALLDATETIME_T: + precision = 16; + break; + case DATE_T: + precision = 10; + break; + case TIME_T: + if (typmod == -1) + precision = 16; + else if (typmod == 0) + precision = 8; + else + precision = typmod + 9; + break; + case FLOAT_T: + precision = 53; + break; + case REAL_T: + precision = 24; + break; + case NUMERIC_T: + if (typmod == -1) + precision = 18; + else + precision = (typmod >> 8) & 0xFF; + break; + break; + case MONEY_T: + precision = 19; + break; + case SMALLMONEY_T: + precision = 10; + break; + case BIGINT_T: + precision = 19; + break; + case INT_T: + precision = 10; + break; + case SMALLINT_T: + precision = 5; + break; + case TINYINT_T: + precision = 3; + break; + case BIT_T: + precision = 1; + break; + case NVARCHAR_T: + case NCHAR_T: + case VARCHAR_T: + case CHAR_T: + case VARBINARY_T: + case BINARY_T: + case UNIQUEIDENTIFIER_T: + precision = 0; + break; + default: + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("Unknown Internal data type code %d", type_code))); + } + + return get_int_sv_datum(precision); } Datum get_scale(bytea *sv_value) { - uint8_t type_code = SV_GET_TYPCODE_PTR(sv_value); - uint8_t svhdr_size = get_tsql_type_info(type_code).svhdr_size; - int16_t typmod; - int scale; - svhdr_2B_t *svhdr_2b; - svhdr_3B_t *svhdr_3b; - svhdr_5B_t *svhdr_5b; - - switch(svhdr_size) - { - case 2: - svhdr_2b = SV_HDR_2B(sv_value); - typmod = svhdr_2b->typmod; - break; - case 3: - svhdr_3b = SV_HDR_3B(sv_value); - typmod = svhdr_3b->typmod; - break; - case 5: - svhdr_5b = SV_HDR_5B(sv_value); - typmod = svhdr_5b->typmod; - break; - default: - typmod = 0; - } - - - switch(type_code) - { - case DATETIME2_T: - if (typmod == -1) - scale = 7; - else - scale = typmod; - break; - case DATETIMEOFFSET_T: - if (typmod == -1) - scale = 7; - else - scale = typmod; - break; - case DATETIME_T: - scale = 3; - break; - case SMALLDATETIME_T: - case DATE_T: - scale = 0; - break; - case TIME_T: - if (typmod == -1) - scale = 7; - else - scale = typmod; - break; - case FLOAT_T: - case REAL_T: - scale = 0; - break; - case NUMERIC_T: - if (typmod == -1) - scale = 0; - else - scale = typmod & 0xFF; - break; - case MONEY_T: - scale = 4; - break; - case SMALLMONEY_T: - scale = 4; - break; - case BIGINT_T: - case INT_T: - case SMALLINT_T: - case TINYINT_T: - case BIT_T: - case NVARCHAR_T: - case NCHAR_T: - case VARCHAR_T: - case CHAR_T: - case VARBINARY_T: - case BINARY_T: - case UNIQUEIDENTIFIER_T: - scale = 0; - break; - default: - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH ), - errmsg("Unknown Internal data type code %d", type_code))); - } - - return get_int_sv_datum(scale); + uint8_t type_code = SV_GET_TYPCODE_PTR(sv_value); + uint8_t svhdr_size = get_tsql_type_info(type_code).svhdr_size; + int16_t typmod; + int scale; + svhdr_2B_t *svhdr_2b; + svhdr_3B_t *svhdr_3b; + svhdr_5B_t *svhdr_5b; + + switch (svhdr_size) + { + case 2: + svhdr_2b = SV_HDR_2B(sv_value); + typmod = svhdr_2b->typmod; + break; + case 3: + svhdr_3b = SV_HDR_3B(sv_value); + typmod = svhdr_3b->typmod; + break; + case 5: + svhdr_5b = SV_HDR_5B(sv_value); + typmod = svhdr_5b->typmod; + break; + default: + typmod = 0; + } + + + switch (type_code) + { + case DATETIME2_T: + if (typmod == -1) + scale = 7; + else + scale = typmod; + break; + case DATETIMEOFFSET_T: + if (typmod == -1) + scale = 7; + else + scale = typmod; + break; + case DATETIME_T: + scale = 3; + break; + case SMALLDATETIME_T: + case DATE_T: + scale = 0; + break; + case TIME_T: + if (typmod == -1) + scale = 7; + else + scale = typmod; + break; + case FLOAT_T: + case REAL_T: + scale = 0; + break; + case NUMERIC_T: + if (typmod == -1) + scale = 0; + else + scale = typmod & 0xFF; + break; + case MONEY_T: + scale = 4; + break; + case SMALLMONEY_T: + scale = 4; + break; + case BIGINT_T: + case INT_T: + case SMALLINT_T: + case TINYINT_T: + case BIT_T: + case NVARCHAR_T: + case NCHAR_T: + case VARCHAR_T: + case CHAR_T: + case VARBINARY_T: + case BINARY_T: + case UNIQUEIDENTIFIER_T: + scale = 0; + break; + default: + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("Unknown Internal data type code %d", type_code))); + } + + return get_int_sv_datum(scale); } Datum get_total_bytes(bytea *sv_value) { - return get_int_sv_datum(VARSIZE_ANY(sv_value)); + return get_int_sv_datum(VARSIZE_ANY(sv_value)); } Datum get_max_length(bytea *sv_value) { - uint8_t type_code = SV_GET_TYPCODE_PTR(sv_value); - int max_len; - - switch(type_code) - { - case DATETIME2_T: - max_len = 8; - break; - case DATETIMEOFFSET_T: - max_len = 10; - break; - case DATETIME_T: - max_len = 8; - break; - case SMALLDATETIME_T: - max_len = 8; - break; - case DATE_T: - max_len = 4; - break; - case TIME_T: - max_len = 8; - break; - case FLOAT_T: - max_len = 8; - break; - case REAL_T: - max_len = 4; - break; - case NUMERIC_T: - max_len = 65535; - break; - case MONEY_T: - max_len = 8; - break; - case SMALLMONEY_T: - max_len = 8; - break; - case BIGINT_T: - max_len = 8; - break; - case INT_T: - max_len = 4; - break; - case SMALLINT_T: - max_len = 2; - break; - case TINYINT_T: - max_len = 2; - break; - case BIT_T: - max_len = 1; - break; - case NVARCHAR_T: - case NCHAR_T: - case VARCHAR_T: - case CHAR_T: - case VARBINARY_T: - case BINARY_T: - max_len = 65535; - break; - case UNIQUEIDENTIFIER_T: - max_len = 16; - break; - default: - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH ), - errmsg("Unknown Internal data type code %d", type_code))); - - } - - return get_int_sv_datum(max_len); + uint8_t type_code = SV_GET_TYPCODE_PTR(sv_value); + int max_len; + + switch (type_code) + { + case DATETIME2_T: + max_len = 8; + break; + case DATETIMEOFFSET_T: + max_len = 10; + break; + case DATETIME_T: + max_len = 8; + break; + case SMALLDATETIME_T: + max_len = 8; + break; + case DATE_T: + max_len = 4; + break; + case TIME_T: + max_len = 8; + break; + case FLOAT_T: + max_len = 8; + break; + case REAL_T: + max_len = 4; + break; + case NUMERIC_T: + max_len = 65535; + break; + case MONEY_T: + max_len = 8; + break; + case SMALLMONEY_T: + max_len = 8; + break; + case BIGINT_T: + max_len = 8; + break; + case INT_T: + max_len = 4; + break; + case SMALLINT_T: + max_len = 2; + break; + case TINYINT_T: + max_len = 2; + break; + case BIT_T: + max_len = 1; + break; + case NVARCHAR_T: + case NCHAR_T: + case VARCHAR_T: + case CHAR_T: + case VARBINARY_T: + case BINARY_T: + max_len = 65535; + break; + case UNIQUEIDENTIFIER_T: + max_len = 16; + break; + default: + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("Unknown Internal data type code %d", type_code))); + + } + + return get_int_sv_datum(max_len); } Datum sql_variant_property(PG_FUNCTION_ARGS) { - bytea *sv_value = PG_GETARG_BYTEA_PP(0); - int prop_len = VARSIZE_ANY_EXHDR(PG_GETARG_BYTEA_PP(1)); - const char *prop_str = VARDATA_ANY(PG_GETARG_BYTEA_PP(1)); - sv_property_t prop_type; - - /* CHECK Validity of Property */ - prop_type = get_property_type(prop_str, prop_len); - if (prop_type == SV_PROPERTY_INVALID) - PG_RETURN_NULL(); - - /* Dispatch to property functions */ - switch(prop_type) - { - case SV_PROPERTY_BASETYPE: - return get_base_type(sv_value); - case SV_PROPERTY_PRECISION: - return get_precision(sv_value); - case SV_PROPERTY_SCALE: - return get_scale(sv_value); - case SV_PROPERTY_TOTALBYTES: - return get_total_bytes(sv_value); - case SV_PROPERTY_COLLATION: - { - uint8_t type_code = SV_GET_TYPCODE_PTR(sv_value); - switch (type_code) - { - case NVARCHAR_T: - case NCHAR_T: - case VARCHAR_T: - case CHAR_T: - { - svhdr_5B_t *svhdr_5b = SV_HDR_5B(sv_value); - Oid coll_oid = get_tsql_collation_oid(svhdr_5b->collid); - char *collname; - collname = get_collation_name(coll_oid); - return get_varchar128_sv_datum(collname); - } - default: - break; - } - PG_RETURN_NULL(); - } - case SV_PROPERTY_MAXLENGTH: - return get_max_length(sv_value); - default: - break; - } - PG_RETURN_NULL(); /* SHOULD NOT HAPPEN */ + bytea *sv_value = PG_GETARG_BYTEA_PP(0); + int prop_len = VARSIZE_ANY_EXHDR(PG_GETARG_BYTEA_PP(1)); + const char *prop_str = VARDATA_ANY(PG_GETARG_BYTEA_PP(1)); + sv_property_t prop_type; + + /* CHECK Validity of Property */ + prop_type = get_property_type(prop_str, prop_len); + if (prop_type == SV_PROPERTY_INVALID) + PG_RETURN_NULL(); + + /* Dispatch to property functions */ + switch (prop_type) + { + case SV_PROPERTY_BASETYPE: + return get_base_type(sv_value); + case SV_PROPERTY_PRECISION: + return get_precision(sv_value); + case SV_PROPERTY_SCALE: + return get_scale(sv_value); + case SV_PROPERTY_TOTALBYTES: + return get_total_bytes(sv_value); + case SV_PROPERTY_COLLATION: + { + uint8_t type_code = SV_GET_TYPCODE_PTR(sv_value); + + switch (type_code) + { + case NVARCHAR_T: + case NCHAR_T: + case VARCHAR_T: + case CHAR_T: + { + svhdr_5B_t *svhdr_5b = SV_HDR_5B(sv_value); + Oid coll_oid = get_tsql_collation_oid(svhdr_5b->collid); + char *collname; + + collname = get_collation_name(coll_oid); + return get_varchar128_sv_datum(collname); + } + default: + break; + } + PG_RETURN_NULL(); + } + case SV_PROPERTY_MAXLENGTH: + return get_max_length(sv_value); + default: + break; + } + PG_RETURN_NULL(); /* SHOULD NOT HAPPEN */ } /* @@ -1542,145 +1556,145 @@ PG_FUNCTION_INFO_V1(sqlvariantge); Datum sqlvariantlt(PG_FUNCTION_ARGS) { - bytea *arg1 = PG_GETARG_BYTEA_PP(0); - bytea *arg2 = PG_GETARG_BYTEA_PP(1); - uint8_t type_code1 = SV_GET_TYPCODE_PTR(arg1); - uint8_t type_code2 = SV_GET_TYPCODE_PTR(arg2); - uint8_t type_family1 = get_tsql_type_info(type_code1).family_prio; - uint8_t type_family2 = get_tsql_type_info(type_code2).family_prio; - char *oprname = "<"; - Datum result; + bytea *arg1 = PG_GETARG_BYTEA_PP(0); + bytea *arg2 = PG_GETARG_BYTEA_PP(1); + uint8_t type_code1 = SV_GET_TYPCODE_PTR(arg1); + uint8_t type_code2 = SV_GET_TYPCODE_PTR(arg2); + uint8_t type_family1 = get_tsql_type_info(type_code1).family_prio; + uint8_t type_family2 = get_tsql_type_info(type_code2).family_prio; + char *oprname = "<"; + Datum result; - if (type_family1 == type_family2) - result = do_compare(oprname, arg1, arg2, PG_GET_COLLATION()); - else /* based on type family precedence */ - result = BoolGetDatum(type_family1 > type_family2); + if (type_family1 == type_family2) + result = do_compare(oprname, arg1, arg2, PG_GET_COLLATION()); + else /* based on type family precedence */ + result = BoolGetDatum(type_family1 > type_family2); - /* Avoid leaking memory for toasted inputs */ - PG_FREE_IF_COPY(arg1, 0); - PG_FREE_IF_COPY(arg2, 1); + /* Avoid leaking memory for toasted inputs */ + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); - return result; + return result; } Datum sqlvariantle(PG_FUNCTION_ARGS) { - bytea *arg1 = PG_GETARG_BYTEA_PP(0); - bytea *arg2 = PG_GETARG_BYTEA_PP(1); - uint8_t type_code1 = SV_GET_TYPCODE_PTR(arg1); - uint8_t type_code2 = SV_GET_TYPCODE_PTR(arg2); - uint8_t type_family1 = get_tsql_type_info(type_code1).family_prio; - uint8_t type_family2 = get_tsql_type_info(type_code2).family_prio; - char *oprname = "<="; - Datum result; + bytea *arg1 = PG_GETARG_BYTEA_PP(0); + bytea *arg2 = PG_GETARG_BYTEA_PP(1); + uint8_t type_code1 = SV_GET_TYPCODE_PTR(arg1); + uint8_t type_code2 = SV_GET_TYPCODE_PTR(arg2); + uint8_t type_family1 = get_tsql_type_info(type_code1).family_prio; + uint8_t type_family2 = get_tsql_type_info(type_code2).family_prio; + char *oprname = "<="; + Datum result; - if (type_family1 == type_family2) - result = do_compare(oprname, arg1, arg2, PG_GET_COLLATION()); - else /* based on type family precedence */ - result = BoolGetDatum(type_family1 > type_family2); + if (type_family1 == type_family2) + result = do_compare(oprname, arg1, arg2, PG_GET_COLLATION()); + else /* based on type family precedence */ + result = BoolGetDatum(type_family1 > type_family2); - /* Avoid leaking memory for toasted inputs */ - PG_FREE_IF_COPY(arg1, 0); - PG_FREE_IF_COPY(arg2, 1); + /* Avoid leaking memory for toasted inputs */ + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); - return result; + return result; } Datum sqlvarianteq(PG_FUNCTION_ARGS) { - bytea *arg1 = PG_GETARG_BYTEA_PP(0); - bytea *arg2 = PG_GETARG_BYTEA_PP(1); - uint8_t type_code1 = SV_GET_TYPCODE_PTR(arg1); - uint8_t type_code2 = SV_GET_TYPCODE_PTR(arg2); - uint8_t type_family1 = get_tsql_type_info(type_code1).family_prio; - uint8_t type_family2 = get_tsql_type_info(type_code2).family_prio; - char *oprname = "="; - Datum result; + bytea *arg1 = PG_GETARG_BYTEA_PP(0); + bytea *arg2 = PG_GETARG_BYTEA_PP(1); + uint8_t type_code1 = SV_GET_TYPCODE_PTR(arg1); + uint8_t type_code2 = SV_GET_TYPCODE_PTR(arg2); + uint8_t type_family1 = get_tsql_type_info(type_code1).family_prio; + uint8_t type_family2 = get_tsql_type_info(type_code2).family_prio; + char *oprname = "="; + Datum result; - if (type_family1 == type_family2) - result = do_compare(oprname, arg1, arg2, PG_GET_COLLATION()); - else /* based on type family precedence */ - result = BoolGetDatum(false); + if (type_family1 == type_family2) + result = do_compare(oprname, arg1, arg2, PG_GET_COLLATION()); + else /* based on type family precedence */ + result = BoolGetDatum(false); - /* Avoid leaking memory for toasted inputs */ - PG_FREE_IF_COPY(arg1, 0); - PG_FREE_IF_COPY(arg2, 1); + /* Avoid leaking memory for toasted inputs */ + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); - return result; + return result; } Datum sqlvariantge(PG_FUNCTION_ARGS) { - bytea *arg1 = PG_GETARG_BYTEA_PP(0); - bytea *arg2 = PG_GETARG_BYTEA_PP(1); - uint8_t type_code1 = SV_GET_TYPCODE_PTR(arg1); - uint8_t type_code2 = SV_GET_TYPCODE_PTR(arg2); - uint8_t type_family1 = get_tsql_type_info(type_code1).family_prio; - uint8_t type_family2 = get_tsql_type_info(type_code2).family_prio; - char *oprname = ">="; - Datum result; + bytea *arg1 = PG_GETARG_BYTEA_PP(0); + bytea *arg2 = PG_GETARG_BYTEA_PP(1); + uint8_t type_code1 = SV_GET_TYPCODE_PTR(arg1); + uint8_t type_code2 = SV_GET_TYPCODE_PTR(arg2); + uint8_t type_family1 = get_tsql_type_info(type_code1).family_prio; + uint8_t type_family2 = get_tsql_type_info(type_code2).family_prio; + char *oprname = ">="; + Datum result; - if (type_family1 == type_family2) - result = do_compare(oprname, arg1, arg2, PG_GET_COLLATION()); - else /* based on type family precedence */ - result = BoolGetDatum(type_family1 < type_family2); + if (type_family1 == type_family2) + result = do_compare(oprname, arg1, arg2, PG_GET_COLLATION()); + else /* based on type family precedence */ + result = BoolGetDatum(type_family1 < type_family2); - /* Avoid leaking memory for toasted inputs */ - PG_FREE_IF_COPY(arg1, 0); - PG_FREE_IF_COPY(arg2, 1); + /* Avoid leaking memory for toasted inputs */ + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); - return result; + return result; } Datum sqlvariantgt(PG_FUNCTION_ARGS) { - bytea *arg1 = PG_GETARG_BYTEA_PP(0); - bytea *arg2 = PG_GETARG_BYTEA_PP(1); - uint8_t type_code1 = SV_GET_TYPCODE_PTR(arg1); - uint8_t type_code2 = SV_GET_TYPCODE_PTR(arg2); - uint8_t type_family1 = get_tsql_type_info(type_code1).family_prio; - uint8_t type_family2 = get_tsql_type_info(type_code2).family_prio; - char *oprname = ">"; - Datum result; + bytea *arg1 = PG_GETARG_BYTEA_PP(0); + bytea *arg2 = PG_GETARG_BYTEA_PP(1); + uint8_t type_code1 = SV_GET_TYPCODE_PTR(arg1); + uint8_t type_code2 = SV_GET_TYPCODE_PTR(arg2); + uint8_t type_family1 = get_tsql_type_info(type_code1).family_prio; + uint8_t type_family2 = get_tsql_type_info(type_code2).family_prio; + char *oprname = ">"; + Datum result; - if (type_family1 == type_family2) - result = do_compare(oprname, arg1, arg2, PG_GET_COLLATION()); - else /* based on type family precedence */ - result = BoolGetDatum(type_family1 < type_family2); + if (type_family1 == type_family2) + result = do_compare(oprname, arg1, arg2, PG_GET_COLLATION()); + else /* based on type family precedence */ + result = BoolGetDatum(type_family1 < type_family2); - /* Avoid leaking memory for toasted inputs */ - PG_FREE_IF_COPY(arg1, 0); - PG_FREE_IF_COPY(arg2, 1); + /* Avoid leaking memory for toasted inputs */ + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); - return result; + return result; } Datum sqlvariantne(PG_FUNCTION_ARGS) { - bytea *arg1 = PG_GETARG_BYTEA_PP(0); - bytea *arg2 = PG_GETARG_BYTEA_PP(1); - uint8_t type_code1 = SV_GET_TYPCODE_PTR(arg1); - uint8_t type_code2 = SV_GET_TYPCODE_PTR(arg2); - uint8_t type_family1 = get_tsql_type_info(type_code1).family_prio; - uint8_t type_family2 = get_tsql_type_info(type_code2).family_prio; - char *oprname = "<>"; - Datum result; + bytea *arg1 = PG_GETARG_BYTEA_PP(0); + bytea *arg2 = PG_GETARG_BYTEA_PP(1); + uint8_t type_code1 = SV_GET_TYPCODE_PTR(arg1); + uint8_t type_code2 = SV_GET_TYPCODE_PTR(arg2); + uint8_t type_family1 = get_tsql_type_info(type_code1).family_prio; + uint8_t type_family2 = get_tsql_type_info(type_code2).family_prio; + char *oprname = "<>"; + Datum result; - if (type_family1 == type_family2) - result = do_compare(oprname, arg1, arg2, PG_GET_COLLATION()); - else /* based on type family precedence */ - result = BoolGetDatum(true); + if (type_family1 == type_family2) + result = do_compare(oprname, arg1, arg2, PG_GET_COLLATION()); + else /* based on type family precedence */ + result = BoolGetDatum(true); - /* Avoid leaking memory for toasted inputs */ - PG_FREE_IF_COPY(arg1, 0); - PG_FREE_IF_COPY(arg2, 1); + /* Avoid leaking memory for toasted inputs */ + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); - return result; + return result; } /* @@ -1693,58 +1707,59 @@ PG_FUNCTION_INFO_V1(sqlvariant_hash); Datum sqlvariant_cmp(PG_FUNCTION_ARGS) { - bytea *arg1 = PG_GETARG_BYTEA_PP(0); - bytea *arg2 = PG_GETARG_BYTEA_PP(1); - uint8_t type_code1 = SV_GET_TYPCODE_PTR(arg1); - uint8_t type_code2 = SV_GET_TYPCODE_PTR(arg2); - uint8_t type_family1 = get_tsql_type_info(type_code1).family_prio; - uint8_t type_family2 = get_tsql_type_info(type_code2).family_prio; - Datum result; - - if (type_family1 == type_family2) - { - char *opeq = "="; - char *oplt = "<"; - Datum is_eq; - Datum is_lt; - is_lt = do_compare(oplt, arg1, arg2, PG_GET_COLLATION()); - if (DatumGetBool(is_lt)) - result = Int32GetDatum(-1); - else - { - is_eq = do_compare(opeq, arg1, arg2, PG_GET_COLLATION()); - result = DatumGetBool(is_eq) ? Int32GetDatum(0) : Int32GetDatum(1); - } - } - else - result = (type_family1 > type_family2) ? Int32GetDatum(-1) : Int32GetDatum(1); - - /* Avoid leaking memory for toasted inputs */ - PG_FREE_IF_COPY(arg1, 0); - PG_FREE_IF_COPY(arg2, 1); - - return result; + bytea *arg1 = PG_GETARG_BYTEA_PP(0); + bytea *arg2 = PG_GETARG_BYTEA_PP(1); + uint8_t type_code1 = SV_GET_TYPCODE_PTR(arg1); + uint8_t type_code2 = SV_GET_TYPCODE_PTR(arg2); + uint8_t type_family1 = get_tsql_type_info(type_code1).family_prio; + uint8_t type_family2 = get_tsql_type_info(type_code2).family_prio; + Datum result; + + if (type_family1 == type_family2) + { + char *opeq = "="; + char *oplt = "<"; + Datum is_eq; + Datum is_lt; + + is_lt = do_compare(oplt, arg1, arg2, PG_GET_COLLATION()); + if (DatumGetBool(is_lt)) + result = Int32GetDatum(-1); + else + { + is_eq = do_compare(opeq, arg1, arg2, PG_GET_COLLATION()); + result = DatumGetBool(is_eq) ? Int32GetDatum(0) : Int32GetDatum(1); + } + } + else + result = (type_family1 > type_family2) ? Int32GetDatum(-1) : Int32GetDatum(1); + + /* Avoid leaking memory for toasted inputs */ + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); + + return result; } Datum sqlvariant_hash(PG_FUNCTION_ARGS) { - bytea *key = PG_GETARG_BYTEA_PP(0); - int keylen = VARSIZE_ANY_EXHDR(key); - int hdrlen = VARSIZE_ANY(key) - keylen; - Datum result; + bytea *key = PG_GETARG_BYTEA_PP(0); + int keylen = VARSIZE_ANY_EXHDR(key); + int hdrlen = VARSIZE_ANY(key) - keylen; + Datum result; - /* Exclude varlena header for computation - * Size of varlena header could be 1 or 4 bytes, - * Newly created values usually have 4 bytes - * However, values read from storage have 1 bytes if total length is short - */ - result = hash_any((unsigned char *) key + hdrlen, keylen); + /* + * Exclude varlena header for computation Size of varlena header could be + * 1 or 4 bytes, Newly created values usually have 4 bytes However, values + * read from storage have 1 bytes if total length is short + */ + result = hash_any((unsigned char *) key + hdrlen, keylen); - /* Avoid leaking memory for toasted inputs */ - PG_FREE_IF_COPY(key, 0); + /* Avoid leaking memory for toasted inputs */ + PG_FREE_IF_COPY(key, 0); - return result; + return result; } @@ -1757,16 +1772,16 @@ PG_FUNCTION_INFO_V1(datalength_sqlvariant); Datum datalength_sqlvariant(PG_FUNCTION_ARGS) { - bytea *sv = PG_GETARG_BYTEA_PP(0); - uint8_t type_code = SV_GET_TYPCODE_PTR(sv); - uint8_t svhdr_size = get_tsql_type_info(type_code).svhdr_size; - int32 octet_len = VARSIZE_ANY_EXHDR(sv) - svhdr_size; + bytea *sv = PG_GETARG_BYTEA_PP(0); + uint8_t type_code = SV_GET_TYPCODE_PTR(sv); + uint8_t svhdr_size = get_tsql_type_info(type_code).svhdr_size; + int32 octet_len = VARSIZE_ANY_EXHDR(sv) - svhdr_size; - /* For varlen types, exclude the original varlena header */ - if (IS_STRING_TYPE(type_code) || IS_BINARY_TYPE(type_code) || type_code == NUMERIC_T) - octet_len -= VARHDRSZ; + /* For varlen types, exclude the original varlena header */ + if (IS_STRING_TYPE(type_code) || IS_BINARY_TYPE(type_code) || type_code == NUMERIC_T) + octet_len -= VARHDRSZ; - PG_RETURN_INT32(octet_len); + PG_RETURN_INT32(octet_len); } /* @@ -1778,193 +1793,219 @@ datalength_sqlvariant(PG_FUNCTION_ARGS) */ void TdsGetPGbaseType(uint8 variantBaseType, int *pgBaseType, int tempLen, - int *dataLen, int *variantHeaderLen) + int *dataLen, int *variantHeaderLen) { switch (variantBaseType) { case VARIANT_TYPE_BIT: + /* - * dataformat: totalLen(4B) + metadata(2B)( baseType(1B) + metadatalen(1B) ) + - * data(dataLen) + * dataformat: totalLen(4B) + metadata(2B)( baseType(1B) + + * metadatalen(1B) ) + data(dataLen) */ *pgBaseType = BIT_T; *dataLen = tempLen - VARIANT_TYPE_METALEN_FOR_NUM_DATATYPES; break; case VARIANT_TYPE_TINYINT: + /* - * dataformat: totalLen(4B) + metadata(2B)( baseType(1B) + metadatalen(1B) ) + - * data(dataLen) + * dataformat: totalLen(4B) + metadata(2B)( baseType(1B) + + * metadatalen(1B) ) + data(dataLen) */ *pgBaseType = TINYINT_T; *dataLen = tempLen - VARIANT_TYPE_METALEN_FOR_NUM_DATATYPES; break; case VARIANT_TYPE_SMALLINT: + /* - * dataformat: totalLen(4B) + metadata(2B)( baseType(1B) + metadatalen(1B) ) + - * data(dataLen) + * dataformat: totalLen(4B) + metadata(2B)( baseType(1B) + + * metadatalen(1B) ) + data(dataLen) */ *pgBaseType = SMALLINT_T; *dataLen = tempLen - VARIANT_TYPE_METALEN_FOR_NUM_DATATYPES; break; case VARIANT_TYPE_INT: + /* - * dataformat: totalLen(4B) + metadata(2B)( baseType(1B) + metadatalen(1B) ) + - * data(dataLen) + * dataformat: totalLen(4B) + metadata(2B)( baseType(1B) + + * metadatalen(1B) ) + data(dataLen) */ *pgBaseType = INT_T; *dataLen = tempLen - VARIANT_TYPE_METALEN_FOR_NUM_DATATYPES; break; case VARIANT_TYPE_BIGINT: + /* - * dataformat: totalLen(4B) + metadata(2B)( baseType(1B) + metadatalen(1B) ) + - * data(dataLen) + * dataformat: totalLen(4B) + metadata(2B)( baseType(1B) + + * metadatalen(1B) ) + data(dataLen) */ *pgBaseType = BIGINT_T; *dataLen = tempLen - VARIANT_TYPE_METALEN_FOR_NUM_DATATYPES; break; case VARIANT_TYPE_REAL: + /* - * dataformat: totalLen(4B) + metadata(2B)( baseType(1B) + metadatalen(1B) ) + - * data(dataLen) + * dataformat: totalLen(4B) + metadata(2B)( baseType(1B) + + * metadatalen(1B) ) + data(dataLen) */ *pgBaseType = REAL_T; *dataLen = tempLen - VARIANT_TYPE_METALEN_FOR_NUM_DATATYPES; break; case VARIANT_TYPE_FLOAT: + /* - * dataformat: totalLen(4B) + metadata(2B)( baseType(1B) + metadatalen(1B) ) + - * data(dataLen) + * dataformat: totalLen(4B) + metadata(2B)( baseType(1B) + + * metadatalen(1B) ) + data(dataLen) */ *pgBaseType = FLOAT_T; *dataLen = tempLen - VARIANT_TYPE_METALEN_FOR_NUM_DATATYPES; break; case VARIANT_TYPE_CHAR: + /* - * dataformat: totalLen(4B) + metadata(9B)( baseType(1B) + metadatalen(1B) + - * encodingLen(5B) + dataLen(2B) ) + data(dataLen) + * dataformat: totalLen(4B) + metadata(9B)( baseType(1B) + + * metadatalen(1B) + encodingLen(5B) + dataLen(2B) ) + + * data(dataLen) */ *pgBaseType = CHAR_T; *dataLen = tempLen - VARIANT_TYPE_METALEN_FOR_CHAR_DATATYPES; break; case VARIANT_TYPE_NCHAR: *pgBaseType = NCHAR_T; + /* - * dataformat: totalLen(4B) + metadata(9B)( baseType(1B) + metadatalen(1B) + - * encodingLen(5B) + dataLen(2B) ) + data(dataLen) - * Data is in UTF16 format. + * dataformat: totalLen(4B) + metadata(9B)( baseType(1B) + + * metadatalen(1B) + encodingLen(5B) + dataLen(2B) ) + + * data(dataLen) Data is in UTF16 format. */ *dataLen = (tempLen - VARIANT_TYPE_METALEN_FOR_CHAR_DATATYPES) / 2; break; case VARIANT_TYPE_VARCHAR: + /* - * dataformat: totalLen(4B) + metadata(9B)( baseType(1B) + metadatalen(1B) + - * encodingLen(5B) + dataLen(2B) ) + data(dataLen) + * dataformat: totalLen(4B) + metadata(9B)( baseType(1B) + + * metadatalen(1B) + encodingLen(5B) + dataLen(2B) ) + + * data(dataLen) */ *pgBaseType = VARCHAR_T; *dataLen = tempLen - VARIANT_TYPE_METALEN_FOR_CHAR_DATATYPES; break; case VARIANT_TYPE_NVARCHAR: *pgBaseType = NVARCHAR_T; + /* - * dataformat: totalLen(4B) + metadata(9B)( baseType(1B) + metadatalen(1B) + - * encodingLen(5B) + dataLen(2B) ) + data(dataLen) - * Data is in UTF16 format. + * dataformat: totalLen(4B) + metadata(9B)( baseType(1B) + + * metadatalen(1B) + encodingLen(5B) + dataLen(2B) ) + + * data(dataLen) Data is in UTF16 format. */ *dataLen = (tempLen - VARIANT_TYPE_METALEN_FOR_CHAR_DATATYPES) / 2; break; case VARIANT_TYPE_BINARY: + /* - * dataformat : totalLen(4B) + metadata(4B)( baseType(1B) + metadatalen(1B) + - * dataLen(2B) ) + data(dataLen) + * dataformat : totalLen(4B) + metadata(4B)( baseType(1B) + + * metadatalen(1B) + dataLen(2B) ) + data(dataLen) */ *pgBaseType = BINARY_T; *dataLen = tempLen - VARIANT_TYPE_METALEN_FOR_BIN_DATATYPES; break; case VARIANT_TYPE_VARBINARY: + /* - * dataformat : totalLen(4B) + metadata(4B)( baseType(1B) + metadatalen(1B) + - * dataLen(2B) ) + data(dataLen) + * dataformat : totalLen(4B) + metadata(4B)( baseType(1B) + + * metadatalen(1B) + dataLen(2B) ) + data(dataLen) */ *pgBaseType = VARBINARY_T; *dataLen = tempLen - VARIANT_TYPE_METALEN_FOR_BIN_DATATYPES; break; case VARIANT_TYPE_DATE: + /* - * dataformat : totalLen(4B) + metadata(2B)( baseType(1B) + metadatalen(1B) ) + - * data(3B) + * dataformat : totalLen(4B) + metadata(2B)( baseType(1B) + + * metadatalen(1B) ) + data(3B) */ *pgBaseType = DATE_T; *dataLen = tempLen - VARIANT_TYPE_METALEN_FOR_DATE; break; case VARIANT_TYPE_TIME: + /* - * dataformat : totalLen(4B) + metadata(3B)( baseType(1B) + metadatalen(1B) + - * scale(1B) ) + data(3B-5B) + * dataformat : totalLen(4B) + metadata(3B)( baseType(1B) + + * metadatalen(1B) + scale(1B) ) + data(3B-5B) */ *pgBaseType = TIME_T; *dataLen = tempLen - VARIANT_TYPE_METALEN_FOR_TIME; break; case VARIANT_TYPE_SMALLDATETIME: + /* - * dataformat : totalLen(4B) + metadata(2B)( baseType(1B) + metadatalen(1B) ) + - * data(4B) + * dataformat : totalLen(4B) + metadata(2B)( baseType(1B) + + * metadatalen(1B) ) + data(4B) */ *pgBaseType = SMALLDATETIME_T; *dataLen = tempLen - VARIANT_TYPE_METALEN_FOR_SMALLDATETIME; break; case VARIANT_TYPE_DATETIME: + /* - * dataformat : totalLen(4B) + metadata(2B)( baseType(1B) + metadatalen(1B) ) + - * data(8B) + * dataformat : totalLen(4B) + metadata(2B)( baseType(1B) + + * metadatalen(1B) ) + data(8B) */ *pgBaseType = DATETIME_T; *dataLen = tempLen - VARIANT_TYPE_METALEN_FOR_DATETIME; break; case VARIANT_TYPE_DATETIME2: + /* - * dataformat : totalLen(4B) + metadata(3B)( baseType(1B) + metadatalen(1B) + - * scale(1B) ) + data(6B-8B) + * dataformat : totalLen(4B) + metadata(3B)( baseType(1B) + + * metadatalen(1B) + scale(1B) ) + data(6B-8B) */ *pgBaseType = DATETIME2_T; *dataLen = tempLen - VARIANT_TYPE_METALEN_FOR_DATETIME2; break; case VARIANT_TYPE_UNIQUEIDENTIFIER: + /* - * dataformat: totalLen(4B) + metadata(2B)( baseType(1B) + metadatalen(1B) ) + - * data(dataLen) + * dataformat: totalLen(4B) + metadata(2B)( baseType(1B) + + * metadatalen(1B) ) + data(dataLen) */ *pgBaseType = UNIQUEIDENTIFIER_T; *dataLen = tempLen - VARIANT_TYPE_METALEN_FOR_NUM_DATATYPES; break; case VARIANT_TYPE_NUMERIC: case VARIANT_TYPE_DECIMAL: + /* - * dataformat : totalLen(4B) + metdata(5B)( baseType(1B) + metadatalen(1B) + - * precision(1B) + scale(1B) + sign(1B) ) + data(dataLen) + * dataformat : totalLen(4B) + metdata(5B)( baseType(1B) + + * metadatalen(1B) + precision(1B) + scale(1B) + sign(1B) ) + + * data(dataLen) */ *pgBaseType = NUMERIC_T; *dataLen = tempLen - VARIANT_TYPE_METALEN_FOR_NUMERIC_DATATYPES; break; case VARIANT_TYPE_MONEY: + /* - * dataformat: totalLen(4B) + metadata(2B)( baseType(1B) + metadatalen(1B) ) + - * data(dataLen) + * dataformat: totalLen(4B) + metadata(2B)( baseType(1B) + + * metadatalen(1B) ) + data(dataLen) */ *pgBaseType = MONEY_T; *dataLen = tempLen - VARIANT_TYPE_METALEN_FOR_NUM_DATATYPES; break; case VARIANT_TYPE_SMALLMONEY: + /* - * dataformat: totalLen(4B) + metadata(2B)( baseType(1B) + metadatalen(1B) ) + - * data(dataLen) + * dataformat: totalLen(4B) + metadata(2B)( baseType(1B) + + * metadatalen(1B) ) + data(dataLen) */ *pgBaseType = SMALLMONEY_T; *dataLen = tempLen - VARIANT_TYPE_METALEN_FOR_NUM_DATATYPES; break; case VARIANT_TYPE_DATETIMEOFFSET: + /* - * dataformat : totalLen(4B) + metadata(3B)(baseType(1B) + metadatalen(1B) + - * scale(1B)) + data(8B-10B) + * dataformat : totalLen(4B) + metadata(3B)(baseType(1B) + + * metadatalen(1B) + scale(1B)) + data(8B-10B) */ *pgBaseType = DATETIMEOFFSET_T; *dataLen = tempLen - VARIANT_TYPE_METALEN_FOR_DATETIMEOFFSET; @@ -1983,13 +2024,14 @@ TdsGetPGbaseType(uint8 variantBaseType, int *pgBaseType, int tempLen, */ void TdsSetMetaData(bytea *result, int pgBaseType, int scale, - int precision, int maxLen) + int precision, int maxLen) { if (pgBaseType == TIME_T || pgBaseType == DATETIME2_T || - pgBaseType == DATETIMEOFFSET_T) + pgBaseType == DATETIMEOFFSET_T) { /* For datatypes having sql_variant specific header of length 2 bytes */ svhdr_2B_t *svhdr2; + svhdr2 = SV_HDR_2B(result); SV_SET_METADATA(svhdr2, pgBaseType, HDR_VER); svhdr2->typmod = scale; @@ -1998,24 +2040,27 @@ TdsSetMetaData(bytea *result, int pgBaseType, int scale, { /* For datatypes having sql_variant specific header of length 3 bytes */ svhdr_3B_t *svhdr3; + svhdr3 = SV_HDR_3B(result); SV_SET_METADATA(svhdr3, pgBaseType, HDR_VER); svhdr3->typmod = (precision << 8) | scale; } else if (pgBaseType == BINARY_T || pgBaseType == VARBINARY_T || - pgBaseType == CHAR_T || pgBaseType == NCHAR_T || - pgBaseType == VARCHAR_T || pgBaseType == NVARCHAR_T) + pgBaseType == CHAR_T || pgBaseType == NCHAR_T || + pgBaseType == VARCHAR_T || pgBaseType == NVARCHAR_T) { /* For datatypes having sql_variant specific header of length 5 bytes */ svhdr_5B_t *svhdr5; + svhdr5 = SV_HDR_5B(result); SV_SET_METADATA(svhdr5, pgBaseType, HDR_VER); - svhdr5->typmod = (int16)maxLen; + svhdr5->typmod = (int16) maxLen; } else { /* For all other fixed-length datatypes */ svhdr_2B_t *svhdr2; + svhdr2 = SV_HDR_2B(result); SV_SET_METADATA(svhdr2, pgBaseType, HDR_VER); } @@ -2024,172 +2069,176 @@ TdsSetMetaData(bytea *result, int pgBaseType, int scale, int TdsPGbaseType(bytea *vlena) { - /* - * First sql variant header byte contains: - * type code ( 5bit ) + MD ver (3bit) - */ - return SV_GET_TYPCODE_PTR(vlena); + /* + * First sql variant header byte contains: type code ( 5bit ) + MD ver + * (3bit) + */ + return SV_GET_TYPCODE_PTR(vlena); } void TdsGetMetaData(bytea *result, int pgBaseType, int *scale, - int *precision, int *maxLen) -{ - svhdr_5B_t *svhdr; - svhdr = SV_HDR_5B(result); - - if (pgBaseType == TIME_T || pgBaseType == DATETIME2_T || - pgBaseType == DATETIMEOFFSET_T) - { - *scale = svhdr->typmod; - } - else if (pgBaseType == NUMERIC_T) - { - *scale = svhdr->typmod & 0x00ff; - *precision = (svhdr->typmod & 0xff00) >> 8; - } - else if (pgBaseType == BINARY_T || pgBaseType == VARBINARY_T || - pgBaseType == CHAR_T || pgBaseType == NCHAR_T || - pgBaseType == VARCHAR_T || pgBaseType == NVARCHAR_T) - { - *maxLen = (int)svhdr->typmod; - } + int *precision, int *maxLen) +{ + svhdr_5B_t *svhdr; + + svhdr = SV_HDR_5B(result); + + if (pgBaseType == TIME_T || pgBaseType == DATETIME2_T || + pgBaseType == DATETIMEOFFSET_T) + { + *scale = svhdr->typmod; + } + else if (pgBaseType == NUMERIC_T) + { + *scale = svhdr->typmod & 0x00ff; + *precision = (svhdr->typmod & 0xff00) >> 8; + } + else if (pgBaseType == BINARY_T || pgBaseType == VARBINARY_T || + pgBaseType == CHAR_T || pgBaseType == NCHAR_T || + pgBaseType == VARCHAR_T || pgBaseType == NVARCHAR_T) + { + *maxLen = (int) svhdr->typmod; + } } void TdsGetVariantBaseType(int pgBaseType, int *variantBaseType, - bool *isBaseNum, bool *isBaseChar, - bool *isBaseDec, bool *isBaseBin, - bool *isBaseDate, int *variantHeaderLen) -{ - switch (pgBaseType) - { - case BIT_T: - *variantBaseType = VARIANT_TYPE_BIT; - *isBaseNum = true; - break; - case BIGINT_T: - *variantBaseType = VARIANT_TYPE_BIGINT; - *isBaseNum = true; - break; - case INT_T: - *variantBaseType = VARIANT_TYPE_INT; - *isBaseNum = true; - break; - case SMALLINT_T: - *variantBaseType = VARIANT_TYPE_SMALLINT; - *isBaseNum = true; - break; - case TINYINT_T: - *variantBaseType = VARIANT_TYPE_TINYINT; - *isBaseNum = true; - break; - case REAL_T: - *variantBaseType = VARIANT_TYPE_REAL; - *isBaseNum = true; - break; - case FLOAT_T: - *variantBaseType = VARIANT_TYPE_FLOAT; - *isBaseNum = true; - break; - case MONEY_T: - *variantBaseType = VARIANT_TYPE_MONEY; - *isBaseNum = true; - break; - case SMALLMONEY_T: - *variantBaseType = VARIANT_TYPE_SMALLMONEY; - *isBaseNum = true; - break; - case DATE_T: - *variantBaseType = VARIANT_TYPE_DATE; - *isBaseDate = true; - break; - case SMALLDATETIME_T: - *variantBaseType = VARIANT_TYPE_SMALLDATETIME; - *isBaseDate = true; - break; - case DATETIME_T: - *variantBaseType = VARIANT_TYPE_DATETIME; - *isBaseDate = true; - break; - case TIME_T: - *variantBaseType = VARIANT_TYPE_TIME; - *isBaseDate = true; - break; - case DATETIME2_T: - *variantBaseType = VARIANT_TYPE_DATETIME2; - *isBaseDate = true; - break; - case DATETIMEOFFSET_T: - *variantBaseType = VARIANT_TYPE_DATETIMEOFFSET; - *isBaseDate = true; - break; - case CHAR_T: - *variantBaseType = VARIANT_TYPE_CHAR; - *isBaseChar = true; - break; - case VARCHAR_T: - *variantBaseType = VARIANT_TYPE_VARCHAR; - *isBaseChar = true; - break; - case NCHAR_T: - *variantBaseType = VARIANT_TYPE_NCHAR; - *isBaseChar = true; - break; - case NVARCHAR_T: - *variantBaseType = VARIANT_TYPE_NVARCHAR; - *isBaseChar = true; - break; - case BINARY_T: - *variantBaseType = VARIANT_TYPE_BINARY; - *isBaseBin = true; - break; - case VARBINARY_T: - *variantBaseType = VARIANT_TYPE_VARBINARY; - *isBaseBin = true; - break; - case UNIQUEIDENTIFIER_T: - *variantBaseType = VARIANT_TYPE_UNIQUEIDENTIFIER; - *isBaseNum = true; - break; - case NUMERIC_T: - *variantBaseType = VARIANT_TYPE_NUMERIC; - *isBaseDec = true; - break; - default: - elog(ERROR, "%d: datatype not supported in TDS sender", pgBaseType); - break; - } - - *variantHeaderLen = get_tsql_type_info(pgBaseType).svhdr_size; -} - -bytea *convertIntToSQLVariantByteA(int ret) { - Datum data = Int64GetDatum(ret); - bytea *result = gen_sqlvariant_bytea_from_type_datum(INT_T, data); - svhdr_1B_t *svhdr; + bool *isBaseNum, bool *isBaseChar, + bool *isBaseDec, bool *isBaseBin, + bool *isBaseDate, int *variantHeaderLen) +{ + switch (pgBaseType) + { + case BIT_T: + *variantBaseType = VARIANT_TYPE_BIT; + *isBaseNum = true; + break; + case BIGINT_T: + *variantBaseType = VARIANT_TYPE_BIGINT; + *isBaseNum = true; + break; + case INT_T: + *variantBaseType = VARIANT_TYPE_INT; + *isBaseNum = true; + break; + case SMALLINT_T: + *variantBaseType = VARIANT_TYPE_SMALLINT; + *isBaseNum = true; + break; + case TINYINT_T: + *variantBaseType = VARIANT_TYPE_TINYINT; + *isBaseNum = true; + break; + case REAL_T: + *variantBaseType = VARIANT_TYPE_REAL; + *isBaseNum = true; + break; + case FLOAT_T: + *variantBaseType = VARIANT_TYPE_FLOAT; + *isBaseNum = true; + break; + case MONEY_T: + *variantBaseType = VARIANT_TYPE_MONEY; + *isBaseNum = true; + break; + case SMALLMONEY_T: + *variantBaseType = VARIANT_TYPE_SMALLMONEY; + *isBaseNum = true; + break; + case DATE_T: + *variantBaseType = VARIANT_TYPE_DATE; + *isBaseDate = true; + break; + case SMALLDATETIME_T: + *variantBaseType = VARIANT_TYPE_SMALLDATETIME; + *isBaseDate = true; + break; + case DATETIME_T: + *variantBaseType = VARIANT_TYPE_DATETIME; + *isBaseDate = true; + break; + case TIME_T: + *variantBaseType = VARIANT_TYPE_TIME; + *isBaseDate = true; + break; + case DATETIME2_T: + *variantBaseType = VARIANT_TYPE_DATETIME2; + *isBaseDate = true; + break; + case DATETIMEOFFSET_T: + *variantBaseType = VARIANT_TYPE_DATETIMEOFFSET; + *isBaseDate = true; + break; + case CHAR_T: + *variantBaseType = VARIANT_TYPE_CHAR; + *isBaseChar = true; + break; + case VARCHAR_T: + *variantBaseType = VARIANT_TYPE_VARCHAR; + *isBaseChar = true; + break; + case NCHAR_T: + *variantBaseType = VARIANT_TYPE_NCHAR; + *isBaseChar = true; + break; + case NVARCHAR_T: + *variantBaseType = VARIANT_TYPE_NVARCHAR; + *isBaseChar = true; + break; + case BINARY_T: + *variantBaseType = VARIANT_TYPE_BINARY; + *isBaseBin = true; + break; + case VARBINARY_T: + *variantBaseType = VARIANT_TYPE_VARBINARY; + *isBaseBin = true; + break; + case UNIQUEIDENTIFIER_T: + *variantBaseType = VARIANT_TYPE_UNIQUEIDENTIFIER; + *isBaseNum = true; + break; + case NUMERIC_T: + *variantBaseType = VARIANT_TYPE_NUMERIC; + *isBaseDec = true; + break; + default: + elog(ERROR, "%d: datatype not supported in TDS sender", pgBaseType); + break; + } + + *variantHeaderLen = get_tsql_type_info(pgBaseType).svhdr_size; +} + +bytea * +convertIntToSQLVariantByteA(int ret) +{ + Datum data = Int64GetDatum(ret); + bytea *result = gen_sqlvariant_bytea_from_type_datum(INT_T, data); + svhdr_1B_t *svhdr; INSTR_METRIC_INC(INSTR_TSQL_INT_SQLVARIANT); /* Type Specific Header */ - svhdr = SV_HDR_1B(result); - SV_SET_METADATA(svhdr, INT_T, HDR_VER); + svhdr = SV_HDR_1B(result); + SV_SET_METADATA(svhdr, INT_T, HDR_VER); return result; } -bytea *convertVarcharToSQLVariantByteA(VarChar *vch, Oid coll) { - bytea *result = gen_sqlvariant_bytea_from_type_datum(NVARCHAR_T, PointerGetDatum(vch)); - svhdr_5B_t *svhdr; +bytea * +convertVarcharToSQLVariantByteA(VarChar *vch, Oid coll) +{ + bytea *result = gen_sqlvariant_bytea_from_type_datum(NVARCHAR_T, PointerGetDatum(vch)); + svhdr_5B_t *svhdr; INSTR_METRIC_INC(INSTR_TSQL_NVARCHAR_SQLVARIANT); /* Type Specific Header */ - svhdr = SV_HDR_5B(result); - SV_SET_METADATA(svhdr, NVARCHAR_T, HDR_VER); - svhdr->typmod = VARSIZE_ANY_EXHDR(vch); - svhdr->collid = get_persist_collation_id(coll); + svhdr = SV_HDR_5B(result); + SV_SET_METADATA(svhdr, NVARCHAR_T, HDR_VER); + svhdr->typmod = VARSIZE_ANY_EXHDR(vch); + svhdr->collid = get_persist_collation_id(coll); - return result; + return result; } - diff --git a/contrib/babelfishpg_common/src/sqlvariant.h b/contrib/babelfishpg_common/src/sqlvariant.h index 5a905ea219..55f316add4 100644 --- a/contrib/babelfishpg_common/src/sqlvariant.h +++ b/contrib/babelfishpg_common/src/sqlvariant.h @@ -33,7 +33,10 @@ /* * macros to store length of metadata (including metadata for base type) for sqlvariant datatypes. */ -#define VARIANT_TYPE_METALEN_FOR_NUM_DATATYPES 2 /* for BIT, TINYINT, SMALLINT, INT, BIGINT, REAL, FLOAT, [SMALL]MONEY and UID */ +#define VARIANT_TYPE_METALEN_FOR_NUM_DATATYPES 2 /* for BIT, TINYINT, + * SMALLINT, INT, BIGINT, + * REAL, FLOAT, + * [SMALL]MONEY and UID */ #define VARIANT_TYPE_METALEN_FOR_CHAR_DATATYPES 9 /* for [N][VAR]CHAR */ #define VARIANT_TYPE_METALEN_FOR_BIN_DATATYPES 4 /* for [VAR]BINARY */ #define VARIANT_TYPE_METALEN_FOR_NUMERIC_DATATYPES 5 /* for NUMERIC */ @@ -85,28 +88,28 @@ * for decimal types, precision and scale are encoded * for datetime2, datetimeoffset it is scale */ -typedef struct __attribute__((packed)) svhdr_1B +typedef struct __attribute__ ((packed)) svhdr_1B { - uint8_t metadata; + uint8_t metadata; } svhdr_1B_t; -typedef struct __attribute__((packed)) svhdr_2B +typedef struct __attribute__ ((packed)) svhdr_2B { - uint8_t metadata; - int8_t typmod; + uint8_t metadata; + int8_t typmod; } svhdr_2B_t; -typedef struct __attribute__((packed)) svhdr_3B +typedef struct __attribute__ ((packed)) svhdr_3B { - uint8_t metadata; - int16_t typmod; + uint8_t metadata; + int16_t typmod; } svhdr_3B_t; -typedef struct __attribute__((packed)) svhdr_5B +typedef struct __attribute__ ((packed)) svhdr_5B { - uint8_t metadata; - int16_t typmod; - uint16_t collid; + uint8_t metadata; + int16_t typmod; + uint16_t collid; } svhdr_5B_t; extern bytea *gen_sqlvariant_bytea_from_type_datum(size_t typcode, Datum data); @@ -115,15 +118,14 @@ extern bytea *convertIntToSQLVariantByteA(int ret); extern Datum datetime2sqlvariant(PG_FUNCTION_ARGS); extern Datum tinyint2sqlvariant(PG_FUNCTION_ARGS); extern void TdsGetPGbaseType(uint8 variantBaseType, int *pgBaseType, int tempLen, - int *dataLen, int *variantHeaderLen); + int *dataLen, int *variantHeaderLen); extern void TdsSetMetaData(bytea *result, int pgBaseType, int scale, - int precision, int maxLen); -extern int TdsPGbaseType(bytea *vlena); + int precision, int maxLen); +extern int TdsPGbaseType(bytea *vlena); extern void TdsGetMetaData(bytea *result, int pgBaseType, int *scale, - int *precision, int *maxLen); + int *precision, int *maxLen); extern void TdsGetVariantBaseType(int pgBaseType, int *variantBaseType, - bool *isBaseNum, bool *isBaseChar, - bool *isBaseDec, bool *isBaseBin, - bool *isBaseDate, int *variantHeaderLen); - -#endif \ No newline at end of file + bool *isBaseNum, bool *isBaseChar, + bool *isBaseDec, bool *isBaseBin, + bool *isBaseDate, int *variantHeaderLen); +#endif diff --git a/contrib/babelfishpg_common/src/typecode.c b/contrib/babelfishpg_common/src/typecode.c index b3addc42d7..121b03abcf 100644 --- a/contrib/babelfishpg_common/src/typecode.c +++ b/contrib/babelfishpg_common/src/typecode.c @@ -19,43 +19,43 @@ MemoryContext TransMemoryContext = NULL; type_info_t type_infos[TOTAL_TYPECODE_COUNT] = { - {0, 1, "sql_variant" , "sql_variant" , 1, 1, 1}, - {0, 1, "datetimeoffset" , "datetimeoffset" , 2, 2, 2}, - {0, 1, "datetime2" , "datetime2" , 2, 3, 2}, - {0, 1, "datetime" , "datetime" , 2, 4, 1}, - {0, 1, "smalldatetime" , "smalldatetime" , 2, 5, 1}, - {0, 0, "date" , "date" , 2, 6, 1}, - {0, 0, "time" , "time" , 2, 7, 2}, - {0, 0, "float8" , "float" , 3, 8, 1}, - {0, 0, "float4" , "real" , 3, 9, 1}, - {0, 0, "numeric" , "numeric" , 4, 10, 3}, - {0, 1, "money" , "money" , 4, 11, 1}, - {0, 1, "smallmoney" , "smallmoney" , 4, 12, 1}, - {0, 0, "int8" , "bigint" , 4, 13, 1}, - {0, 0, "int4" , "int" , 4, 14, 1}, - {0, 0, "int2" , "smallint" , 4, 15, 1}, - {0, 1, "tinyint" , "tinyint" , 4, 16, 1}, - {0, 1, "bit" , "bit" , 4, 17, 1}, - {0, 1, "nvarchar" , "nvarchar" , 5, 18, 5}, - {0, 1, "nchar" , "nchar" , 5, 19, 5}, - {0, 1, "varchar" , "varchar" , 5, 20, 5}, - {0, 1, "bpchar" , "char" , 5, 21, 5}, - {0, 1, "varbinary" , "varbinary" , 6, 22, 3}, - {0, 1, "binary" , "binary" , 6, 23, 3}, - {0, 1, "uniqueidentifier", "uniqueidentifier", 7, 24, 1}, - {0, 0, "text" , "text" , 5, 25, 5}, - {0, 1, "ntext" , "ntext" , 5, 26, 5}, - {0, 1, "image" , "image" , 5, 27, 5}, - {0, 0, "xml" , "xml" , 5, 28, 5}, - {0, 0, "bpchar" , "char" , 5, 29, 5}, - {0, 1, "decimal" , "decimal" , 5, 30, 5}, - {0, 1, "sysname" , "sysname" , 5, 31, 5}, - {0, 1, "rowversion" , "timestamp" , 8, 32, 3}, - {0, 1, "timestamp" , "timestamp" , 8, 33, 3} + {0, 1, "sql_variant", "sql_variant", 1, 1, 1}, + {0, 1, "datetimeoffset", "datetimeoffset", 2, 2, 2}, + {0, 1, "datetime2", "datetime2", 2, 3, 2}, + {0, 1, "datetime", "datetime", 2, 4, 1}, + {0, 1, "smalldatetime", "smalldatetime", 2, 5, 1}, + {0, 0, "date", "date", 2, 6, 1}, + {0, 0, "time", "time", 2, 7, 2}, + {0, 0, "float8", "float", 3, 8, 1}, + {0, 0, "float4", "real", 3, 9, 1}, + {0, 0, "numeric", "numeric", 4, 10, 3}, + {0, 1, "money", "money", 4, 11, 1}, + {0, 1, "smallmoney", "smallmoney", 4, 12, 1}, + {0, 0, "int8", "bigint", 4, 13, 1}, + {0, 0, "int4", "int", 4, 14, 1}, + {0, 0, "int2", "smallint", 4, 15, 1}, + {0, 1, "tinyint", "tinyint", 4, 16, 1}, + {0, 1, "bit", "bit", 4, 17, 1}, + {0, 1, "nvarchar", "nvarchar", 5, 18, 5}, + {0, 1, "nchar", "nchar", 5, 19, 5}, + {0, 1, "varchar", "varchar", 5, 20, 5}, + {0, 1, "bpchar", "char", 5, 21, 5}, + {0, 1, "varbinary", "varbinary", 6, 22, 3}, + {0, 1, "binary", "binary", 6, 23, 3}, + {0, 1, "uniqueidentifier", "uniqueidentifier", 7, 24, 1}, + {0, 0, "text", "text", 5, 25, 5}, + {0, 1, "ntext", "ntext", 5, 26, 5}, + {0, 1, "image", "image", 5, 27, 5}, + {0, 0, "xml", "xml", 5, 28, 5}, + {0, 0, "bpchar", "char", 5, 29, 5}, + {0, 1, "decimal", "decimal", 5, 30, 5}, + {0, 1, "sysname", "sysname", 5, 31, 5}, + {0, 1, "rowversion", "timestamp", 8, 32, 3}, + {0, 1, "timestamp", "timestamp", 8, 33, 3} }; /* Hash tables to help backward searching (from OID to Persist ID) */ -HTAB *ht_oid2typecode = NULL; +HTAB *ht_oid2typecode = NULL; static bool inited_ht_oid2typecode = false; /* @@ -74,71 +74,72 @@ PG_FUNCTION_INFO_V1(init_tcode_trans_tab); Datum init_tcode_trans_tab(PG_FUNCTION_ARGS) { - HASHCTL hashCtl; - Oid sys_nspoid; - Oid nspoid; - ht_oid2typecode_entry_t *entry; - - if (TransMemoryContext == NULL) /* initialize memory context */ - { - TransMemoryContext = - AllocSetContextCreateInternal(NULL, - "SQL Variant Memory Context", - ALLOCSET_DEFAULT_SIZES); - } - - if (ht_oid2typecode == NULL) /* create hash table */ - { - MemSet(&hashCtl, 0, sizeof(hashCtl)); - hashCtl.keysize = sizeof(Oid); - hashCtl.entrysize = sizeof(ht_oid2typecode_entry_t); - hashCtl.hcxt = TransMemoryContext; - ht_oid2typecode = hash_create("OID to Persist Type Code Mapping", - TOTAL_TYPECODE_COUNT, - &hashCtl, - HASH_ELEM | HASH_CONTEXT | HASH_BLOBS); - } - - sys_nspoid = get_namespace_oid("sys", true); - - if (!OidIsValid(sys_nspoid)) - PG_RETURN_INT32(0); + HASHCTL hashCtl; + Oid sys_nspoid; + Oid nspoid; + ht_oid2typecode_entry_t *entry; + + if (TransMemoryContext == NULL) /* initialize memory context */ + { + TransMemoryContext = + AllocSetContextCreateInternal(NULL, + "SQL Variant Memory Context", + ALLOCSET_DEFAULT_SIZES); + } + + if (ht_oid2typecode == NULL) /* create hash table */ + { + MemSet(&hashCtl, 0, sizeof(hashCtl)); + hashCtl.keysize = sizeof(Oid); + hashCtl.entrysize = sizeof(ht_oid2typecode_entry_t); + hashCtl.hcxt = TransMemoryContext; + ht_oid2typecode = hash_create("OID to Persist Type Code Mapping", + TOTAL_TYPECODE_COUNT, + &hashCtl, + HASH_ELEM | HASH_CONTEXT | HASH_BLOBS); + } - /* mark the hash table initialised */ - inited_ht_oid2typecode = true; - - /* retrieve oid and setup hashtable*/ - for (int i=0; ipersist_id = i; - } - else - { - /* type is not loaded. wait for next scan */ - inited_ht_oid2typecode = false; - } - } - - PG_RETURN_INT32(0); + sys_nspoid = get_namespace_oid("sys", true); + + if (!OidIsValid(sys_nspoid)) + PG_RETURN_INT32(0); + + /* mark the hash table initialised */ + inited_ht_oid2typecode = true; + + /* retrieve oid and setup hashtable */ + for (int i = 0; i < TOTAL_TYPECODE_COUNT; i++) + { + nspoid = type_infos[i].nsp_is_sys ? sys_nspoid : PG_CATALOG_NAMESPACE; + type_infos[i].oid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, + CStringGetDatum(type_infos[i].pg_typname), ObjectIdGetDatum(nspoid)); + if (OidIsValid(type_infos[i].oid)) + { + entry = hash_search(ht_oid2typecode, &type_infos[i].oid, HASH_ENTER, NULL); + entry->persist_id = i; + } + else + { + /* type is not loaded. wait for next scan */ + inited_ht_oid2typecode = false; + } + } + + PG_RETURN_INT32(0); } type_info_t get_tsql_type_info(uint8_t type_code) { - /* Initialise T-SQL type info hash table if not already done */ + /* Initialise T-SQL type info hash table if not already done */ if (!inited_ht_oid2typecode) { - FunctionCallInfo fcinfo = NULL; /* empty interface */ + FunctionCallInfo fcinfo = NULL; /* empty interface */ + init_tcode_trans_tab(fcinfo); } - return type_infos[type_code]; + return type_infos[type_code]; } PG_FUNCTION_INFO_V1(typecode_list); @@ -146,80 +147,80 @@ PG_FUNCTION_INFO_V1(typecode_list); Datum typecode_list(PG_FUNCTION_ARGS) { - ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; - Tuplestorestate *tupstore; - MemoryContext per_query_ctx; - MemoryContext oldcontext; - - /* check to see if caller supports us returning a tuplestore */ - if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("set-valued function called in context that cannot accept a set"))); - if (!(rsinfo->allowedModes & SFRM_Materialize)) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("materialize mode required, but it is not " \ - "allowed in this context"))); - - /* need to build tuplestore in query context */ - per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; - oldcontext = MemoryContextSwitchTo(per_query_ctx); - - /* - * build tupdesc for result tuples. - */ - tupdesc = CreateTemplateTupleDesc(7); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "oid", - INT4OID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "pg_namespace", - TEXTOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 3, "pg_typname", - TEXTOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 4, "tsql_typname", - TEXTOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 5, "type_family_priority", - INT2OID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 6, "priority", - INT2OID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 7, "sql_variant_hdr_size", - INT2OID, -1, 0); - - tupstore = - tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random, - false, 1024); - /* generate junk in short-term context */ - MemoryContextSwitchTo(oldcontext); - - /* scan all the variables in top estate */ - for (int i = 0; i < TOTAL_TYPECODE_COUNT; i++) - { - type_info_t *info = &type_infos[i]; - Datum values[7]; - bool nulls[7]; - - MemSet(nulls, 0, sizeof(nulls)); - - values[0] = info->oid; - values[1] = info->nsp_is_sys ? CStringGetTextDatum("sys") : CStringGetTextDatum("pg_catalog"); - values[2] = CStringGetTextDatum(info->pg_typname); - values[3] = CStringGetTextDatum(info->tsql_typname); - values[4] = info->family_prio; - values[5] = info->prio; - values[6] = info->svhdr_size; - - tuplestore_putvalues(tupstore, tupdesc, values, nulls); - } - - /* clean up and return the tuplestore */ - tuplestore_donestoring(tupstore); - - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - - PG_RETURN_NULL(); + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + TupleDesc tupdesc; + Tuplestorestate *tupstore; + MemoryContext per_query_ctx; + MemoryContext oldcontext; + + /* check to see if caller supports us returning a tuplestore */ + if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("set-valued function called in context that cannot accept a set"))); + if (!(rsinfo->allowedModes & SFRM_Materialize)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("materialize mode required, but it is not " \ + "allowed in this context"))); + + /* need to build tuplestore in query context */ + per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; + oldcontext = MemoryContextSwitchTo(per_query_ctx); + + /* + * build tupdesc for result tuples. + */ + tupdesc = CreateTemplateTupleDesc(7); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "oid", + INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "pg_namespace", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "pg_typname", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 4, "tsql_typname", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 5, "type_family_priority", + INT2OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 6, "priority", + INT2OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 7, "sql_variant_hdr_size", + INT2OID, -1, 0); + + tupstore = + tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random, + false, 1024); + /* generate junk in short-term context */ + MemoryContextSwitchTo(oldcontext); + + /* scan all the variables in top estate */ + for (int i = 0; i < TOTAL_TYPECODE_COUNT; i++) + { + type_info_t *info = &type_infos[i]; + Datum values[7]; + bool nulls[7]; + + MemSet(nulls, 0, sizeof(nulls)); + + values[0] = info->oid; + values[1] = info->nsp_is_sys ? CStringGetTextDatum("sys") : CStringGetTextDatum("pg_catalog"); + values[2] = CStringGetTextDatum(info->pg_typname); + values[3] = CStringGetTextDatum(info->tsql_typname); + values[4] = info->family_prio; + values[5] = info->prio; + values[6] = info->svhdr_size; + + tuplestore_putvalues(tupstore, tupdesc, values, nulls); + } + + /* clean up and return the tuplestore */ + tuplestore_donestoring(tupstore); + + rsinfo->returnMode = SFRM_Materialize; + rsinfo->setResult = tupstore; + rsinfo->setDesc = tupdesc; + + PG_RETURN_NULL(); } PG_FUNCTION_INFO_V1(translate_pg_type_to_tsql); @@ -227,7 +228,7 @@ PG_FUNCTION_INFO_V1(translate_pg_type_to_tsql); Datum translate_pg_type_to_tsql(PG_FUNCTION_ARGS) { - Oid pg_type = PG_GETARG_OID(0); + Oid pg_type = PG_GETARG_OID(0); ht_oid2typecode_entry_t *entry; if (OidIsValid(pg_type)) @@ -240,31 +241,32 @@ translate_pg_type_to_tsql(PG_FUNCTION_ARGS) PG_RETURN_NULL(); } -Oid get_type_oid(int type_code) +Oid +get_type_oid(int type_code) { return type_infos[type_code].oid; } -Oid tsql_bpchar_oid = InvalidOid; -Oid tsql_nchar_oid = InvalidOid; -Oid tsql_varchar_oid = InvalidOid; -Oid tsql_nvarchar_oid = InvalidOid; -Oid tsql_ntext_oid = InvalidOid; -Oid tsql_image_oid = InvalidOid; -Oid tsql_binary_oid = InvalidOid; -Oid tsql_varbinary_oid = InvalidOid; -Oid tsql_rowversion_oid = InvalidOid; -Oid tsql_timestamp_oid = InvalidOid; -Oid tsql_datetime2_oid = InvalidOid; -Oid tsql_smalldatetime_oid = InvalidOid; -Oid tsql_datetimeoffset_oid = InvalidOid; -Oid tsql_decimal_oid = InvalidOid; +Oid tsql_bpchar_oid = InvalidOid; +Oid tsql_nchar_oid = InvalidOid; +Oid tsql_varchar_oid = InvalidOid; +Oid tsql_nvarchar_oid = InvalidOid; +Oid tsql_ntext_oid = InvalidOid; +Oid tsql_image_oid = InvalidOid; +Oid tsql_binary_oid = InvalidOid; +Oid tsql_varbinary_oid = InvalidOid; +Oid tsql_rowversion_oid = InvalidOid; +Oid tsql_timestamp_oid = InvalidOid; +Oid tsql_datetime2_oid = InvalidOid; +Oid tsql_smalldatetime_oid = InvalidOid; +Oid tsql_datetimeoffset_oid = InvalidOid; +Oid tsql_decimal_oid = InvalidOid; Oid lookup_tsql_datatype_oid(const char *typename) { - Oid nspoid; - Oid typoid; + Oid nspoid; + Oid typoid; nspoid = get_namespace_oid("sys", true); if (nspoid == InvalidOid) @@ -363,7 +365,7 @@ is_tsql_timestamp_datatype(Oid oid) bool is_tsql_rowversion_or_timestamp_datatype(Oid oid) { - return (is_tsql_rowversion_datatype(oid) || is_tsql_timestamp_datatype(oid)); + return (is_tsql_rowversion_datatype(oid) || is_tsql_timestamp_datatype(oid)); } bool @@ -403,22 +405,24 @@ is_tsql_decimal_datatype(Oid oid) * collation id assigned to FuncExpr of the target column. (Maily for target types * based on [n][var]char including domains created over it.) */ -void +void handle_type_and_collation(Node *node, Oid typeid, Oid collationid) { - FuncExpr *expr; + FuncExpr *expr; /* - * We want to preserve the datatype and collation of the target column, so that it can be - * used later in datatype input function. + * We want to preserve the datatype and collation of the target column, so + * that it can be used later in datatype input function. */ if (nodeTag(node) == T_FuncExpr) expr = (FuncExpr *) node; - /* - * If datatype of target column is created as domain over varchar or char (e.g., nvarchar or nchar) - * Or if datatypes is user defined datatype created over [n][var]char - * then override funcresulttype with the oid of the domain type and store the collation using - * funccollid field so that we can make distinction inside input function to handle the input. + + /* + * If datatype of target column is created as domain over varchar or char + * (e.g., nvarchar or nchar) Or if datatypes is user defined datatype + * created over [n][var]char then override funcresulttype with the oid of + * the domain type and store the collation using funccollid field so that + * we can make distinction inside input function to handle the input. */ else if (nodeTag(node) == T_CoerceToDomain && ((CoerceToDomain *) node)->arg && @@ -431,7 +435,7 @@ handle_type_and_collation(Node *node, Oid typeid, Oid collationid) nodeTag(((CoerceToDomain *) ((RelabelType *) node)->arg)->arg) == T_FuncExpr) expr = (FuncExpr *) ((CoerceToDomain *) ((RelabelType *) node)->arg)->arg; else - return ; + return; if (!check_target_type_is_sys_varchar(expr->funcid)) return; @@ -450,8 +454,8 @@ handle_type_and_collation(Node *node, Oid typeid, Oid collationid) bool check_target_type_is_sys_varchar(Oid funcid) { - char *func_namespace = NULL; - char *funcname = NULL; + char *func_namespace = NULL; + char *funcname = NULL; func_namespace = get_namespace_name(get_func_namespace(funcid)); if (!func_namespace || strcmp("sys", func_namespace) != 0) diff --git a/contrib/babelfishpg_common/src/typecode.h b/contrib/babelfishpg_common/src/typecode.h index 0d79816c63..8101c3c0f3 100644 --- a/contrib/babelfishpg_common/src/typecode.h +++ b/contrib/babelfishpg_common/src/typecode.h @@ -51,38 +51,40 @@ struct Node; typedef struct type_info { - Oid oid; /* oid is only retrievable during runtime, so we have to init to 0 */ - bool nsp_is_sys; - const char *pg_typname; - const char *tsql_typname; - uint8_t family_prio; - uint8_t prio; - uint8_t svhdr_size; + Oid oid; /* oid is only retrievable during runtime, so + * we have to init to 0 */ + bool nsp_is_sys; + const char *pg_typname; + const char *tsql_typname; + uint8_t family_prio; + uint8_t prio; + uint8_t svhdr_size; } type_info_t; -typedef struct ht_oid2typecode_entry { - Oid key; - uint8_t persist_id; +typedef struct ht_oid2typecode_entry +{ + Oid key; + uint8_t persist_id; } ht_oid2typecode_entry_t; -extern Oid get_type_oid(int type_code); - -extern Oid tsql_bpchar_oid; -extern Oid tsql_nchar_oid; -extern Oid tsql_varchar_oid; -extern Oid tsql_nvarchar_oid; -extern Oid tsql_ntext_oid; -extern Oid tsql_image_oid; -extern Oid tsql_binary_oid; -extern Oid tsql_varbinary_oid; -extern Oid tsql_rowversion_oid; -extern Oid tsql_timestamp_oid; -extern Oid tsql_datetime2_oid; -extern Oid tsql_smalldatetime_oid; -extern Oid tsql_datetimeoffset_oid; -extern Oid tsql_decimal_oid; - -extern Oid lookup_tsql_datatype_oid(const char *typename); +extern Oid get_type_oid(int type_code); + +extern Oid tsql_bpchar_oid; +extern Oid tsql_nchar_oid; +extern Oid tsql_varchar_oid; +extern Oid tsql_nvarchar_oid; +extern Oid tsql_ntext_oid; +extern Oid tsql_image_oid; +extern Oid tsql_binary_oid; +extern Oid tsql_varbinary_oid; +extern Oid tsql_rowversion_oid; +extern Oid tsql_timestamp_oid; +extern Oid tsql_datetime2_oid; +extern Oid tsql_smalldatetime_oid; +extern Oid tsql_datetimeoffset_oid; +extern Oid tsql_decimal_oid; + +extern Oid lookup_tsql_datatype_oid(const char *typename); extern bool is_tsql_bpchar_datatype(Oid oid); extern bool is_tsql_nchar_datatype(Oid oid); extern bool is_tsql_varchar_datatype(Oid oid); @@ -105,9 +107,9 @@ extern bool check_target_type_is_sys_varchar(Oid funcid); extern type_info_t get_tsql_type_info(uint8_t type_code); extern Datum translate_pg_type_to_tsql(PG_FUNCTION_ARGS); -/* - * TransMemoryContext Memory context is created to load hash table to - * store 1. "OID to Persist Type Code Mapping" and 2. "OID to Persist +/* + * TransMemoryContext Memory context is created to load hash table to + * store 1. "OID to Persist Type Code Mapping" and 2. "OID to Persist * like to ilike Mapping" and 3. "OID to Persist Collation ID Mapping". */ extern MemoryContext TransMemoryContext; diff --git a/contrib/babelfishpg_common/src/uniqueidentifier.c b/contrib/babelfishpg_common/src/uniqueidentifier.c index 566a2e23d6..103181c4ce 100644 --- a/contrib/babelfishpg_common/src/uniqueidentifier.c +++ b/contrib/babelfishpg_common/src/uniqueidentifier.c @@ -21,12 +21,12 @@ PG_FUNCTION_INFO_V1(uniqueidentifier_in); Datum uniqueidentifier_in(PG_FUNCTION_ARGS) { - char *uuid_str = PG_GETARG_CSTRING(0); - pg_uuid_t *uuid; + char *uuid_str = PG_GETARG_CSTRING(0); + pg_uuid_t *uuid; - uuid = (pg_uuid_t *) palloc(sizeof(*uuid)); - string_to_uuid(uuid_str, uuid); - PG_RETURN_UUID_P(uuid); + uuid = (pg_uuid_t *) palloc(sizeof(*uuid)); + string_to_uuid(uuid_str, uuid); + PG_RETURN_UUID_P(uuid); } PG_FUNCTION_INFO_V1(uniqueidentifier_out); @@ -34,33 +34,33 @@ PG_FUNCTION_INFO_V1(uniqueidentifier_out); Datum uniqueidentifier_out(PG_FUNCTION_ARGS) { - pg_uuid_t *uuid = PG_GETARG_UUID_P(0); - static const char hex_chars[] = "0123456789ABCDEF"; - StringInfoData buf; - int i; - - initStringInfo(&buf); - for (i = 0; i < UUID_LEN; i++) - { - int hi; - int lo; - - /* - * We print uuid values as a string of 8, 4, 4, 4, and then 12 - * hexadecimal characters, with each group is separated by a hyphen - * ("-"). Therefore, add the hyphens at the appropriate places here. - */ - if (i == 4 || i == 6 || i == 8 || i == 10) - appendStringInfoChar(&buf, '-'); - - hi = uuid->data[i] >> 4; - lo = uuid->data[i] & 0x0F; - - appendStringInfoChar(&buf, hex_chars[hi]); - appendStringInfoChar(&buf, hex_chars[lo]); - } - - PG_RETURN_CSTRING(buf.data); + pg_uuid_t *uuid = PG_GETARG_UUID_P(0); + static const char hex_chars[] = "0123456789ABCDEF"; + StringInfoData buf; + int i; + + initStringInfo(&buf); + for (i = 0; i < UUID_LEN; i++) + { + int hi; + int lo; + + /* + * We print uuid values as a string of 8, 4, 4, 4, and then 12 + * hexadecimal characters, with each group is separated by a hyphen + * ("-"). Therefore, add the hyphens at the appropriate places here. + */ + if (i == 4 || i == 6 || i == 8 || i == 10) + appendStringInfoChar(&buf, '-'); + + hi = uuid->data[i] >> 4; + lo = uuid->data[i] & 0x0F; + + appendStringInfoChar(&buf, hex_chars[hi]); + appendStringInfoChar(&buf, hex_chars[lo]); + } + + PG_RETURN_CSTRING(buf.data); } /* @@ -121,11 +121,12 @@ PG_FUNCTION_INFO_V1(varchar2uniqueidentifier); Datum varchar2uniqueidentifier(PG_FUNCTION_ARGS) { - pg_uuid_t *uuid; - char *uuid_str = TextDatumGetCString(PG_GETARG_DATUM(0)); - uuid = (pg_uuid_t *) palloc(sizeof(*uuid)); - string_to_uuid(uuid_str, uuid); - PG_RETURN_UUID_P(uuid); + pg_uuid_t *uuid; + char *uuid_str = TextDatumGetCString(PG_GETARG_DATUM(0)); + + uuid = (pg_uuid_t *) palloc(sizeof(*uuid)); + string_to_uuid(uuid_str, uuid); + PG_RETURN_UUID_P(uuid); } @@ -134,11 +135,11 @@ PG_FUNCTION_INFO_V1(varbinary2uniqueidentifier); Datum varbinary2uniqueidentifier(PG_FUNCTION_ARGS) { - pg_uuid_t *uuid; + pg_uuid_t *uuid; unsigned char buffer[UUID_LEN]; - bytea *source = PG_GETARG_BYTEA_PP(0); - char *data = VARDATA_ANY(source); - int len = VARSIZE_ANY_EXHDR(source); + bytea *source = PG_GETARG_BYTEA_PP(0); + char *data = VARDATA_ANY(source); + int len = VARSIZE_ANY_EXHDR(source); memset(buffer, 0, UUID_LEN); memcpy(buffer, data, (len > UUID_LEN) ? UUID_LEN : len); @@ -146,9 +147,9 @@ varbinary2uniqueidentifier(PG_FUNCTION_ARGS) uuid = (pg_uuid_t *) palloc0(sizeof(*uuid)); /* T-SQL uses UUID variant 2 which is mixed-endian encoding */ reverse_memcpy(uuid->data, buffer, 4); - reverse_memcpy(uuid->data+4, buffer+4, 2); - reverse_memcpy(uuid->data+6, buffer+6, 2); - memcpy(uuid->data+8, buffer+8, 8); + reverse_memcpy(uuid->data + 4, buffer + 4, 2); + reverse_memcpy(uuid->data + 6, buffer + 6, 2); + memcpy(uuid->data + 8, buffer + 8, 8); PG_RETURN_UUID_P(uuid); } @@ -158,19 +159,19 @@ PG_FUNCTION_INFO_V1(uniqueidentifier2varbinary); Datum uniqueidentifier2varbinary(PG_FUNCTION_ARGS) { - char *rp; - bytea *result; - int32 maxlen; + char *rp; + bytea *result; + int32 maxlen; unsigned char buffer[UUID_LEN]; - size_t len = UUID_LEN; - pg_uuid_t *uuid = PG_GETARG_UUID_P(0); - int32 typmod = PG_GETARG_INT32(1); + size_t len = UUID_LEN; + pg_uuid_t *uuid = PG_GETARG_UUID_P(0); + int32 typmod = PG_GETARG_INT32(1); /* T-SQL uses UUID variant 2 which is mixed-endian encoding */ reverse_memcpy(buffer, uuid->data, 4); - reverse_memcpy(buffer+4, uuid->data+4, 2); - reverse_memcpy(buffer+6, uuid->data+6, 2); - memcpy(buffer+8, uuid->data+8, 8); + reverse_memcpy(buffer + 4, uuid->data + 4, 2); + reverse_memcpy(buffer + 6, uuid->data + 6, 2); + memcpy(buffer + 8, uuid->data + 8, 8); /* If typmod is -1 (or invalid), use the actual length */ if (typmod < (int32) VARHDRSZ) @@ -194,19 +195,19 @@ PG_FUNCTION_INFO_V1(uniqueidentifier2binary); Datum uniqueidentifier2binary(PG_FUNCTION_ARGS) { - char *rp; - bytea *result; - int32 maxlen; + char *rp; + bytea *result; + int32 maxlen; unsigned char buffer[UUID_LEN]; - size_t len = UUID_LEN; - pg_uuid_t *uuid = PG_GETARG_UUID_P(0); - int32 typmod = PG_GETARG_INT32(1); + size_t len = UUID_LEN; + pg_uuid_t *uuid = PG_GETARG_UUID_P(0); + int32 typmod = PG_GETARG_INT32(1); /* T-SQL uses UUID variant 2 which is mixed-endian encoding */ reverse_memcpy(buffer, uuid->data, 4); - reverse_memcpy(buffer+4, uuid->data+4, 2); - reverse_memcpy(buffer+6, uuid->data+6, 2); - memcpy(buffer+8, uuid->data+8, 8); + reverse_memcpy(buffer + 4, uuid->data + 4, 2); + reverse_memcpy(buffer + 6, uuid->data + 6, 2); + memcpy(buffer + 8, uuid->data + 8, 8); /* If typmod is -1 (or invalid), use the actual length */ if (typmod < (int32) VARHDRSZ) @@ -231,8 +232,8 @@ uniqueidentifier2binary(PG_FUNCTION_ARGS) static void reverse_memcpy(unsigned char *dst, unsigned char *src, size_t n) { - size_t i; + size_t i; for (i = 0; i < n; i++) - dst[n-1-i] = src[i]; + dst[n - 1 - i] = src[i]; } diff --git a/contrib/babelfishpg_common/src/varbinary.c b/contrib/babelfishpg_common/src/varbinary.c index 213d1e9e89..581e749d32 100644 --- a/contrib/babelfishpg_common/src/varbinary.c +++ b/contrib/babelfishpg_common/src/varbinary.c @@ -131,12 +131,15 @@ babelfish_hex_decode_allow_odd_digits(const char *src, unsigned len, char *dst) if (len % 2 == 1) { - /* If input has odd number of hex digits, add a 0 to the front to make it even */ + /* + * If input has odd number of hex digits, add a 0 to the front to make + * it even + */ v1 = '\0'; v2 = get_hex(*s++); *p++ = v1 | v2; } - /* The rest of the input must have even number of digits*/ + /* The rest of the input must have even number of digits */ while (s < srcend) { if (*s == ' ' || *s == '\n' || *s == '\t' || *s == '\r') @@ -160,23 +163,25 @@ varbinaryin(PG_FUNCTION_ARGS) { char *inputText = PG_GETARG_CSTRING(0); char *rp; - char *tp; + char *tp; int len; bytea *result; - int32 typmod = PG_GETARG_INT32(2); + int32 typmod = PG_GETARG_INT32(2); const char *dump_restore = GetConfigOption("babelfishpg_tsql.dump_restore", true, false); len = strlen(inputText); if (typmod == TSQLHexConstTypmod || - (dump_restore && strcmp(dump_restore, "on") == 0)) /* Treat input string as T-SQL hex constant during restore */ + (dump_restore && strcmp(dump_restore, "on") == 0)) /* Treat input string as + * T-SQL hex constant + * during restore */ { /* - * calculate length of the binary code - * e.g. 0xFF should be 1 byte (plus VARHDRSZ) - * and 0xF should also be 1 byte (plus VARHDRSZ). + * calculate length of the binary code e.g. 0xFF should be 1 byte + * (plus VARHDRSZ) and 0xF should also be 1 byte (plus VARHDRSZ). */ - int bc = (len - 1) / 2 + VARHDRSZ; /* maximum possible length */ + int bc = (len - 1) / 2 + VARHDRSZ; /* maximum possible length */ + result = palloc(bc); bc = babelfish_hex_decode_allow_odd_digits(inputText + 2, len - 2, VARDATA(result)); SET_VARSIZE(result, bc + VARHDRSZ); /* actual length */ @@ -319,27 +324,27 @@ varbinarysend(PG_FUNCTION_ARGS) Datum varbinary(PG_FUNCTION_ARGS) { - bytea *source = PG_GETARG_BYTEA_PP(0); - char *data = VARDATA_ANY(source); - int32 typmod = PG_GETARG_INT32(1); - bool isExplicit = PG_GETARG_BOOL(2); - int32 len, - maxlen; + bytea *source = PG_GETARG_BYTEA_PP(0); + char *data = VARDATA_ANY(source); + int32 typmod = PG_GETARG_INT32(1); + bool isExplicit = PG_GETARG_BOOL(2); + int32 len, + maxlen; len = VARSIZE_ANY_EXHDR(source); /* If typmod is -1 (or invalid), use the actual length */ if (typmod < (int32) VARHDRSZ) - maxlen = len; + maxlen = len; else maxlen = typmod - VARHDRSZ; if (!isExplicit && - !(suppress_string_truncation_error_hook && (*suppress_string_truncation_error_hook)())) + !(suppress_string_truncation_error_hook && (*suppress_string_truncation_error_hook) ())) if (len > maxlen) ereport(ERROR, (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), - errmsg("String or binary data would be truncated.\n" + errmsg("String or binary data would be truncated.\n" "The statement has been terminated."))); /* No work if typmod is invalid or supplied data fits it already */ @@ -347,8 +352,8 @@ varbinary(PG_FUNCTION_ARGS) PG_RETURN_BYTEA_P(source); /* - * Truncate the input data using cstring_to_text_with_len, notice text - * and bytea actually have the same struct. + * Truncate the input data using cstring_to_text_with_len, notice text and + * bytea actually have the same struct. */ PG_RETURN_BYTEA_P((bytea *) cstring_to_text_with_len(data, maxlen)); } @@ -367,20 +372,20 @@ varbinary(PG_FUNCTION_ARGS) Datum binary(PG_FUNCTION_ARGS) { - bytea *source = PG_GETARG_BYTEA_PP(0); - char *data = VARDATA_ANY(source); - int32 typmod = PG_GETARG_INT32(1); - bool isExplicit = PG_GETARG_BOOL(2); - int32 len, - maxlen; + bytea *source = PG_GETARG_BYTEA_PP(0); + char *data = VARDATA_ANY(source); + int32 typmod = PG_GETARG_INT32(1); + bool isExplicit = PG_GETARG_BOOL(2); + int32 len, + maxlen; len = VARSIZE_ANY_EXHDR(source); /* If typmod is -1 (or invalid), use the actual length */ if (typmod < (int32) VARHDRSZ) - maxlen = len; + maxlen = len; else - maxlen = typmod - VARHDRSZ; + maxlen = typmod - VARHDRSZ; if (maxlen > MAX_BINARY_SIZE) ereport(ERROR, @@ -389,11 +394,11 @@ binary(PG_FUNCTION_ARGS) maxlen, MAX_BINARY_SIZE))); if (!isExplicit && - !(suppress_string_truncation_error_hook && (*suppress_string_truncation_error_hook)())) - if(len > maxlen) + !(suppress_string_truncation_error_hook && (*suppress_string_truncation_error_hook) ())) + if (len > maxlen) ereport(ERROR, (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), - errmsg("String or binary data would be truncated.\n" + errmsg("String or binary data would be truncated.\n" "The statement has been terminated."))); /* No work if maxlen is invalid or supplied data fits it exactly */ @@ -402,10 +407,10 @@ binary(PG_FUNCTION_ARGS) if (len < maxlen) { - bytea *result; - int total_size = maxlen + VARHDRSZ; - char *tp; - char *rp; + bytea *result; + int total_size = maxlen + VARHDRSZ; + char *tp; + char *rp; result = (bytea *) palloc(total_size); SET_VARSIZE(result, total_size); @@ -420,8 +425,8 @@ binary(PG_FUNCTION_ARGS) } /* - * Truncate the input data to maxlen using cstring_to_text_with_len, notice text - * and bytea actually have the same struct. + * Truncate the input data to maxlen using cstring_to_text_with_len, + * notice text and bytea actually have the same struct. */ PG_RETURN_BYTEA_P((bytea *) cstring_to_text_with_len(data, maxlen)); } @@ -505,12 +510,12 @@ varbinarytypmodout(PG_FUNCTION_ARGS) } static void -reverse_memcpy(char* dst, char* src, size_t n) +reverse_memcpy(char *dst, char *src, size_t n) { - size_t i; + size_t i; for (i = 0; i < n; i++) - dst[n-1-i] = src[i]; + dst[n - 1 - i] = src[i]; } /* @@ -519,7 +524,7 @@ reverse_memcpy(char* dst, char* src, size_t n) Datum byteavarbinary(PG_FUNCTION_ARGS) { - bytea *source = PG_GETARG_BYTEA_PP(0); + bytea *source = PG_GETARG_BYTEA_PP(0); PG_RETURN_BYTEA_P(source); } @@ -527,7 +532,7 @@ byteavarbinary(PG_FUNCTION_ARGS) Datum varbinarybytea(PG_FUNCTION_ARGS) { - bytea *source = PG_GETARG_BYTEA_PP(0); + bytea *source = PG_GETARG_BYTEA_PP(0); PG_RETURN_BYTEA_P(source); } @@ -535,18 +540,18 @@ varbinarybytea(PG_FUNCTION_ARGS) Datum varbinaryrowversion(PG_FUNCTION_ARGS) { - bytea *source = PG_GETARG_BYTEA_PP(0); - bytea *result; - char *data = VARDATA_ANY(source); - size_t len = VARSIZE_ANY_EXHDR(source); - char *rp; + bytea *source = PG_GETARG_BYTEA_PP(0); + bytea *result; + char *data = VARDATA_ANY(source); + size_t len = VARSIZE_ANY_EXHDR(source); + char *rp; if (len > ROWVERSION_SIZE) len = ROWVERSION_SIZE; - + result = (bytea *) palloc0(ROWVERSION_SIZE + VARHDRSZ); SET_VARSIZE(result, ROWVERSION_SIZE + VARHDRSZ); - + rp = VARDATA(result); memcpy(rp, data, len); @@ -556,13 +561,13 @@ varbinaryrowversion(PG_FUNCTION_ARGS) Datum rowversionbinary(PG_FUNCTION_ARGS) { - bytea *source = PG_GETARG_BYTEA_PP(0); - int32 typmod = PG_GETARG_INT32(1); - char *data = VARDATA_ANY(source); - char *rp; - size_t len = VARSIZE_ANY_EXHDR(source); - int32 maxlen; - bytea *result; + bytea *source = PG_GETARG_BYTEA_PP(0); + int32 typmod = PG_GETARG_INT32(1); + char *data = VARDATA_ANY(source); + char *rp; + size_t len = VARSIZE_ANY_EXHDR(source); + int32 maxlen; + bytea *result; /* If typmod is -1 (or invalid), use the actual length */ if (typmod < (int32) VARHDRSZ) @@ -585,13 +590,13 @@ rowversionbinary(PG_FUNCTION_ARGS) Datum rowversionvarbinary(PG_FUNCTION_ARGS) { - bytea *source = PG_GETARG_BYTEA_PP(0); - int32 typmod = PG_GETARG_INT32(1); - char *data = VARDATA_ANY(source); - char *rp; - size_t len = VARSIZE_ANY_EXHDR(source); - int32 maxlen; - bytea *result; + bytea *source = PG_GETARG_BYTEA_PP(0); + int32 typmod = PG_GETARG_INT32(1); + char *data = VARDATA_ANY(source); + char *rp; + size_t len = VARSIZE_ANY_EXHDR(source); + int32 maxlen; + bytea *result; /* If typmod is -1 (or invalid), use the actual length */ if (typmod < (int32) VARHDRSZ) @@ -614,25 +619,25 @@ rowversionvarbinary(PG_FUNCTION_ARGS) Datum varcharvarbinary(PG_FUNCTION_ARGS) { - VarChar *source = PG_GETARG_VARCHAR_PP(0); - char *data = VARDATA_ANY(source); - char *rp; - size_t len = VARSIZE_ANY_EXHDR(source); - int32 typmod = PG_GETARG_INT32(1); - bool isExplicit = PG_GETARG_BOOL(2); - int32 maxlen; - bytea *result; + VarChar *source = PG_GETARG_VARCHAR_PP(0); + char *data = VARDATA_ANY(source); + char *rp; + size_t len = VARSIZE_ANY_EXHDR(source); + int32 typmod = PG_GETARG_INT32(1); + bool isExplicit = PG_GETARG_BOOL(2); + int32 maxlen; + bytea *result; if (!isExplicit) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("Implicit conversion from data type varchar to " - "varbinary is not allowed. Use the CONVERT function " - "to run this query."))); + "varbinary is not allowed. Use the CONVERT function " + "to run this query."))); /* If typmod is -1 (or invalid), use the actual length */ if (typmod < (int32) VARHDRSZ) - maxlen = len; + maxlen = len; else maxlen = typmod - VARHDRSZ; @@ -651,25 +656,25 @@ varcharvarbinary(PG_FUNCTION_ARGS) Datum bpcharvarbinary(PG_FUNCTION_ARGS) { - BpChar *source = PG_GETARG_BPCHAR_PP(0); - char *data = VARDATA_ANY(source); - char *rp; - size_t len = VARSIZE_ANY_EXHDR(source); - int32 typmod = PG_GETARG_INT32(1); - bool isExplicit = PG_GETARG_BOOL(2); - int32 maxlen; - bytea *result; + BpChar *source = PG_GETARG_BPCHAR_PP(0); + char *data = VARDATA_ANY(source); + char *rp; + size_t len = VARSIZE_ANY_EXHDR(source); + int32 typmod = PG_GETARG_INT32(1); + bool isExplicit = PG_GETARG_BOOL(2); + int32 maxlen; + bytea *result; if (!isExplicit) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("Implicit conversion from data type bpchar to " - "varbinary is not allowed. Use the CONVERT function " - "to run this query."))); + "varbinary is not allowed. Use the CONVERT function " + "to run this query."))); /* If typmod is -1 (or invalid), use the actual length */ if (typmod < (int32) VARHDRSZ) - maxlen = len; + maxlen = len; else maxlen = typmod - VARHDRSZ; @@ -690,14 +695,17 @@ bpcharvarbinary(PG_FUNCTION_ARGS) Datum varbinaryvarchar(PG_FUNCTION_ARGS) { - bytea *source = PG_GETARG_BYTEA_PP(0); - char *data = VARDATA_ANY(source); - size_t len = VARSIZE_ANY_EXHDR(source); - int32 typmod = PG_GETARG_INT32(1); - int32 maxlen = typmod - VARHDRSZ; - VarChar *result; - - /* Cast the entire input binary data if maxlen is invalid or supplied data fits it */ + bytea *source = PG_GETARG_BYTEA_PP(0); + char *data = VARDATA_ANY(source); + size_t len = VARSIZE_ANY_EXHDR(source); + int32 typmod = PG_GETARG_INT32(1); + int32 maxlen = typmod - VARHDRSZ; + VarChar *result; + + /* + * Cast the entire input binary data if maxlen is invalid or supplied data + * fits it + */ if (maxlen < 0 || len <= maxlen) result = (VarChar *) cstring_to_text_with_len(data, len); /* Else truncate it */ @@ -709,25 +717,25 @@ varbinaryvarchar(PG_FUNCTION_ARGS) Datum varcharbinary(PG_FUNCTION_ARGS) { - VarChar *source = PG_GETARG_VARCHAR_PP(0); - char *data = VARDATA_ANY(source); - char *rp; - size_t len = VARSIZE_ANY_EXHDR(source); - int32 typmod = PG_GETARG_INT32(1); - bool isExplicit = PG_GETARG_BOOL(2); - int32 maxlen; - bytea *result; + VarChar *source = PG_GETARG_VARCHAR_PP(0); + char *data = VARDATA_ANY(source); + char *rp; + size_t len = VARSIZE_ANY_EXHDR(source); + int32 typmod = PG_GETARG_INT32(1); + bool isExplicit = PG_GETARG_BOOL(2); + int32 maxlen; + bytea *result; if (!isExplicit) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("Implicit conversion from data type varchar to " - "binary is not allowed. Use the CONVERT function " - "to run this query."))); + "binary is not allowed. Use the CONVERT function " + "to run this query."))); /* If typmod is -1 (or invalid), use the actual length */ if (typmod < (int32) VARHDRSZ) - maxlen = len; + maxlen = len; else maxlen = typmod - VARHDRSZ; @@ -748,25 +756,25 @@ varcharbinary(PG_FUNCTION_ARGS) Datum bpcharbinary(PG_FUNCTION_ARGS) { - BpChar *source = PG_GETARG_BPCHAR_PP(0); - char *data = VARDATA_ANY(source); - char *rp; - size_t len = VARSIZE_ANY_EXHDR(source); - int32 typmod = PG_GETARG_INT32(1); - bool isExplicit = PG_GETARG_BOOL(2); - int32 maxlen; - bytea *result; + BpChar *source = PG_GETARG_BPCHAR_PP(0); + char *data = VARDATA_ANY(source); + char *rp; + size_t len = VARSIZE_ANY_EXHDR(source); + int32 typmod = PG_GETARG_INT32(1); + bool isExplicit = PG_GETARG_BOOL(2); + int32 maxlen; + bytea *result; if (!isExplicit) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("Implicit conversion from data type char to " - "binary is not allowed. Use the CONVERT function " - "to run this query."))); + "binary is not allowed. Use the CONVERT function " + "to run this query."))); /* If typmod is -1 (or invalid), use the actual length */ if (typmod < (int32) VARHDRSZ) - maxlen = len; + maxlen = len; else maxlen = typmod - VARHDRSZ; @@ -787,19 +795,19 @@ bpcharbinary(PG_FUNCTION_ARGS) Datum varcharrowversion(PG_FUNCTION_ARGS) { - VarChar *source = PG_GETARG_VARCHAR_PP(0); - char *data = VARDATA_ANY(source); - char *rp; - size_t len = VARSIZE_ANY_EXHDR(source); - bool isExplicit = PG_GETARG_BOOL(2); - bytea *result; + VarChar *source = PG_GETARG_VARCHAR_PP(0); + char *data = VARDATA_ANY(source); + char *rp; + size_t len = VARSIZE_ANY_EXHDR(source); + bool isExplicit = PG_GETARG_BOOL(2); + bytea *result; if (!isExplicit) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("Implicit conversion from data type varchar to " - "rowversion is not allowed. Use the CONVERT function " - "to run this query."))); + "rowversion is not allowed. Use the CONVERT function " + "to run this query."))); if (len > ROWVERSION_SIZE) len = ROWVERSION_SIZE; @@ -816,19 +824,19 @@ varcharrowversion(PG_FUNCTION_ARGS) Datum bpcharrowversion(PG_FUNCTION_ARGS) { - BpChar *source = PG_GETARG_BPCHAR_PP(0); - char *data = VARDATA_ANY(source); - char *rp; - size_t len = VARSIZE_ANY_EXHDR(source); - bool isExplicit = PG_GETARG_BOOL(2); - bytea *result; + BpChar *source = PG_GETARG_BPCHAR_PP(0); + char *data = VARDATA_ANY(source); + char *rp; + size_t len = VARSIZE_ANY_EXHDR(source); + bool isExplicit = PG_GETARG_BOOL(2); + bytea *result; if (!isExplicit) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("Implicit conversion from data type bpchar to " - "rowversion is not allowed. Use the CONVERT function " - "to run this query."))); + "rowversion is not allowed. Use the CONVERT function " + "to run this query."))); if (len > ROWVERSION_SIZE) len = ROWVERSION_SIZE; @@ -845,17 +853,17 @@ bpcharrowversion(PG_FUNCTION_ARGS) Datum int2varbinary(PG_FUNCTION_ARGS) { - int16 input = PG_GETARG_INT16(0); - int32 typmod = PG_GETARG_INT32(1); - int32 maxlen; - int len = sizeof(int16); - int actual_len; - bytea *result; - char *rp; + int16 input = PG_GETARG_INT16(0); + int32 typmod = PG_GETARG_INT32(1); + int32 maxlen; + int len = sizeof(int16); + int actual_len; + bytea *result; + char *rp; /* If typmod is -1 (or invalid), use the actual length */ if (typmod < (int32) VARHDRSZ) - maxlen = len; + maxlen = len; else maxlen = typmod - VARHDRSZ; @@ -866,7 +874,7 @@ int2varbinary(PG_FUNCTION_ARGS) rp = VARDATA(result); /* Need reverse copy because endianness is different in MSSQL */ - reverse_memcpy(rp, (char *) &input , actual_len); + reverse_memcpy(rp, (char *) &input, actual_len); PG_RETURN_BYTEA_P(result); } @@ -874,17 +882,17 @@ int2varbinary(PG_FUNCTION_ARGS) Datum int4varbinary(PG_FUNCTION_ARGS) { - int32 input = PG_GETARG_INT32(0); - int32 typmod = PG_GETARG_INT32(1); - int32 maxlen; - int len = sizeof(int32); - int actual_len; - bytea *result; - char *rp; + int32 input = PG_GETARG_INT32(0); + int32 typmod = PG_GETARG_INT32(1); + int32 maxlen; + int len = sizeof(int32); + int actual_len; + bytea *result; + char *rp; /* If typmod is -1 (or invalid), use the actual length */ if (typmod < (int32) VARHDRSZ) - maxlen = len; + maxlen = len; else maxlen = typmod - VARHDRSZ; @@ -895,7 +903,7 @@ int4varbinary(PG_FUNCTION_ARGS) rp = VARDATA(result); /* Need reverse copy because endianness is different in MSSQL */ - reverse_memcpy(rp, (char *) &input , actual_len); + reverse_memcpy(rp, (char *) &input, actual_len); PG_RETURN_BYTEA_P(result); } @@ -903,17 +911,17 @@ int4varbinary(PG_FUNCTION_ARGS) Datum int8varbinary(PG_FUNCTION_ARGS) { - int64 input = PG_GETARG_INT64(0); - int32 typmod = PG_GETARG_INT32(1); - int32 maxlen; - int len = sizeof(int64); - int actual_len; - bytea *result; - char *rp; + int64 input = PG_GETARG_INT64(0); + int32 typmod = PG_GETARG_INT32(1); + int32 maxlen; + int len = sizeof(int64); + int actual_len; + bytea *result; + char *rp; /* If typmod is -1 (or invalid), use the actual length */ if (typmod < (int32) VARHDRSZ) - maxlen = len; + maxlen = len; else maxlen = typmod - VARHDRSZ; @@ -924,7 +932,7 @@ int8varbinary(PG_FUNCTION_ARGS) rp = VARDATA(result); /* Need reverse copy because endianness is different in MSSQL */ - reverse_memcpy(rp, (char *) &input , actual_len); + reverse_memcpy(rp, (char *) &input, actual_len); PG_RETURN_BYTEA_P(result); } @@ -932,15 +940,15 @@ int8varbinary(PG_FUNCTION_ARGS) Datum varbinaryint2(PG_FUNCTION_ARGS) { - bytea *source = PG_GETARG_BYTEA_PP(0); - char *data = VARDATA_ANY(source); - int32 len; - int32 result_len; - int16 *result = palloc0(sizeof(int16)); + bytea *source = PG_GETARG_BYTEA_PP(0); + char *data = VARDATA_ANY(source); + int32 len; + int32 result_len; + int16 *result = palloc0(sizeof(int16)); len = VARSIZE_ANY_EXHDR(source); result_len = len > sizeof(int16) ? sizeof(int16) : len; - reverse_memcpy((char *)result, data, result_len); + reverse_memcpy((char *) result, data, result_len); PG_RETURN_INT16(*result); } @@ -948,15 +956,15 @@ varbinaryint2(PG_FUNCTION_ARGS) Datum varbinaryint4(PG_FUNCTION_ARGS) { - bytea *source = PG_GETARG_BYTEA_PP(0); - char *data = VARDATA_ANY(source); - int32 len; - int32 result_len; - int32 *result = palloc0(sizeof(int32)); + bytea *source = PG_GETARG_BYTEA_PP(0); + char *data = VARDATA_ANY(source); + int32 len; + int32 result_len; + int32 *result = palloc0(sizeof(int32)); len = VARSIZE_ANY_EXHDR(source); result_len = len > sizeof(int32) ? sizeof(int32) : len; - reverse_memcpy((char *)result, data, result_len); + reverse_memcpy((char *) result, data, result_len); PG_RETURN_INT32(*result); } @@ -964,15 +972,15 @@ varbinaryint4(PG_FUNCTION_ARGS) Datum varbinaryint8(PG_FUNCTION_ARGS) { - bytea *source = PG_GETARG_BYTEA_PP(0); - char *data = VARDATA_ANY(source); - int32 len; - int32 result_len; - int64 *result = palloc0(sizeof(int64)); + bytea *source = PG_GETARG_BYTEA_PP(0); + char *data = VARDATA_ANY(source); + int32 len; + int32 result_len; + int64 *result = palloc0(sizeof(int64)); len = VARSIZE_ANY_EXHDR(source); result_len = len > sizeof(int64) ? sizeof(int64) : len; - reverse_memcpy((char *)result, data, result_len); + reverse_memcpy((char *) result, data, result_len); PG_RETURN_INT64(*result); } @@ -980,17 +988,17 @@ varbinaryint8(PG_FUNCTION_ARGS) Datum float4varbinary(PG_FUNCTION_ARGS) { - float4 input = PG_GETARG_FLOAT4(0); - int32 typmod = PG_GETARG_INT32(1); - int32 maxlen; - int len = sizeof(float4); - int actual_len; - bytea *result; - char *rp; + float4 input = PG_GETARG_FLOAT4(0); + int32 typmod = PG_GETARG_INT32(1); + int32 maxlen; + int len = sizeof(float4); + int actual_len; + bytea *result; + char *rp; /* If typmod is -1 (or invalid), use the actual length */ if (typmod < (int32) VARHDRSZ) - maxlen = len; + maxlen = len; else maxlen = typmod - VARHDRSZ; @@ -1001,7 +1009,7 @@ float4varbinary(PG_FUNCTION_ARGS) rp = VARDATA(result); /* Need reverse copy because endianness is different in MSSQL */ - reverse_memcpy(rp, (char *) &input , actual_len); + reverse_memcpy(rp, (char *) &input, actual_len); PG_RETURN_BYTEA_P(result); } @@ -1009,17 +1017,17 @@ float4varbinary(PG_FUNCTION_ARGS) Datum float8varbinary(PG_FUNCTION_ARGS) { - float8 input = PG_GETARG_FLOAT8(0); - int32 typmod = PG_GETARG_INT32(1); - int32 maxlen; - int len = sizeof(float8); - int actual_len; - bytea *result; - char *rp; + float8 input = PG_GETARG_FLOAT8(0); + int32 typmod = PG_GETARG_INT32(1); + int32 maxlen; + int len = sizeof(float8); + int actual_len; + bytea *result; + char *rp; /* If typmod is -1 (or invalid), use the actual length */ if (typmod < (int32) VARHDRSZ) - maxlen = len; + maxlen = len; else maxlen = typmod - VARHDRSZ; @@ -1030,7 +1038,7 @@ float8varbinary(PG_FUNCTION_ARGS) rp = VARDATA(result); /* Need reverse copy because endianness is different in MSSQL */ - reverse_memcpy(rp, (char *) &input , actual_len); + reverse_memcpy(rp, (char *) &input, actual_len); PG_RETURN_BYTEA_P(result); } @@ -1038,15 +1046,15 @@ float8varbinary(PG_FUNCTION_ARGS) Datum varbinaryfloat4(PG_FUNCTION_ARGS) { - bytea *source = PG_GETARG_BYTEA_PP(0); - char *data = VARDATA_ANY(source); - int32 len; - int32 result_len; - float4 *result = palloc0(sizeof(float4)); + bytea *source = PG_GETARG_BYTEA_PP(0); + char *data = VARDATA_ANY(source); + int32 len; + int32 result_len; + float4 *result = palloc0(sizeof(float4)); len = VARSIZE_ANY_EXHDR(source); result_len = len > sizeof(float4) ? sizeof(float4) : len; - reverse_memcpy((char *)result, data, result_len); + reverse_memcpy((char *) result, data, result_len); PG_RETURN_FLOAT4(*result); } @@ -1054,15 +1062,15 @@ varbinaryfloat4(PG_FUNCTION_ARGS) Datum varbinaryfloat8(PG_FUNCTION_ARGS) { - bytea *source = PG_GETARG_BYTEA_PP(0); - char *data = VARDATA_ANY(source); - int32 len; - int32 result_len; - float8 *result = palloc0(sizeof(float8)); + bytea *source = PG_GETARG_BYTEA_PP(0); + char *data = VARDATA_ANY(source); + int32 len; + int32 result_len; + float8 *result = palloc0(sizeof(float8)); len = VARSIZE_ANY_EXHDR(source); result_len = len > sizeof(float8) ? sizeof(float8) : len; - reverse_memcpy((char *)result, data, result_len); + reverse_memcpy((char *) result, data, result_len); PG_RETURN_FLOAT8(*result); } @@ -1070,16 +1078,16 @@ varbinaryfloat8(PG_FUNCTION_ARGS) Datum int2binary(PG_FUNCTION_ARGS) { - int16 input = PG_GETARG_INT16(0); - int32 typmod = PG_GETARG_INT32(1); - int32 maxlen; - int len = sizeof(int16); - bytea *result; - char *rp; + int16 input = PG_GETARG_INT16(0); + int32 typmod = PG_GETARG_INT32(1); + int32 maxlen; + int len = sizeof(int16); + bytea *result; + char *rp; /* If typmod is -1 (or invalid), use the actual length */ if (typmod < (int32) VARHDRSZ) - maxlen = len; + maxlen = len; else maxlen = typmod - VARHDRSZ; @@ -1089,10 +1097,10 @@ int2binary(PG_FUNCTION_ARGS) rp = VARDATA(result); if (maxlen <= len) /* Need reverse copy because endianness is different in MSSQL */ - reverse_memcpy(rp, (char *) &input , maxlen); + reverse_memcpy(rp, (char *) &input, maxlen); else /* Pad 0 to the left if maxlen is longer than input length */ - reverse_memcpy(rp+maxlen-len, (char *) &input , len); + reverse_memcpy(rp + maxlen - len, (char *) &input, len); PG_RETURN_BYTEA_P(result); } @@ -1100,16 +1108,16 @@ int2binary(PG_FUNCTION_ARGS) Datum int4binary(PG_FUNCTION_ARGS) { - int32 input = PG_GETARG_INT32(0); - int32 typmod = PG_GETARG_INT32(1); - int32 maxlen; - int len = sizeof(int32); - bytea *result; - char *rp; + int32 input = PG_GETARG_INT32(0); + int32 typmod = PG_GETARG_INT32(1); + int32 maxlen; + int len = sizeof(int32); + bytea *result; + char *rp; /* If typmod is -1 (or invalid), use the actual length */ if (typmod < (int32) VARHDRSZ) - maxlen = len; + maxlen = len; else maxlen = typmod - VARHDRSZ; @@ -1120,10 +1128,10 @@ int4binary(PG_FUNCTION_ARGS) rp = VARDATA(result); if (maxlen <= len) /* Need reverse copy because endianness is different in MSSQL */ - reverse_memcpy(rp, (char *) &input , maxlen); + reverse_memcpy(rp, (char *) &input, maxlen); else /* Pad 0 to the left if maxlen is longer than input length */ - reverse_memcpy(rp+maxlen-len, (char *) &input , len); + reverse_memcpy(rp + maxlen - len, (char *) &input, len); PG_RETURN_BYTEA_P(result); } @@ -1131,16 +1139,16 @@ int4binary(PG_FUNCTION_ARGS) Datum int8binary(PG_FUNCTION_ARGS) { - int64 input = PG_GETARG_INT64(0); - int32 typmod = PG_GETARG_INT32(1); - int32 maxlen; - int len = sizeof(int64); - bytea *result; - char *rp; + int64 input = PG_GETARG_INT64(0); + int32 typmod = PG_GETARG_INT32(1); + int32 maxlen; + int len = sizeof(int64); + bytea *result; + char *rp; /* If typmod is -1 (or invalid), use the actual length */ if (typmod < (int32) VARHDRSZ) - maxlen = len; + maxlen = len; else maxlen = typmod - VARHDRSZ; @@ -1151,10 +1159,10 @@ int8binary(PG_FUNCTION_ARGS) rp = VARDATA(result); if (maxlen <= len) /* Need reverse copy because endianness is different in MSSQL */ - reverse_memcpy(rp, (char *) &input , maxlen); + reverse_memcpy(rp, (char *) &input, maxlen); else /* Pad 0 to the left if maxlen is longer than input length */ - reverse_memcpy(rp+maxlen-len, (char *) &input , len); + reverse_memcpy(rp + maxlen - len, (char *) &input, len); PG_RETURN_BYTEA_P(result); } @@ -1162,17 +1170,17 @@ int8binary(PG_FUNCTION_ARGS) Datum int2rowversion(PG_FUNCTION_ARGS) { - int16 input = PG_GETARG_INT16(0); - int len = sizeof(int16); - bytea *result; - char *rp; + int16 input = PG_GETARG_INT16(0); + int len = sizeof(int16); + bytea *result; + char *rp; result = (bytea *) palloc0(ROWVERSION_SIZE + VARHDRSZ); SET_VARSIZE(result, ROWVERSION_SIZE + VARHDRSZ); rp = VARDATA(result); /* Need reverse copy because endianness is different in T-SQL */ - reverse_memcpy(rp+ROWVERSION_SIZE-len, (char *) &input , len); + reverse_memcpy(rp + ROWVERSION_SIZE - len, (char *) &input, len); PG_RETURN_BYTEA_P(result); } @@ -1180,17 +1188,17 @@ int2rowversion(PG_FUNCTION_ARGS) Datum int4rowversion(PG_FUNCTION_ARGS) { - int32 input = PG_GETARG_INT32(0); - int len = sizeof(int32); - bytea *result; - char *rp; + int32 input = PG_GETARG_INT32(0); + int len = sizeof(int32); + bytea *result; + char *rp; result = (bytea *) palloc0(ROWVERSION_SIZE + VARHDRSZ); SET_VARSIZE(result, ROWVERSION_SIZE + VARHDRSZ); rp = VARDATA(result); /* Need reverse copy because endianness is different in T-SQL */ - reverse_memcpy(rp+ROWVERSION_SIZE-len, (char *) &input , len); + reverse_memcpy(rp + ROWVERSION_SIZE - len, (char *) &input, len); PG_RETURN_BYTEA_P(result); } @@ -1198,17 +1206,17 @@ int4rowversion(PG_FUNCTION_ARGS) Datum int8rowversion(PG_FUNCTION_ARGS) { - int64 input = PG_GETARG_INT64(0); - int len = sizeof(int64); - bytea *result; - char *rp; + int64 input = PG_GETARG_INT64(0); + int len = sizeof(int64); + bytea *result; + char *rp; result = (bytea *) palloc0(ROWVERSION_SIZE + VARHDRSZ); SET_VARSIZE(result, ROWVERSION_SIZE + VARHDRSZ); rp = VARDATA(result); /* Need reverse copy because endianness is different in T-SQL */ - reverse_memcpy(rp, (char *) &input , len); + reverse_memcpy(rp, (char *) &input, len); PG_RETURN_BYTEA_P(result); } @@ -1216,19 +1224,23 @@ int8rowversion(PG_FUNCTION_ARGS) Datum binaryint2(PG_FUNCTION_ARGS) { - bytea *source = PG_GETARG_BYTEA_PP(0); - char *data = VARDATA_ANY(source); - int32 len; - int32 result_len; - int16 *result = palloc0(sizeof(int16)); + bytea *source = PG_GETARG_BYTEA_PP(0); + char *data = VARDATA_ANY(source); + int32 len; + int32 result_len; + int16 *result = palloc0(sizeof(int16)); len = VARSIZE_ANY_EXHDR(source); result_len = len > sizeof(int16) ? sizeof(int16) : len; if (len > sizeof(int16)) - /* Skip the potentially 0 padded part if the input binary is over length */ - reverse_memcpy((char *)result, data+len-sizeof(int16), result_len); + + /* + * Skip the potentially 0 padded part if the input binary is over + * length + */ + reverse_memcpy((char *) result, data + len - sizeof(int16), result_len); else - reverse_memcpy((char *)result, data, result_len); + reverse_memcpy((char *) result, data, result_len); PG_RETURN_INT16(*result); } @@ -1236,19 +1248,23 @@ binaryint2(PG_FUNCTION_ARGS) Datum binaryint4(PG_FUNCTION_ARGS) { - bytea *source = PG_GETARG_BYTEA_PP(0); - char *data = VARDATA_ANY(source); - int32 len; - int32 result_len; - int32 *result = palloc0(sizeof(int32)); + bytea *source = PG_GETARG_BYTEA_PP(0); + char *data = VARDATA_ANY(source); + int32 len; + int32 result_len; + int32 *result = palloc0(sizeof(int32)); len = VARSIZE_ANY_EXHDR(source); result_len = len > sizeof(int32) ? sizeof(int32) : len; if (len > sizeof(int32)) - /* Skip the potentially 0 padded part if the input binary is over length */ - reverse_memcpy((char *)result, data+len-sizeof(int32), result_len); + + /* + * Skip the potentially 0 padded part if the input binary is over + * length + */ + reverse_memcpy((char *) result, data + len - sizeof(int32), result_len); else - reverse_memcpy((char *)result, data, result_len); + reverse_memcpy((char *) result, data, result_len); PG_RETURN_INT32(*result); } @@ -1256,19 +1272,23 @@ binaryint4(PG_FUNCTION_ARGS) Datum binaryint8(PG_FUNCTION_ARGS) { - bytea *source = PG_GETARG_BYTEA_PP(0); - char *data = VARDATA_ANY(source); - int32 len; - int32 result_len; - int64 *result = palloc0(sizeof(int64)); + bytea *source = PG_GETARG_BYTEA_PP(0); + char *data = VARDATA_ANY(source); + int32 len; + int32 result_len; + int64 *result = palloc0(sizeof(int64)); len = VARSIZE_ANY_EXHDR(source); result_len = len > sizeof(int64) ? sizeof(int64) : len; if (len > sizeof(int64)) - /* Skip the potentially 0 padded part if the input binary is over length */ - reverse_memcpy((char *)result, data+len-sizeof(int64), result_len); + + /* + * Skip the potentially 0 padded part if the input binary is over + * length + */ + reverse_memcpy((char *) result, data + len - sizeof(int64), result_len); else - reverse_memcpy((char *)result, data, result_len); + reverse_memcpy((char *) result, data, result_len); PG_RETURN_INT64(*result); } @@ -1276,16 +1296,16 @@ binaryint8(PG_FUNCTION_ARGS) Datum float4binary(PG_FUNCTION_ARGS) { - float4 input = PG_GETARG_FLOAT4(0); - int32 typmod = PG_GETARG_INT32(1); - int32 maxlen; - int len = sizeof(float4); - bytea *result; - char *rp; + float4 input = PG_GETARG_FLOAT4(0); + int32 typmod = PG_GETARG_INT32(1); + int32 maxlen; + int len = sizeof(float4); + bytea *result; + char *rp; /* If typmod is -1 (or invalid), use the actual length */ if (typmod < (int32) VARHDRSZ) - maxlen = len; + maxlen = len; else maxlen = typmod - VARHDRSZ; @@ -1296,10 +1316,10 @@ float4binary(PG_FUNCTION_ARGS) rp = VARDATA(result); if (maxlen <= len) /* Need reverse copy because endianness is different in MSSQL */ - reverse_memcpy(rp, (char *) &input , maxlen); + reverse_memcpy(rp, (char *) &input, maxlen); else /* Pad 0 to the left if maxlen is longer than input length */ - reverse_memcpy(rp+maxlen-len, (char *) &input , len); + reverse_memcpy(rp + maxlen - len, (char *) &input, len); PG_RETURN_BYTEA_P(result); } @@ -1307,16 +1327,16 @@ float4binary(PG_FUNCTION_ARGS) Datum float8binary(PG_FUNCTION_ARGS) { - float8 input = PG_GETARG_FLOAT8(0); - int32 typmod = PG_GETARG_INT32(1); - int32 maxlen; - int len = sizeof(float8); - bytea *result; - char *rp; + float8 input = PG_GETARG_FLOAT8(0); + int32 typmod = PG_GETARG_INT32(1); + int32 maxlen; + int len = sizeof(float8); + bytea *result; + char *rp; /* If typmod is -1 (or invalid), use the actual length */ if (typmod < (int32) VARHDRSZ) - maxlen = len; + maxlen = len; else maxlen = typmod - VARHDRSZ; @@ -1327,10 +1347,10 @@ float8binary(PG_FUNCTION_ARGS) rp = VARDATA(result); if (maxlen <= len) /* Need reverse copy because endianness is different in MSSQL */ - reverse_memcpy(rp, (char *) &input , maxlen); + reverse_memcpy(rp, (char *) &input, maxlen); else /* Pad 0 to the left if maxlen is longer than input length */ - reverse_memcpy(rp+maxlen-len, (char *) &input , len); + reverse_memcpy(rp + maxlen - len, (char *) &input, len); PG_RETURN_BYTEA_P(result); } @@ -1338,19 +1358,23 @@ float8binary(PG_FUNCTION_ARGS) Datum binaryfloat4(PG_FUNCTION_ARGS) { - bytea *source = PG_GETARG_BYTEA_PP(0); - char *data = VARDATA_ANY(source); - int32 len; - int32 result_len; - float4 *result = palloc0(sizeof(float4)); + bytea *source = PG_GETARG_BYTEA_PP(0); + char *data = VARDATA_ANY(source); + int32 len; + int32 result_len; + float4 *result = palloc0(sizeof(float4)); len = VARSIZE_ANY_EXHDR(source); result_len = len > sizeof(float4) ? sizeof(float4) : len; if (len > sizeof(float4)) - /* Skip the potentially 0 padded part if the input binary is over length */ - reverse_memcpy((char *)result, data+len-sizeof(float4), result_len); + + /* + * Skip the potentially 0 padded part if the input binary is over + * length + */ + reverse_memcpy((char *) result, data + len - sizeof(float4), result_len); else - reverse_memcpy((char *)result, data, result_len); + reverse_memcpy((char *) result, data, result_len); PG_RETURN_FLOAT4(*result); } @@ -1358,42 +1382,48 @@ binaryfloat4(PG_FUNCTION_ARGS) Datum binaryfloat8(PG_FUNCTION_ARGS) { - bytea *source = PG_GETARG_BYTEA_PP(0); - char *data = VARDATA_ANY(source); - int32 len; - int32 result_len; - float8 *result = palloc0(sizeof(float8)); + bytea *source = PG_GETARG_BYTEA_PP(0); + char *data = VARDATA_ANY(source); + int32 len; + int32 result_len; + float8 *result = palloc0(sizeof(float8)); len = VARSIZE_ANY_EXHDR(source); result_len = len > sizeof(float8) ? sizeof(float8) : len; if (len > sizeof(float8)) - /* Skip the potentially 0 padded part if the input binary is over length */ - reverse_memcpy((char *)result, data+len-sizeof(float8), result_len); + + /* + * Skip the potentially 0 padded part if the input binary is over + * length + */ + reverse_memcpy((char *) result, data + len - sizeof(float8), result_len); else - reverse_memcpy((char *)result, data, result_len); + reverse_memcpy((char *) result, data, result_len); PG_RETURN_FLOAT8(*result); } int8 -varbinarycompare(bytea *source1, bytea *source2); + varbinarycompare(bytea *source1, bytea *source2); int8 -inline varbinarycompare(bytea *source1, bytea *source2) + inline +varbinarycompare(bytea *source1, bytea *source2) { - char *data1 = VARDATA_ANY(source1); - int32 len1 = VARSIZE_ANY_EXHDR(source1); - char *data2 = VARDATA_ANY(source2); - int32 len2 = VARSIZE_ANY_EXHDR(source2); - + char *data1 = VARDATA_ANY(source1); + int32 len1 = VARSIZE_ANY_EXHDR(source1); + char *data2 = VARDATA_ANY(source2); + int32 len2 = VARSIZE_ANY_EXHDR(source2); + unsigned char byte1; unsigned char byte2; - int32 maxlen = len2 > len1 ? len2 : len1; + int32 maxlen = len2 > len1 ? len2 : len1; INSTR_METRIC_INC(INSTR_TSQL_VARBINARY_COMPARE); /* loop all the bytes */ - for (int i=0; i 0; + bytea *source1 = PG_GETARG_BYTEA_PP(0); + bytea *source2 = PG_GETARG_BYTEA_PP(1); + bool result = varbinarycompare(source1, source2) > 0; + PG_RETURN_BOOL(result); } Datum -varbinary_geq (PG_FUNCTION_ARGS) +varbinary_geq(PG_FUNCTION_ARGS) { - bytea *source1 = PG_GETARG_BYTEA_PP(0); - bytea *source2 = PG_GETARG_BYTEA_PP(1); - bool result = varbinarycompare(source1, source2) >= 0; + bytea *source1 = PG_GETARG_BYTEA_PP(0); + bytea *source2 = PG_GETARG_BYTEA_PP(1); + bool result = varbinarycompare(source1, source2) >= 0; + PG_RETURN_BOOL(result); } Datum -varbinary_lt (PG_FUNCTION_ARGS) +varbinary_lt(PG_FUNCTION_ARGS) { - bytea *source1 = PG_GETARG_BYTEA_PP(0); - bytea *source2 = PG_GETARG_BYTEA_PP(1); - bool result = varbinarycompare(source1, source2) < 0; + bytea *source1 = PG_GETARG_BYTEA_PP(0); + bytea *source2 = PG_GETARG_BYTEA_PP(1); + bool result = varbinarycompare(source1, source2) < 0; + PG_RETURN_BOOL(result); } Datum -varbinary_leq (PG_FUNCTION_ARGS) +varbinary_leq(PG_FUNCTION_ARGS) { - bytea *source1 = PG_GETARG_BYTEA_PP(0); - bytea *source2 = PG_GETARG_BYTEA_PP(1); - bool result = varbinarycompare(source1, source2) <= 0; + bytea *source1 = PG_GETARG_BYTEA_PP(0); + bytea *source2 = PG_GETARG_BYTEA_PP(1); + bool result = varbinarycompare(source1, source2) <= 0; + PG_RETURN_BOOL(result); } Datum -varbinary_cmp (PG_FUNCTION_ARGS) +varbinary_cmp(PG_FUNCTION_ARGS) { - bytea *source1 = PG_GETARG_BYTEA_PP(0); - bytea *source2 = PG_GETARG_BYTEA_PP(1); + bytea *source1 = PG_GETARG_BYTEA_PP(0); + bytea *source2 = PG_GETARG_BYTEA_PP(1); + PG_RETURN_INT32(varbinarycompare(source1, source2)); } @@ -1479,9 +1516,10 @@ varbinary_cmp (PG_FUNCTION_ARGS) PG_FUNCTION_INFO_V1(varbinary_length); Datum -varbinary_length (PG_FUNCTION_ARGS) +varbinary_length(PG_FUNCTION_ARGS) { - bytea *source = PG_GETARG_BYTEA_PP(0); - int32 limit = VARSIZE_ANY_EXHDR(source); + bytea *source = PG_GETARG_BYTEA_PP(0); + int32 limit = VARSIZE_ANY_EXHDR(source); + PG_RETURN_INT32(limit); } diff --git a/contrib/babelfishpg_common/src/varchar.c b/contrib/babelfishpg_common/src/varchar.c index 7d1514b6ef..d9ee253f8e 100644 --- a/contrib/babelfishpg_common/src/varchar.c +++ b/contrib/babelfishpg_common/src/varchar.c @@ -23,7 +23,7 @@ #include "fmgr.h" #include "libpq/pqformat.h" #include "nodes/nodeFuncs.h" -#include "parser/parser.h" /* only needed for GUC variables */ +#include "parser/parser.h" /* only needed for GUC variables */ #include "utils/array.h" #include "utils/builtins.h" #include "utils/float.h" @@ -42,26 +42,26 @@ #include "typecode.h" #include "varchar.h" -int TsqlUTF8LengthInUTF16(const void *vin, int len); -void TsqlCheckUTF16Length_varchar(const char *s_data, int32 len, int32 maxlen, bool isExplicit); -void TsqlCheckUTF16Length_bpchar(const char *s, int32 len, int32 maxlen, int charlen, bool isExplicit); -void TsqlCheckUTF16Length_bpchar_input(const char *s, int32 len, int32 maxlen, int charlen); -void TsqlCheckUTF16Length_varchar_input(const char *s, int32 len, int32 maxlen); +int TsqlUTF8LengthInUTF16(const void *vin, int len); +void TsqlCheckUTF16Length_varchar(const char *s_data, int32 len, int32 maxlen, bool isExplicit); +void TsqlCheckUTF16Length_bpchar(const char *s, int32 len, int32 maxlen, int charlen, bool isExplicit); +void TsqlCheckUTF16Length_bpchar_input(const char *s, int32 len, int32 maxlen, int charlen); +void TsqlCheckUTF16Length_varchar_input(const char *s, int32 len, int32 maxlen); static inline int varcharTruelen(VarChar *arg); #define DEFAULT_LCID 1033 /* - * is_basetype_nchar_nvarchar - given datatype is nvarchar or nchar + * is_basetype_nchar_nvarchar - given datatype is nvarchar or nchar * or created over nvarchar or nchar. */ -static bool +static bool is_basetype_nchar_nvarchar(Oid typid) { if (tsql_nvarchar_oid == InvalidOid) - tsql_nvarchar_oid = lookup_tsql_datatype_oid("nvarchar"); + tsql_nvarchar_oid = lookup_tsql_datatype_oid("nvarchar"); if (tsql_nchar_oid == InvalidOid) - tsql_nchar_oid = lookup_tsql_datatype_oid("nchar"); + tsql_nchar_oid = lookup_tsql_datatype_oid("nchar"); for (;;) { @@ -154,7 +154,7 @@ GetUTF8CodePoint(const unsigned char *in, int len, int *consumed_p) errmsg("invalid UTF8 byte sequence starting with 0x%02x", in[0]))); code = ((in[0] & 0x07) << 18) | ((in[1] & 0x3F) << 12) | - ((in[2] & 0x3F) << 6) | (in[3] & 0x3F); + ((in[2] & 0x3F) << 6) | (in[3] & 0x3F); consumed = 4; } else @@ -180,11 +180,11 @@ GetUTF8CodePoint(const unsigned char *in, int len, int *consumed_p) * TsqlUTF8LengthInUTF16 - compute the length of a UTF8 string in number of * 16-bit units if we were to convert it into * UTF16 with TdsUTF8toUTF16StringInfo() - */ + */ int TsqlUTF8LengthInUTF16(const void *vin, int len) { - const unsigned char *in = vin; + const unsigned char *in = vin; int result = 0; int i; int consumed; @@ -215,18 +215,19 @@ TsqlUTF8LengthInUTF16(const void *vin, int len) static inline void TsqlCheckUTF16Length(const char *utf8_str, size_t len, size_t maxlen, - char *varstr) + char *varstr) { - int i; + int i; + for (i = len; i > 0; i--) if (utf8_str[i - 1] != ' ') break; if (TsqlUTF8LengthInUTF16(utf8_str, i) > maxlen) ereport(ERROR, (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), - errmsg("value too long for type character%s(%d) " + errmsg("value too long for type character%s(%d) " "as UTF16 output", - varstr, (int)maxlen))); + varstr, (int) maxlen))); } /* @@ -235,22 +236,23 @@ TsqlCheckUTF16Length(const char *utf8_str, size_t len, size_t maxlen, void TsqlCheckUTF16Length_varchar(const char *s_data, int32 len, int32 maxlen, bool isExplicit) { - int i; + int i; size_t maxmblen; + if (maxlen < 0) - return ; - + return; + if (len <= maxlen) { TsqlCheckUTF16Length(s_data, len, maxlen, " varying"); - return ; + return; } /* truncate multibyte string preserving multibyte boundary */ maxmblen = pg_mbcharcliplen(s_data, len, maxlen); - if (!isExplicit && - !(suppress_string_truncation_error_hook && (*suppress_string_truncation_error_hook)())) + if (!isExplicit && + !(suppress_string_truncation_error_hook && (*suppress_string_truncation_error_hook) ())) { for (i = maxmblen; i < len; i++) if (s_data[i] != ' ') @@ -270,7 +272,8 @@ TsqlCheckUTF16Length_varchar(const char *s_data, int32 len, int32 maxlen, bool i void TsqlCheckUTF16Length_bpchar(const char *s, int32 len, int32 maxlen, int charlen, bool isExplicit) { - int i; + int i; + if (charlen == maxlen) { TsqlCheckUTF16Length(s, len, maxlen, ""); @@ -282,8 +285,8 @@ TsqlCheckUTF16Length_bpchar(const char *s, int32 len, int32 maxlen, int charlen, maxmblen = pg_mbcharcliplen(s, len, maxlen); - if (!isExplicit && - !(suppress_string_truncation_error_hook && (*suppress_string_truncation_error_hook)())) + if (!isExplicit && + !(suppress_string_truncation_error_hook && (*suppress_string_truncation_error_hook) ())) { for (i = maxmblen; i < len; i++) if (s[i] != ' ') @@ -302,10 +305,11 @@ TsqlCheckUTF16Length_bpchar(const char *s, int32 len, int32 maxlen, int charlen, } } -/* +/* * Check for T-SQL varchar common input function, varchar_input() */ -void TsqlCheckUTF16Length_varchar_input(const char *s, int32 len, int32 maxlen) +void +TsqlCheckUTF16Length_varchar_input(const char *s, int32 len, int32 maxlen) { TsqlCheckUTF16Length(s, len, maxlen, " varying"); } @@ -313,7 +317,8 @@ void TsqlCheckUTF16Length_varchar_input(const char *s, int32 len, int32 maxlen) /* * Check for T-SQL bpchar function */ -void TsqlCheckUTF16Length_bpchar_input(const char *s, int32 len, int32 maxlen, int charlen) +void +TsqlCheckUTF16Length_bpchar_input(const char *s, int32 len, int32 maxlen, int charlen) { if (charlen > maxlen) { @@ -322,9 +327,9 @@ void TsqlCheckUTF16Length_bpchar_input(const char *s, int32 len, int32 maxlen, i size_t j; /* - * at this point, len is the actual BYTE length of the input - * string, maxlen is the max number of CHARACTERS allowed for this - * bpchar type, mbmaxlen is the length in BYTES of those chars. + * at this point, len is the actual BYTE length of the input string, + * maxlen is the max number of CHARACTERS allowed for this bpchar + * type, mbmaxlen is the length in BYTES of those chars. */ for (j = mbmaxlen; j < len; j++) { @@ -495,19 +500,21 @@ varcharrecv(PG_FUNCTION_ARGS) Datum varchar(PG_FUNCTION_ARGS) { - VarChar *source = PG_GETARG_VARCHAR_PP(0); /* source string is in UTF8 */ + VarChar *source = PG_GETARG_VARCHAR_PP(0); /* source string is in + * UTF8 */ int32 typmod = PG_GETARG_INT32(1); bool isExplicit = PG_GETARG_BOOL(2); int32 byteLen; int32 maxByteLen; size_t maxmblen; - int i; - char *s_data; + int i; + char *s_data; coll_info collInfo; - int charLength; - char *tmp = NULL; /* To hold the string encoded in target column's collation. */ - char *resStr = NULL; /* To hold the final string in UTF8 encoding. */ - int encodedByteLen; + int charLength; + char *tmp = NULL; /* To hold the string encoded in target + * column's collation. */ + char *resStr = NULL; /* To hold the final string in UTF8 encoding. */ + int encodedByteLen; /* If type of target is NVARCHAR then handle it differently. */ if (fcinfo->flinfo->fn_expr && is_basetype_nchar_nvarchar(((FuncExpr *) fcinfo->flinfo->fn_expr)->funcresulttype)) @@ -521,18 +528,20 @@ varchar(PG_FUNCTION_ARGS) if (maxByteLen < 0) PG_RETURN_VARCHAR_P(source); - /* - * Try to find the lcid corresponding to the collation of the target column. + /* + * Try to find the lcid corresponding to the collation of the target + * column. */ if (fcinfo->flinfo->fn_expr) { - collInfo = lookup_collation_table(((FuncExpr *)fcinfo->flinfo->fn_expr)->funccollid); + collInfo = lookup_collation_table(((FuncExpr *) fcinfo->flinfo->fn_expr)->funccollid); } else { - /* - * Special handling required for OUTPUT params because this input function, varchar would be - * called from TDS to send the OUTPUT params of stored proc. + /* + * Special handling required for OUTPUT params because this input + * function, varchar would be called from TDS to send the OUTPUT + * params of stored proc. */ collInfo = lookup_collation_table(get_server_collation_oid_internal(false)); } @@ -540,20 +549,23 @@ varchar(PG_FUNCTION_ARGS) /* count the number of chars present in input string. */ charLength = pg_mbstrlen_with_len(s_data, byteLen); - /* - * Optimisation: Check if we can accommodate charLength number of chars considering every char requires - * max number of bytes for given encoding. + /* + * Optimisation: Check if we can accommodate charLength number of chars + * considering every char requires max number of bytes for given encoding. */ if (charLength * pg_encoding_max_length(collInfo.enc) <= maxByteLen) PG_RETURN_VARCHAR_P(source); - /* And encode the input string (usually in UTF8 encoding) in desired encoding. */ + /* + * And encode the input string (usually in UTF8 encoding) in desired + * encoding. + */ tmp = encoding_conv_util(s_data, byteLen, PG_UTF8, collInfo.enc, &encodedByteLen); byteLen = encodedByteLen; - /* - * We used byteLen here because we are interested in byte length of input string - * encoded using the code page of the target column's collation. + /* + * We used byteLen here because we are interested in byte length of input + * string encoded using the code page of the target column's collation. */ if (tmp && byteLen <= maxByteLen) { @@ -564,14 +576,14 @@ varchar(PG_FUNCTION_ARGS) /* only reach here if string is too long... */ - /* - * Truncate multibyte string (already encoded to the collation of target column) - * preserving multibyte boundary. + /* + * Truncate multibyte string (already encoded to the collation of target + * column) preserving multibyte boundary. */ maxmblen = pg_encoding_mbcliplen(collInfo.enc, tmp, byteLen, maxByteLen); if (!isExplicit && - !(suppress_string_truncation_error_hook && (*suppress_string_truncation_error_hook)())) + !(suppress_string_truncation_error_hook && (*suppress_string_truncation_error_hook) ())) { for (i = maxmblen; i < byteLen; i++) if (tmp[i] != ' ') @@ -587,7 +599,10 @@ varchar(PG_FUNCTION_ARGS) if (tmp && s_data != tmp && tmp != resStr) pfree(tmp); - /* Output of encoding_conv_util() would always be NULL terminated So we can use cstring_to_text directly. */ + /* + * Output of encoding_conv_util() would always be NULL terminated So we + * can use cstring_to_text directly. + */ PG_RETURN_VARCHAR_P((VarChar *) cstring_to_text_with_len(resStr, encodedByteLen)); } @@ -631,7 +646,7 @@ nvarchar(PG_FUNCTION_ARGS) maxmblen = pg_mbcharcliplen(s_data, len, maxlen); if (!isExplicit && - !(suppress_string_truncation_error_hook && (*suppress_string_truncation_error_hook)())) + !(suppress_string_truncation_error_hook && (*suppress_string_truncation_error_hook) ())) { for (i = maxmblen; i < len; i++) if (s_data[i] != ' ') @@ -649,9 +664,10 @@ static char * varchar2cstring(const VarChar *source) { const char *s_data = VARDATA_ANY(source); - int len = VARSIZE_ANY_EXHDR(source); + int len = VARSIZE_ANY_EXHDR(source); + + char *result = (char *) palloc(len + 1); - char *result = (char *) palloc(len + 1); memcpy(result, s_data, len); result[len] = '\0'; @@ -661,7 +677,8 @@ varchar2cstring(const VarChar *source) Datum varchar2int2(PG_FUNCTION_ARGS) { - VarChar *source = PG_GETARG_VARCHAR_PP(0); + VarChar *source = PG_GETARG_VARCHAR_PP(0); + if (varcharTruelen(source) == 0) PG_RETURN_INT16(0); @@ -671,7 +688,8 @@ varchar2int2(PG_FUNCTION_ARGS) Datum varchar2int4(PG_FUNCTION_ARGS) { - VarChar *source = PG_GETARG_VARCHAR_PP(0); + VarChar *source = PG_GETARG_VARCHAR_PP(0); + if (varcharTruelen(source) == 0) PG_RETURN_INT32(0); @@ -681,7 +699,8 @@ varchar2int4(PG_FUNCTION_ARGS) Datum varchar2int8(PG_FUNCTION_ARGS) { - VarChar *source = PG_GETARG_VARCHAR_PP(0); + VarChar *source = PG_GETARG_VARCHAR_PP(0); + if (varcharTruelen(source) == 0) PG_RETURN_INT64(0); @@ -692,9 +711,10 @@ static Datum cstring2float4(char *num) { /* This came from float4in() in backend/utils/adt/float.c */ - char *orig_num; - float val; - char *endptr; + char *orig_num; + float val; + char *endptr; + /* * endptr points to the first character _after_ the sequence we recognized * as a valid floating point number. orig_num points to the original input @@ -830,7 +850,7 @@ cstring2float4(char *num) Datum varchar2float4(PG_FUNCTION_ARGS) { - VarChar *source = PG_GETARG_VARCHAR_PP(0); + VarChar *source = PG_GETARG_VARCHAR_PP(0); if (varcharTruelen(source) == 0) PG_RETURN_FLOAT4(0); @@ -841,8 +861,8 @@ varchar2float4(PG_FUNCTION_ARGS) Datum varchar2float8(PG_FUNCTION_ARGS) { - VarChar *source = PG_GETARG_VARCHAR_PP(0); - char *num; + VarChar *source = PG_GETARG_VARCHAR_PP(0); + char *num; if (varcharTruelen(source) == 0) PG_RETURN_FLOAT8(0); @@ -854,9 +874,9 @@ varchar2float8(PG_FUNCTION_ARGS) Datum varchar2date(PG_FUNCTION_ARGS) { - VarChar *source = PG_GETARG_VARCHAR_PP(0); - char *str; - DateADT date; + VarChar *source = PG_GETARG_VARCHAR_PP(0); + char *str; + DateADT date; str = varchar2cstring(source); date = DatumGetDateADT(DirectFunctionCall1(date_in, CStringGetDatum(str))); @@ -867,9 +887,9 @@ varchar2date(PG_FUNCTION_ARGS) Datum varchar2time(PG_FUNCTION_ARGS) { - VarChar *source = PG_GETARG_VARCHAR_PP(0); - char *str; - TimeADT time; + VarChar *source = PG_GETARG_VARCHAR_PP(0); + char *str; + TimeADT time; str = varchar2cstring(source); time = DatumGetTimeADT(DirectFunctionCall1(time_in, CStringGetDatum(str))); @@ -880,22 +900,22 @@ varchar2time(PG_FUNCTION_ARGS) Datum varchar2money(PG_FUNCTION_ARGS) { - VarChar *source = PG_GETARG_VARCHAR_PP(0); - int64 val; + VarChar *source = PG_GETARG_VARCHAR_PP(0); + int64 val; if (varcharTruelen(source) == 0) PG_RETURN_CASH(0); val = pg_strtoint64(varchar2cstring(source)); - PG_RETURN_CASH((Cash)val); + PG_RETURN_CASH((Cash) val); } Datum varchar2numeric(PG_FUNCTION_ARGS) { - VarChar *source = PG_GETARG_VARCHAR_PP(0); - Numeric result; - char *str; + VarChar *source = PG_GETARG_VARCHAR_PP(0); + Numeric result; + char *str; str = varchar2cstring(source); result = DatumGetNumeric(DirectFunctionCall1(numeric_in, CStringGetDatum(str))); @@ -1051,16 +1071,17 @@ bpchar(PG_FUNCTION_ARGS) BpChar *source = PG_GETARG_BPCHAR_PP(0); /* source string in UTF8 */ int32 maxByteLen = PG_GETARG_INT32(1); bool isExplicit = PG_GETARG_BOOL(2); - BpChar *result; + BpChar *result; int32 byteLen; - char *r; - char *s_data; + char *r; + char *s_data; int i; - char *tmp = NULL; /* To hold the string encoded in target column's collation. */ - char *resStr = NULL; /* To hold the final string in UTF8 encoding. */ + char *tmp = NULL; /* To hold the string encoded in target + * column's collation. */ + char *resStr = NULL; /* To hold the final string in UTF8 encoding. */ coll_info collInfo; - int blankSpace = 0; /* How many blank space we need to pad. */ - int encodedByteLen; + int blankSpace = 0; /* How many blank space we need to pad. */ + int encodedByteLen; /* If type of target is NCHAR then handle it differently. */ if (fcinfo->flinfo->fn_expr && is_basetype_nchar_nvarchar(((FuncExpr *) fcinfo->flinfo->fn_expr)->funcresulttype)) @@ -1074,23 +1095,29 @@ bpchar(PG_FUNCTION_ARGS) byteLen = VARSIZE_ANY_EXHDR(source); s_data = VARDATA_ANY(source); - /* - * Try to find the lcid corresponding to the collation of the target column. + + /* + * Try to find the lcid corresponding to the collation of the target + * column. */ if (fcinfo->flinfo->fn_expr) { - collInfo = lookup_collation_table(((FuncExpr *)fcinfo->flinfo->fn_expr)->funccollid); + collInfo = lookup_collation_table(((FuncExpr *) fcinfo->flinfo->fn_expr)->funccollid); } else { - /* - * Special handling required for OUTPUT params because this input function, bpchar would be - * called from TDS to send the OUTPUT params of stored proc. - */ + /* + * Special handling required for OUTPUT params because this input + * function, bpchar would be called from TDS to send the OUTPUT params + * of stored proc. + */ collInfo = lookup_collation_table(get_server_collation_oid_internal(false)); } - /* And encode the input string (usually in UTF8 encoding) in desired encoding. */ + /* + * And encode the input string (usually in UTF8 encoding) in desired + * encoding. + */ tmp = encoding_conv_util(s_data, byteLen, PG_UTF8, collInfo.enc, &encodedByteLen); byteLen = encodedByteLen; @@ -1108,7 +1135,7 @@ bpchar(PG_FUNCTION_ARGS) maxmblen = pg_encoding_mbcliplen(collInfo.enc, tmp, byteLen, maxByteLen); if (!isExplicit && - !(suppress_string_truncation_error_hook && (*suppress_string_truncation_error_hook)())) + !(suppress_string_truncation_error_hook && (*suppress_string_truncation_error_hook) ())) { for (i = maxmblen; i < byteLen; i++) if (tmp[i] != ' ') @@ -1128,7 +1155,10 @@ bpchar(PG_FUNCTION_ARGS) /* Encode the input string back to UTF8 */ resStr = encoding_conv_util(tmp, byteLen, collInfo.enc, PG_UTF8, &encodedByteLen); - /* And override the len with actual length of string (encoded in UTF-8) */ + /* + * And override the len with actual length of string (encoded in + * UTF-8) + */ if (resStr != tmp) byteLen = encodedByteLen; } @@ -1142,7 +1172,7 @@ bpchar(PG_FUNCTION_ARGS) /* blank pad the string if necessary */ if (blankSpace > 0) memset(r + byteLen, ' ', blankSpace); - + if (tmp && s_data != tmp) pfree(tmp); @@ -1200,7 +1230,7 @@ nchar(PG_FUNCTION_ARGS) maxmblen = pg_mbcharcliplen(s, len, maxlen); if (!isExplicit && - !(suppress_string_truncation_error_hook && (*suppress_string_truncation_error_hook)())) + !(suppress_string_truncation_error_hook && (*suppress_string_truncation_error_hook) ())) { for (i = maxmblen; i < len; i++) if (s[i] != ' ') @@ -1247,9 +1277,10 @@ static char * bpchar2cstring(const BpChar *source) { const char *s_data = VARDATA_ANY(source); - int len = VARSIZE_ANY_EXHDR(source); + int len = VARSIZE_ANY_EXHDR(source); + + char *result = (char *) palloc(len + 1); - char *result = (char *) palloc(len + 1); memcpy(result, s_data, len); result[len] = '\0'; @@ -1259,7 +1290,8 @@ bpchar2cstring(const BpChar *source) Datum bpchar2int2(PG_FUNCTION_ARGS) { - BpChar *source = PG_GETARG_BPCHAR_PP(0); + BpChar *source = PG_GETARG_BPCHAR_PP(0); + if (bpchartruelen(VARDATA_ANY(source), VARSIZE_ANY_EXHDR(source)) == 0) PG_RETURN_INT16(0); @@ -1269,7 +1301,8 @@ bpchar2int2(PG_FUNCTION_ARGS) Datum bpchar2int4(PG_FUNCTION_ARGS) { - BpChar *source = PG_GETARG_BPCHAR_PP(0); + BpChar *source = PG_GETARG_BPCHAR_PP(0); + if (bpchartruelen(VARDATA_ANY(source), VARSIZE_ANY_EXHDR(source)) == 0) PG_RETURN_INT32(0); @@ -1279,7 +1312,8 @@ bpchar2int4(PG_FUNCTION_ARGS) Datum bpchar2int8(PG_FUNCTION_ARGS) { - BpChar *source = PG_GETARG_BPCHAR_PP(0); + BpChar *source = PG_GETARG_BPCHAR_PP(0); + if (bpchartruelen(VARDATA_ANY(source), VARSIZE_ANY_EXHDR(source)) == 0) PG_RETURN_INT64(0); @@ -1289,7 +1323,7 @@ bpchar2int8(PG_FUNCTION_ARGS) Datum bpchar2float4(PG_FUNCTION_ARGS) { - BpChar *source = PG_GETARG_BPCHAR_PP(0); + BpChar *source = PG_GETARG_BPCHAR_PP(0); if (bpchartruelen(VARDATA_ANY(source), VARSIZE_ANY_EXHDR(source)) == 0) PG_RETURN_FLOAT4(0); @@ -1300,8 +1334,8 @@ bpchar2float4(PG_FUNCTION_ARGS) Datum bpchar2float8(PG_FUNCTION_ARGS) { - BpChar *source = PG_GETARG_BPCHAR_PP(0); - char *num; + BpChar *source = PG_GETARG_BPCHAR_PP(0); + char *num; if (bpchartruelen(VARDATA_ANY(source), VARSIZE_ANY_EXHDR(source)) == 0) PG_RETURN_FLOAT8(0); @@ -1313,10 +1347,10 @@ bpchar2float8(PG_FUNCTION_ARGS) static inline int varcharTruelen(VarChar *arg) { - char *s = VARDATA_ANY(arg); - int len = VARSIZE_ANY_EXHDR(arg); + char *s = VARDATA_ANY(arg); + int len = VARSIZE_ANY_EXHDR(arg); - int i; + int i; /* * Note that we rely on the assumption that ' ' is a singleton unit on @@ -1349,8 +1383,8 @@ check_collation_set(Oid collid) Datum varchareq(PG_FUNCTION_ARGS) { - VarChar *arg1 = PG_GETARG_VARCHAR_PP(0); - VarChar *arg2 = PG_GETARG_VARCHAR_PP(1); + VarChar *arg1 = PG_GETARG_VARCHAR_PP(0); + VarChar *arg2 = PG_GETARG_VARCHAR_PP(1); int len1, len2; bool result; @@ -1389,8 +1423,8 @@ varchareq(PG_FUNCTION_ARGS) Datum varcharne(PG_FUNCTION_ARGS) { - VarChar *arg1 = PG_GETARG_VARCHAR_PP(0); - VarChar *arg2 = PG_GETARG_VARCHAR_PP(1); + VarChar *arg1 = PG_GETARG_VARCHAR_PP(0); + VarChar *arg2 = PG_GETARG_VARCHAR_PP(1); int len1, len2; bool result; @@ -1429,8 +1463,8 @@ varcharne(PG_FUNCTION_ARGS) Datum varcharlt(PG_FUNCTION_ARGS) { - VarChar *arg1 = PG_GETARG_VARCHAR_PP(0); - VarChar *arg2 = PG_GETARG_VARCHAR_PP(1); + VarChar *arg1 = PG_GETARG_VARCHAR_PP(0); + VarChar *arg2 = PG_GETARG_VARCHAR_PP(1); int len1, len2; int cmp; @@ -1450,8 +1484,8 @@ varcharlt(PG_FUNCTION_ARGS) Datum varcharle(PG_FUNCTION_ARGS) { - VarChar *arg1 = PG_GETARG_VARCHAR_PP(0); - VarChar *arg2 = PG_GETARG_VARCHAR_PP(1); + VarChar *arg1 = PG_GETARG_VARCHAR_PP(0); + VarChar *arg2 = PG_GETARG_VARCHAR_PP(1); int len1, len2; int cmp; @@ -1471,8 +1505,8 @@ varcharle(PG_FUNCTION_ARGS) Datum varchargt(PG_FUNCTION_ARGS) { - VarChar *arg1 = PG_GETARG_VARCHAR_PP(0); - VarChar *arg2 = PG_GETARG_VARCHAR_PP(1); + VarChar *arg1 = PG_GETARG_VARCHAR_PP(0); + VarChar *arg2 = PG_GETARG_VARCHAR_PP(1); int len1, len2; int cmp; @@ -1492,8 +1526,8 @@ varchargt(PG_FUNCTION_ARGS) Datum varcharge(PG_FUNCTION_ARGS) { - VarChar *arg1 = PG_GETARG_VARCHAR_PP(0); - VarChar *arg2 = PG_GETARG_VARCHAR_PP(1); + VarChar *arg1 = PG_GETARG_VARCHAR_PP(0); + VarChar *arg2 = PG_GETARG_VARCHAR_PP(1); int len1, len2; int cmp; @@ -1513,8 +1547,8 @@ varcharge(PG_FUNCTION_ARGS) Datum varcharcmp(PG_FUNCTION_ARGS) { - VarChar *arg1 = PG_GETARG_VARCHAR_PP(0); - VarChar *arg2 = PG_GETARG_VARCHAR_PP(1); + VarChar *arg1 = PG_GETARG_VARCHAR_PP(0); + VarChar *arg2 = PG_GETARG_VARCHAR_PP(1); int len1, len2; int cmp; @@ -1538,7 +1572,7 @@ varcharcmp(PG_FUNCTION_ARGS) Datum hashvarchar(PG_FUNCTION_ARGS) { - VarChar *key = PG_GETARG_VARCHAR_PP(0); + VarChar *key = PG_GETARG_VARCHAR_PP(0); Oid collid = PG_GET_COLLATION(); char *keydata; int keylen; diff --git a/contrib/babelfishpg_common/src/varchar.h b/contrib/babelfishpg_common/src/varchar.h index b16021db96..122455592d 100644 --- a/contrib/babelfishpg_common/src/varchar.h +++ b/contrib/babelfishpg_common/src/varchar.h @@ -6,4 +6,4 @@ extern void *tsql_varchar_input(const char *s, size_t len, int32 atttypmod); extern void *tsql_bpchar_input(const char *s, size_t len, int32 atttypmod); -#endif \ No newline at end of file +#endif diff --git a/contrib/babelfishpg_money/fixeddecimal.c b/contrib/babelfishpg_money/fixeddecimal.c index 14fc29b1ba..f76a345b35 100755 --- a/contrib/babelfishpg_money/fixeddecimal.c +++ b/contrib/babelfishpg_money/fixeddecimal.c @@ -63,7 +63,7 @@ #ifndef HAVE_BUILTIN_OVERFLOW #define SAMESIGN(a,b) (((a) < 0) == ((b) < 0)) -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ #define FIXEDDECIMAL_MAX (INT64_MAX/FIXEDDECIMAL_MULTIPLIER) #define FIXEDDECIMAL_MIN (INT64_MIN/FIXEDDECIMAL_MULTIPLIER) @@ -244,24 +244,24 @@ static int64 int8fixeddecimal_internal(int64 arg, const char *typename); *---------------------------------------------------------*/ /* - * pg_int64tostr - * Converts 'value' into a decimal string representation of the number. - * - * Caller must ensure that 'str' points to enough memory to hold the result - * (at least 21 bytes, counting a leading sign and trailing NUL). - * Return value is a pointer to the new NUL terminated end of string. - */ + * pg_int64tostr Converts 'value' into a decimal string representation of the + * number. + * + * Caller must ensure that 'str' points to enough memory to hold the result + * (at least 21 bytes, counting a leading sign and trailing NUL). Return + * value is a pointer to the new NUL terminated end of string. + */ static char * pg_int64tostr(char *str, int64 value) { - char *start; - char *end; + char *start; + char *end; /* * Handle negative numbers in a special way. We can't just append a '-' * prefix and reverse the sign as on two's complement machines negative - * numbers can be 1 further from 0 than positive numbers, we do it this way - * so we properly handle the smallest possible value. + * numbers can be 1 further from 0 than positive numbers, we do it this + * way so we properly handle the smallest possible value. */ if (value < 0) { @@ -304,6 +304,7 @@ pg_int64tostr(char *str, int64 value) while (start < str) { char swap = *start; + *start++ = *str; *str-- = swap; } @@ -329,15 +330,15 @@ pg_int64tostr_zeropad(char *str, int64 value, int64 padding) { char *start = str; char *end = &str[padding]; - int64 num = value; + int64 num = value; Assert(padding > 0); /* * Handle negative numbers in a special way. We can't just append a '-' * prefix and reverse the sign as on two's complement machines negative - * numbers can be 1 further from 0 than positive numbers, we do it this way - * so we properly handle the smallest possible value. + * numbers can be 1 further from 0 than positive numbers, we do it this + * way so we properly handle the smallest possible value. */ if (num < 0) { @@ -438,7 +439,7 @@ scanfixeddecimal(const char *str, int *precision, int *scale) /* skip leading spaces */ while (isspace((unsigned char) *ptr)) ptr++; - + /* handle sign */ if (*ptr == '-') { @@ -468,33 +469,37 @@ scanfixeddecimal(const char *str, int *precision, int *scale) (unsigned int) *ptr != '+' && (unsigned int) *ptr != ' ' && (unsigned int) *ptr != '\0') + { + /* + * Current workaround for BABEL-704 - this will accept multiple + * currency symbols until BABEL-704 is fixed + */ + if ((*ptr >= 'a' && *ptr <= 'z') || (*ptr >= 'A' && *ptr <= 'Z')) { - /* Current workaround for BABEL-704 - this will accept multiple currency symbols - * until BABEL-704 is fixed */ - if ((*ptr >= 'a' && *ptr <= 'z') || (*ptr >= 'A' && *ptr <= 'Z')) - { ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("invalid characters found: cannot cast value \"%s\" to money", + errmsg("invalid characters found: cannot cast value \"%s\" to money", str))); - } - ptr++; } + ptr++; + } /* skip leading spaces */ while (isspace((unsigned char) *ptr)) ptr++; - - /* Handle sign again. This is needed so that a sign after the currency symbol - * can be recognized */ + + /* + * Handle sign again. This is needed so that a sign after the currency + * symbol can be recognized + */ if (*ptr == '-') { if (has_seen_sign) { ereport(ERROR, - (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("invalid characters found: cannot cast value \"%s\" to money", - str))); + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("invalid characters found: cannot cast value \"%s\" to money", + str))); } negative = true; ptr++; @@ -508,16 +513,16 @@ scanfixeddecimal(const char *str, int *precision, int *scale) int64 tmp = integralpart * 10 - (*ptr++ - '0'); vprecision++; - if ((tmp / 10) != integralpart) /* underflow? */ + if ((tmp / 10) != integralpart) /* underflow? */ { ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("value \"%s\" is out of range for type fixeddecimal", - str))); + errmsg("value \"%s\" is out of range for type fixeddecimal", + str))); } integralpart = tmp; /* skip thousand separator */ - if(*ptr == ',') + if (*ptr == ',') ptr++; } } @@ -531,9 +536,9 @@ scanfixeddecimal(const char *str, int *precision, int *scale) if (has_seen_sign) { ereport(ERROR, - (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("invalid characters found: cannot cast value \"%s\" to money", - str))); + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("invalid characters found: cannot cast value \"%s\" to money", + str))); } ptr++; } @@ -541,34 +546,35 @@ scanfixeddecimal(const char *str, int *precision, int *scale) /* skip leading spaces */ while (isspace((unsigned char) *ptr)) ptr++; - + while (isdigit((unsigned char) *ptr)) { int64 tmp; - + if (!negative) tmp = integralpart * 10 + (*ptr++ - '0'); else tmp = integralpart * 10 - (*ptr++ - '0'); vprecision++; - if ((tmp / 10) != integralpart) /* overflow? */ + if ((tmp / 10) != integralpart) /* overflow? */ { ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("value \"%s\" is out of range for type fixeddecimal", - str))); + errmsg("value \"%s\" is out of range for type fixeddecimal", + str))); } integralpart = tmp; - /* skip thousand separator */ - if(*ptr == ',') - ptr++; + /* skip thousand separator */ + if (*ptr == ',') + ptr++; } } /* process the part after the decimal point */ if (*ptr == '.') { - int64 multiplier = FIXEDDECIMAL_MULTIPLIER; + int64 multiplier = FIXEDDECIMAL_MULTIPLIER; + ptr++; while (isdigit((unsigned char) *ptr) && multiplier > 1) @@ -579,9 +585,9 @@ scanfixeddecimal(const char *str, int *precision, int *scale) } /* - * Eat into any excess precision digits. - * For first digit, apply "Round half away from zero" - * XXX These are ignored, should we error instead? + * Eat into any excess precision digits. For first digit, apply "Round + * half away from zero" XXX These are ignored, should we error + * instead? */ if (isdigit((unsigned char) *ptr) && (unsigned char) *ptr >= '5') { @@ -600,7 +606,7 @@ scanfixeddecimal(const char *str, int *precision, int *scale) if (*ptr != '\0') ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("value \"%s\" is out of range for type fixeddecimal", str))); + errmsg("value \"%s\" is out of range for type fixeddecimal", str))); *precision = vprecision; *scale = vscale; @@ -608,21 +614,22 @@ scanfixeddecimal(const char *str, int *precision, int *scale) if (negative) { - int64 value; + int64 value; #ifdef HAVE_BUILTIN_OVERFLOW - int64 multiplier = FIXEDDECIMAL_MULTIPLIER; + int64 multiplier = FIXEDDECIMAL_MULTIPLIER; + if (__builtin_mul_overflow(integralpart, multiplier, &value)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("value \"%s\" is out of range for type fixeddecimal", - str))); + errmsg("value \"%s\" is out of range for type fixeddecimal", + str))); if (__builtin_sub_overflow(value, fractionalpart, &value)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("value \"%s\" is out of range for type fixeddecimal", - str))); + errmsg("value \"%s\" is out of range for type fixeddecimal", + str))); return value; #else @@ -632,29 +639,29 @@ scanfixeddecimal(const char *str, int *precision, int *scale) !SAMESIGN(value - fractionalpart, value))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("value \"%s\" is out of range for type fixeddecimal", - str))); + errmsg("value \"%s\" is out of range for type fixeddecimal", + str))); return value - fractionalpart; -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ } else { - int64 value; + int64 value; #ifdef HAVE_BUILTIN_OVERFLOW if (__builtin_mul_overflow(integralpart, FIXEDDECIMAL_MULTIPLIER, &value)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("value \"%s\" is out of range for type fixeddecimal", - str))); + errmsg("value \"%s\" is out of range for type fixeddecimal", + str))); if (__builtin_add_overflow(value, fractionalpart, &value)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("value \"%s\" is out of range for type fixeddecimal", - str))); + errmsg("value \"%s\" is out of range for type fixeddecimal", + str))); return value; #else value = integralpart * FIXEDDECIMAL_MULTIPLIER; @@ -663,11 +670,11 @@ scanfixeddecimal(const char *str, int *precision, int *scale) !SAMESIGN(value + fractionalpart, value))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("value \"%s\" is out of range for type fixeddecimal", - str))); + errmsg("value \"%s\" is out of range for type fixeddecimal", + str))); return value + fractionalpart; -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ } } @@ -707,11 +714,11 @@ apply_typmod(int64 value, int32 typmod, int precision, int scale) if (scale > scalelimit) - if (scale != FIXEDDECIMAL_SCALE) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("FIXEDDECIMAL scale must be %d", - FIXEDDECIMAL_SCALE))); + if (scale != FIXEDDECIMAL_SCALE) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("FIXEDDECIMAL scale must be %d", + FIXEDDECIMAL_SCALE))); if (precision > maxdigits) ereport(ERROR, @@ -719,7 +726,7 @@ apply_typmod(int64 value, int32 typmod, int precision, int scale) errmsg("FIXEDDECIMAL field overflow"), errdetail("A field with precision %d, scale %d must round to an absolute value less than %s%d.", precision, scale, - /* Display 10^0 as 1 */ + /* Display 10^0 as 1 */ maxdigits ? "10^" : "", maxdigits ? maxdigits : 1 ))); @@ -804,6 +811,7 @@ fixeddecimalout(PG_FUNCTION_ARGS) int64 val = PG_GETARG_INT64(0); char buf[MAXINT8LEN + 1]; char *end = fixeddecimal2str(val, buf); + PG_RETURN_CSTRING(pnstrdup(buf, end - buf)); } @@ -1186,13 +1194,13 @@ fixeddecimal_int8_eq(PG_FUNCTION_ARGS) int64 val1 = PG_GETARG_INT64(0); int64 val2 = PG_GETARG_INT64(1); - if (val2 > FIXEDDECIMAL_MAX) - PG_RETURN_BOOL(false); - else if (val2 < FIXEDDECIMAL_MIN) - PG_RETURN_BOOL(false); - - val2 = val2 * FIXEDDECIMAL_MULTIPLIER; - return val1 == val2; + if (val2 > FIXEDDECIMAL_MAX) + PG_RETURN_BOOL(false); + else if (val2 < FIXEDDECIMAL_MIN) + PG_RETURN_BOOL(false); + + val2 = val2 * FIXEDDECIMAL_MULTIPLIER; + return val1 == val2; } Datum @@ -1201,13 +1209,13 @@ fixeddecimal_int8_ne(PG_FUNCTION_ARGS) int64 val1 = PG_GETARG_INT64(0); int64 val2 = PG_GETARG_INT64(1); - if (val2 > FIXEDDECIMAL_MAX) - PG_RETURN_BOOL(true); - else if (val2 < FIXEDDECIMAL_MIN) - PG_RETURN_BOOL(true); - - val2 = val2 * FIXEDDECIMAL_MULTIPLIER; - return val1 != val2; + if (val2 > FIXEDDECIMAL_MAX) + PG_RETURN_BOOL(true); + else if (val2 < FIXEDDECIMAL_MIN) + PG_RETURN_BOOL(true); + + val2 = val2 * FIXEDDECIMAL_MULTIPLIER; + return val1 != val2; } Datum @@ -1216,13 +1224,13 @@ fixeddecimal_int8_lt(PG_FUNCTION_ARGS) int64 val1 = PG_GETARG_INT64(0); int64 val2 = PG_GETARG_INT64(1); - if (val2 > FIXEDDECIMAL_MAX) - PG_RETURN_BOOL(true); - else if (val2 < FIXEDDECIMAL_MIN) - PG_RETURN_BOOL(false); - - val2 = val2 * FIXEDDECIMAL_MULTIPLIER; - return val1 < val2; + if (val2 > FIXEDDECIMAL_MAX) + PG_RETURN_BOOL(true); + else if (val2 < FIXEDDECIMAL_MIN) + PG_RETURN_BOOL(false); + + val2 = val2 * FIXEDDECIMAL_MULTIPLIER; + return val1 < val2; } Datum @@ -1231,13 +1239,13 @@ fixeddecimal_int8_gt(PG_FUNCTION_ARGS) int64 val1 = PG_GETARG_INT64(0); int64 val2 = PG_GETARG_INT64(1); - if (val2 > FIXEDDECIMAL_MAX) - PG_RETURN_BOOL(false); - else if (val2 < FIXEDDECIMAL_MIN) - PG_RETURN_BOOL(true); - - val2 = val2 * FIXEDDECIMAL_MULTIPLIER; - return val1 > val2; + if (val2 > FIXEDDECIMAL_MAX) + PG_RETURN_BOOL(false); + else if (val2 < FIXEDDECIMAL_MIN) + PG_RETURN_BOOL(true); + + val2 = val2 * FIXEDDECIMAL_MULTIPLIER; + return val1 > val2; } Datum @@ -1246,13 +1254,13 @@ fixeddecimal_int8_le(PG_FUNCTION_ARGS) int64 val1 = PG_GETARG_INT64(0); int64 val2 = PG_GETARG_INT64(1); - if (val2 > FIXEDDECIMAL_MAX) - PG_RETURN_BOOL(true); - else if (val2 < FIXEDDECIMAL_MIN) - PG_RETURN_BOOL(false); - - val2 = val2 * FIXEDDECIMAL_MULTIPLIER; - return val1 <= val2; + if (val2 > FIXEDDECIMAL_MAX) + PG_RETURN_BOOL(true); + else if (val2 < FIXEDDECIMAL_MIN) + PG_RETURN_BOOL(false); + + val2 = val2 * FIXEDDECIMAL_MULTIPLIER; + return val1 <= val2; } Datum @@ -1261,13 +1269,13 @@ fixeddecimal_int8_ge(PG_FUNCTION_ARGS) int64 val1 = PG_GETARG_INT64(0); int64 val2 = PG_GETARG_INT64(1); - if (val2 > FIXEDDECIMAL_MAX) - PG_RETURN_BOOL(false); - else if (val2 < FIXEDDECIMAL_MIN) - PG_RETURN_BOOL(true); - - val2 = val2 * FIXEDDECIMAL_MULTIPLIER; - return val1 >= val2; + if (val2 > FIXEDDECIMAL_MAX) + PG_RETURN_BOOL(false); + else if (val2 < FIXEDDECIMAL_MIN) + PG_RETURN_BOOL(true); + + val2 = val2 * FIXEDDECIMAL_MULTIPLIER; + return val1 >= val2; } Datum @@ -1276,12 +1284,12 @@ fixeddecimal_int8_cmp(PG_FUNCTION_ARGS) int64 val1 = PG_GETARG_INT64(0); int64 val2 = PG_GETARG_INT64(1); - if (val2 > FIXEDDECIMAL_MAX) - PG_RETURN_INT32(-1); - else if (val2 < FIXEDDECIMAL_MIN) - PG_RETURN_INT32(1); - - val2 = val2 * FIXEDDECIMAL_MULTIPLIER; + if (val2 > FIXEDDECIMAL_MAX) + PG_RETURN_INT32(-1); + else if (val2 < FIXEDDECIMAL_MIN) + PG_RETURN_INT32(1); + + val2 = val2 * FIXEDDECIMAL_MULTIPLIER; if (val1 == val2) PG_RETURN_INT32(0); else if (val1 < val2) @@ -1296,13 +1304,13 @@ int8_fixeddecimal_eq(PG_FUNCTION_ARGS) int64 val1 = PG_GETARG_INT64(0); int64 val2 = PG_GETARG_INT64(1); - if (val1 > FIXEDDECIMAL_MAX) - PG_RETURN_BOOL(false); - else if (val1 < FIXEDDECIMAL_MIN) - PG_RETURN_BOOL(false); - - val1 = val1 * FIXEDDECIMAL_MULTIPLIER; - return val1 == val2; + if (val1 > FIXEDDECIMAL_MAX) + PG_RETURN_BOOL(false); + else if (val1 < FIXEDDECIMAL_MIN) + PG_RETURN_BOOL(false); + + val1 = val1 * FIXEDDECIMAL_MULTIPLIER; + return val1 == val2; } Datum @@ -1311,13 +1319,13 @@ int8_fixeddecimal_ne(PG_FUNCTION_ARGS) int64 val1 = PG_GETARG_INT64(0); int64 val2 = PG_GETARG_INT64(1); - if (val1 > FIXEDDECIMAL_MAX) - PG_RETURN_BOOL(true); - else if (val1 < FIXEDDECIMAL_MIN) - PG_RETURN_BOOL(true); - - val1 = val1 * FIXEDDECIMAL_MULTIPLIER; - return val1 != val2; + if (val1 > FIXEDDECIMAL_MAX) + PG_RETURN_BOOL(true); + else if (val1 < FIXEDDECIMAL_MIN) + PG_RETURN_BOOL(true); + + val1 = val1 * FIXEDDECIMAL_MULTIPLIER; + return val1 != val2; } Datum @@ -1326,13 +1334,13 @@ int8_fixeddecimal_lt(PG_FUNCTION_ARGS) int64 val1 = PG_GETARG_INT64(0); int64 val2 = PG_GETARG_INT64(1); - if (val1 > FIXEDDECIMAL_MAX) - PG_RETURN_BOOL(false); - else if (val1 < FIXEDDECIMAL_MIN) - PG_RETURN_BOOL(true); - - val1 = val1 * FIXEDDECIMAL_MULTIPLIER; - return val1 < val2; + if (val1 > FIXEDDECIMAL_MAX) + PG_RETURN_BOOL(false); + else if (val1 < FIXEDDECIMAL_MIN) + PG_RETURN_BOOL(true); + + val1 = val1 * FIXEDDECIMAL_MULTIPLIER; + return val1 < val2; } Datum @@ -1341,13 +1349,13 @@ int8_fixeddecimal_gt(PG_FUNCTION_ARGS) int64 val1 = PG_GETARG_INT64(0); int64 val2 = PG_GETARG_INT64(1); - if (val1 > FIXEDDECIMAL_MAX) - PG_RETURN_BOOL(true); - else if (val1 < FIXEDDECIMAL_MIN) - PG_RETURN_BOOL(false); - - val1 = val1 * FIXEDDECIMAL_MULTIPLIER; - return val1 > val2; + if (val1 > FIXEDDECIMAL_MAX) + PG_RETURN_BOOL(true); + else if (val1 < FIXEDDECIMAL_MIN) + PG_RETURN_BOOL(false); + + val1 = val1 * FIXEDDECIMAL_MULTIPLIER; + return val1 > val2; } Datum @@ -1356,13 +1364,13 @@ int8_fixeddecimal_le(PG_FUNCTION_ARGS) int64 val1 = PG_GETARG_INT64(0); int64 val2 = PG_GETARG_INT64(1); - if (val1 > FIXEDDECIMAL_MAX) - PG_RETURN_BOOL(false); - else if (val1 < FIXEDDECIMAL_MIN) - PG_RETURN_BOOL(true); - - val1 = val1 * FIXEDDECIMAL_MULTIPLIER; - return val1 <= val2; + if (val1 > FIXEDDECIMAL_MAX) + PG_RETURN_BOOL(false); + else if (val1 < FIXEDDECIMAL_MIN) + PG_RETURN_BOOL(true); + + val1 = val1 * FIXEDDECIMAL_MULTIPLIER; + return val1 <= val2; } Datum @@ -1371,13 +1379,13 @@ int8_fixeddecimal_ge(PG_FUNCTION_ARGS) int64 val1 = PG_GETARG_INT64(0); int64 val2 = PG_GETARG_INT64(1); - if (val1 > FIXEDDECIMAL_MAX) - PG_RETURN_BOOL(true); - else if (val1 < FIXEDDECIMAL_MIN) - PG_RETURN_BOOL(false); - - val1 = val1 * FIXEDDECIMAL_MULTIPLIER; - return val1 >= val2; + if (val1 > FIXEDDECIMAL_MAX) + PG_RETURN_BOOL(true); + else if (val1 < FIXEDDECIMAL_MIN) + PG_RETURN_BOOL(false); + + val1 = val1 * FIXEDDECIMAL_MULTIPLIER; + return val1 >= val2; } Datum @@ -1386,12 +1394,12 @@ int8_fixeddecimal_cmp(PG_FUNCTION_ARGS) int64 val1 = PG_GETARG_INT64(0); int64 val2 = PG_GETARG_INT64(1); - if (val1 > FIXEDDECIMAL_MAX) - PG_RETURN_INT32(1); - else if (val1 < FIXEDDECIMAL_MIN) - PG_RETURN_INT32(-1); - - val1 = val1 * FIXEDDECIMAL_MULTIPLIER; + if (val1 > FIXEDDECIMAL_MAX) + PG_RETURN_INT32(1); + else if (val1 < FIXEDDECIMAL_MIN) + PG_RETURN_INT32(-1); + + val1 = val1 * FIXEDDECIMAL_MULTIPLIER; if (val1 == val2) PG_RETURN_INT32(0); else if (val1 < val2) @@ -1601,9 +1609,9 @@ fixeddecimalum(PG_FUNCTION_ARGS) int64 result; #ifdef HAVE_BUILTIN_OVERFLOW - int64 zero = 0; + int64 zero = 0; - if (__builtin_sub_overflow(zero, arg, &result)) + if (__builtin_sub_overflow(zero, arg, &result)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); @@ -1614,7 +1622,7 @@ fixeddecimalum(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ PG_RETURN_INT64(result); } @@ -1650,7 +1658,7 @@ fixeddecimalpl(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ PG_RETURN_INT64(result); } @@ -1679,7 +1687,7 @@ fixeddecimalmi(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ PG_RETURN_INT64(result); } @@ -1691,10 +1699,10 @@ fixeddecimalmul(PG_FUNCTION_ARGS) int64 arg2 = PG_GETARG_INT64(1); int128 result; - /* We need to promote this to 128bit as we may overflow int64 here. - * Remember that arg2 is the number multiplied by - * FIXEDDECIMAL_MULTIPLIER, we must divide the result by this to get - * the correct result. + /* + * We need to promote this to 128bit as we may overflow int64 here. + * Remember that arg2 is the number multiplied by FIXEDDECIMAL_MULTIPLIER, + * we must divide the result by this to get the correct result. */ result = (int128) arg1 * arg2 / FIXEDDECIMAL_MULTIPLIER; @@ -1808,7 +1816,7 @@ fixeddecimalint8pl(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ PG_RETURN_INT64(result); } @@ -1838,7 +1846,7 @@ fixeddecimalint8mi(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ PG_RETURN_INT64(result); } @@ -1873,7 +1881,7 @@ fixeddecimalint8mul(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ PG_RETURN_INT64(result); } @@ -1903,7 +1911,8 @@ fixeddecimalint8div(PG_FUNCTION_ARGS) if (arg2 == -1) { #ifdef HAVE_BUILTIN_OVERFLOW - int64 zero = 0; + int64 zero = 0; + if (__builtin_sub_overflow(zero, arg1, &result)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), @@ -1915,7 +1924,7 @@ fixeddecimalint8div(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ PG_RETURN_INT64(result); } @@ -1951,7 +1960,7 @@ int8fixeddecimalpl(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ PG_RETURN_INT64(result); } @@ -1980,7 +1989,7 @@ int8fixeddecimalmi(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ PG_RETURN_INT64(result); } @@ -2015,7 +2024,7 @@ int8fixeddecimalmul(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ PG_RETURN_INT64(result); } @@ -2063,7 +2072,7 @@ fixeddecimalint4pl(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ PG_RETURN_INT64(result); } @@ -2093,7 +2102,7 @@ fixeddecimalint4mi(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ PG_RETURN_INT64(result); } @@ -2128,7 +2137,7 @@ fixeddecimalint4mul(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ PG_RETURN_INT64(result); } @@ -2158,7 +2167,8 @@ fixeddecimalint4div(PG_FUNCTION_ARGS) if (arg2 == -1) { #ifdef HAVE_BUILTIN_OVERFLOW - int64 zero = 0; + int64 zero = 0; + if (__builtin_sub_overflow(zero, arg1, &result)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), @@ -2170,7 +2180,7 @@ fixeddecimalint4div(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ PG_RETURN_INT64(result); } @@ -2206,7 +2216,7 @@ int4fixeddecimalpl(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ PG_RETURN_INT64(result); } @@ -2235,7 +2245,7 @@ int4fixeddecimalmi(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ PG_RETURN_INT64(result); } @@ -2270,7 +2280,7 @@ int4fixeddecimalmul(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ PG_RETURN_INT64(result); } @@ -2318,7 +2328,7 @@ fixeddecimalint2pl(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ PG_RETURN_INT64(result); } @@ -2347,7 +2357,7 @@ fixeddecimalint2mi(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ PG_RETURN_INT64(result); } @@ -2382,7 +2392,7 @@ fixeddecimalint2mul(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ PG_RETURN_INT64(result); } @@ -2412,7 +2422,8 @@ fixeddecimalint2div(PG_FUNCTION_ARGS) if (arg2 == -1) { #ifdef HAVE_BUILTIN_OVERFLOW - int64 zero = 0; + int64 zero = 0; + if (__builtin_sub_overflow(zero, arg1, &result)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), @@ -2424,7 +2435,7 @@ fixeddecimalint2div(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ PG_RETURN_INT64(result); } @@ -2459,7 +2470,7 @@ int2fixeddecimalpl(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ PG_RETURN_INT64(result); } @@ -2488,7 +2499,7 @@ int2fixeddecimalmi(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ PG_RETURN_INT64(result); } @@ -2509,9 +2520,9 @@ int2fixeddecimalmul(PG_FUNCTION_ARGS) result = arg1 * arg2; /* - * Overflow check. We basically check to see if result / arg2 gives - * arg1 again. There is one case where this fails: arg2 = 0 (which - * cannot overflow). + * Overflow check. We basically check to see if result / arg2 gives arg1 + * again. There is one case where this fails: arg2 = 0 (which cannot + * overflow). * * Since the division is likely much more expensive than the actual * multiplication, we'd like to skip it where possible. The best bang for @@ -2523,7 +2534,7 @@ int2fixeddecimalmul(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("fixeddecimal out of range"))); -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ PG_RETURN_INT64(result); } @@ -2577,6 +2588,7 @@ int8_to_money(PG_FUNCTION_ARGS) { int64 arg = PG_GETARG_INT64(0); int64 result = int8fixeddecimal_internal(arg, "money"); + PG_RETURN_INT64(result); } @@ -2585,6 +2597,7 @@ int8_to_smallmoney(PG_FUNCTION_ARGS) { int64 arg = PG_GETARG_INT64(0); int64 result = int8fixeddecimal_internal(arg, "smallmoney"); + PG_RETURN_INT64(result); } @@ -2593,6 +2606,7 @@ int8fixeddecimal(PG_FUNCTION_ARGS) { int64 arg = PG_GETARG_INT64(0); int64 result = int8fixeddecimal_internal(arg, "fixeddecimal"); + PG_RETURN_INT64(result); } @@ -2600,9 +2614,9 @@ static int64 int8fixeddecimal_internal(int64 arg, const char *typename) { int64 result; - + /* check for INT64 overflow on multiplication */ - if(unlikely(pg_mul_s64_overflow(arg, FIXEDDECIMAL_MULTIPLIER, &result))) + if (unlikely(pg_mul_s64_overflow(arg, FIXEDDECIMAL_MULTIPLIER, &result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("value \"%ld\" is out of range for type %s", arg, typename))); @@ -2820,7 +2834,7 @@ fixeddecimal_accum(FixedDecimalAggState *state, int64 newval) #else if (state->N++ > 0) { - int64 result = state->sumX + newval; + int64 result = state->sumX + newval; if (SAMESIGN(state->sumX, newval) && !SAMESIGN(result, state->sumX)) ereport(ERROR, @@ -2831,7 +2845,7 @@ fixeddecimal_accum(FixedDecimalAggState *state, int64 newval) } else state->sumX = newval; -#endif /* HAVE_BUILTIN_OVERFLOW */ +#endif /* HAVE_BUILTIN_OVERFLOW */ } Datum @@ -2889,9 +2903,9 @@ fixeddecimal_sum(PG_FUNCTION_ARGS) Datum fixeddecimalaggstatein(PG_FUNCTION_ARGS) { - char *str = pstrdup(PG_GETARG_CSTRING(0)); - FixedDecimalAggState *state; - char *token; + char *str = pstrdup(PG_GETARG_CSTRING(0)); + FixedDecimalAggState *state; + char *token; state = (FixedDecimalAggState *) palloc(sizeof(FixedDecimalAggState)); @@ -2928,8 +2942,9 @@ fixeddecimalaggstateout(PG_FUNCTION_ARGS) Datum fixeddecimalaggstaterecv(PG_FUNCTION_ARGS) { - StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); - FixedDecimalAggState *state; + StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); + FixedDecimalAggState *state; + state = (FixedDecimalAggState *) palloc(sizeof(FixedDecimalAggState)); state->sumX = pq_getmsgint(buf, sizeof(int64)); @@ -2944,13 +2959,13 @@ fixeddecimalaggstaterecv(PG_FUNCTION_ARGS) Datum fixeddecimalaggstatesend(PG_FUNCTION_ARGS) { - FixedDecimalAggState *state = (FixedDecimalAggState *) PG_GETARG_POINTER(0); - StringInfoData buf; + FixedDecimalAggState *state = (FixedDecimalAggState *) PG_GETARG_POINTER(0); + StringInfoData buf; pq_begintypsend(&buf); - pq_sendint(&buf, state->sumX, sizeof (int64)); - pq_sendint(&buf, state->N, sizeof (int64)); + pq_sendint(&buf, state->sumX, sizeof(int64)); + pq_sendint(&buf, state->N, sizeof(int64)); PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); } @@ -3034,7 +3049,7 @@ fixeddecimalaggstatecombine(PG_FUNCTION_ARGS) if (collectstate == NULL) { collectstate = (FixedDecimalAggState *) palloc(sizeof - (FixedDecimalAggState)); + (FixedDecimalAggState)); collectstate->sumX = 0; collectstate->N = 0; } @@ -3046,9 +3061,9 @@ fixeddecimalaggstatecombine(PG_FUNCTION_ARGS) PG_RETURN_POINTER(collectstate); collectstate->sumX = DatumGetInt64(DirectFunctionCall2(fixeddecimalpl, - Int64GetDatum(collectstate->sumX), Int64GetDatum(transstate->sumX))); + Int64GetDatum(collectstate->sumX), Int64GetDatum(transstate->sumX))); collectstate->N = DatumGetInt64(DirectFunctionCall2(int8pl, - Int64GetDatum(collectstate->N), Int64GetDatum(transstate->N))); + Int64GetDatum(collectstate->N), Int64GetDatum(transstate->N))); MemoryContextSwitchTo(old_context); diff --git a/contrib/babelfishpg_tds/src/backend/fault_injection/fault_injection.c b/contrib/babelfishpg_tds/src/backend/fault_injection/fault_injection.c index 40fccd6170..0a799de273 100644 --- a/contrib/babelfishpg_tds/src/backend/fault_injection/fault_injection.c +++ b/contrib/babelfishpg_tds/src/backend/fault_injection/fault_injection.c @@ -35,10 +35,10 @@ PG_FUNCTION_INFO_V1(inject_fault_status); PG_FUNCTION_INFO_V1(trigger_test_fault); PG_FUNCTION_INFO_V1(inject_fault_status_all); -bool trigger_fault_injection = true; -static HTAB *faultInjectorHash = NULL; +bool trigger_fault_injection = true; +static HTAB *faultInjectorHash = NULL; -int tamperByte = INVALID_TAMPER_BYTE; +int tamperByte = INVALID_TAMPER_BYTE; /* * FaultInjectionHashInit - initialize the hash @@ -46,8 +46,8 @@ int tamperByte = INVALID_TAMPER_BYTE; static void FaultInjectionHashInit() { - HASHCTL hash_ctl; - MemoryContext oldContext; + HASHCTL hash_ctl; + MemoryContext oldContext; oldContext = MemoryContextSwitchTo(TopMemoryContext); /* Local cache */ @@ -55,9 +55,9 @@ FaultInjectionHashInit() hash_ctl.keysize = FAULT_NAME_MAX_LENGTH; hash_ctl.entrysize = sizeof(FaultInjectorEntry_s); faultInjectorHash = hash_create("Fault Injection Cache", - 16, - &hash_ctl, - HASH_ELEM | HASH_STRINGS); + 16, + &hash_ctl, + HASH_ELEM | HASH_STRINGS); MemoryContextSwitchTo(oldContext); } @@ -81,10 +81,10 @@ FaultInjectionInitialize() if (entry->type == InvalidType) break; new_entry = (FaultInjectorEntry_s *) hash_search( - faultInjectorHash, - (void *) entry->faultName, //key - HASH_ENTER, - &foundPtr); + faultInjectorHash, + (void *) entry->faultName, //key + HASH_ENTER, + &foundPtr); /* should not try to insert same entry multiple times */ Assert(foundPtr == false); @@ -100,7 +100,7 @@ FaultInjectionInitialize() new_entry->fault_callback = entry->fault_callback; i++; - } while(true); + } while (true); } /* @@ -133,9 +133,9 @@ FaultInjectionLookupHashEntry(const char *faultName) static void FaultInjectionEnableTest(FaultInjectorEntry_s *entry) { - List *list = FaultInjectionTypes[entry->type].injected_entries; - ListCell *lc; - MemoryContext oldContext; + List *list = FaultInjectionTypes[entry->type].injected_entries; + ListCell *lc; + MemoryContext oldContext; foreach(lc, list) @@ -154,8 +154,8 @@ FaultInjectionEnableTest(FaultInjectorEntry_s *entry) static inline void FaultInjectionDisableTest(FaultInjectorEntry_s *entry) { - ListCell *lc; - List *list = FaultInjectionTypes[entry->type].injected_entries; + ListCell *lc; + List *list = FaultInjectionTypes[entry->type].injected_entries; if (list_length(list) == 1) { @@ -175,7 +175,7 @@ FaultInjectionDisableTest(FaultInjectorEntry_s *entry) FaultInjectionTypes[entry->type].injected_entries = list; } -static char* +static char * FetchFaultStatus(char *faultName) { StringInfo buf = makeStringInfo(); @@ -213,7 +213,7 @@ InjectFault(const char *faultName, int num_occurrences, int tamper_byte) appendStringInfo(buf, "disabled"); else if (tamperByte != INVALID_TAMPER_BYTE) appendStringInfo(buf, "enabled, pending occurrences: %d, tamper byte value: %d", - entry->num_occurrences, tamperByte); + entry->num_occurrences, tamperByte); else appendStringInfo(buf, "enabled, pending occurrences: %d", entry->num_occurrences); @@ -223,9 +223,9 @@ InjectFault(const char *faultName, int num_occurrences, int tamper_byte) void TriggerFault(FaultInjectorType_e type, void *arg) { - List *list = FaultInjectionTypes[type].injected_entries; - List *tmp_list = NIL; - ListCell *lc; + List *list = FaultInjectionTypes[type].injected_entries; + List *tmp_list = NIL; + ListCell *lc; /* if triggering is disabled, return */ if (!trigger_fault_injection || list_length(list) == 0) @@ -317,7 +317,7 @@ TriggerFault(FaultInjectorType_e type, void *arg) * * It enables the faults with occurences as 1 */ -static char* +static char * InjectFaultAll(bool enable) { int i = 0; @@ -338,7 +338,7 @@ InjectFaultAll(bool enable) pfree(ret); i++; - } while(true); + } while (true); appendStringInfo(response, "success"); @@ -352,7 +352,7 @@ inject_fault(PG_FUNCTION_ARGS) int num_occurrences = PG_GETARG_INT32(1); char *response; int nargs = PG_NARGS(); - int tamper_byte = INVALID_TAMPER_BYTE; + int tamper_byte = INVALID_TAMPER_BYTE; if (nargs > 2) tamper_byte = PG_GETARG_INT32(2); diff --git a/contrib/babelfishpg_tds/src/backend/fault_injection/fault_injection_tests.c b/contrib/babelfishpg_tds/src/backend/fault_injection/fault_injection_tests.c index 7fc34336db..f64ca58222 100644 --- a/contrib/babelfishpg_tds/src/backend/fault_injection/fault_injection_tests.c +++ b/contrib/babelfishpg_tds/src/backend/fault_injection/fault_injection_tests.c @@ -29,7 +29,7 @@ static void test_fault1(void *arg, int *num_occurrences) { - StringInfo buf = (StringInfo) arg; + StringInfo buf = (StringInfo) arg; (*num_occurrences) -= 1; @@ -42,7 +42,7 @@ test_fault1(void *arg, int *num_occurrences) static void test_fault2(void *arg, int *num_occurrences) { - StringInfo buf = (StringInfo) arg; + StringInfo buf = (StringInfo) arg; (*num_occurrences) -= 1; @@ -61,13 +61,13 @@ static void tamper_request_sequential(void *arg, char tamper_byte) { StringInfo buf, - tmp; - MemoryContext oldcontext; - int i; + tmp; + MemoryContext oldcontext; + int i; - struct TdsMessageWrapper *wrapper = (struct TdsMessageWrapper *) arg; - uint64_t offset = 0; - uint32_t tdsVersion = GetClientTDSVersion(); + struct TdsMessageWrapper *wrapper = (struct TdsMessageWrapper *) arg; + uint64_t offset = 0; + uint32_t tdsVersion = GetClientTDSVersion(); /* Skip if its an Attention Request. */ if (wrapper->messageType == TDS_ATTENTION) @@ -81,9 +81,10 @@ tamper_request_sequential(void *arg, char tamper_byte) * Skip the offset part, otherwise, we'll throw FATAL error and terminate * the connection * - * Note: In the ALL_HEADERS rule, the Query Notifications header and the Transaction - * Descriptor header were introduced in TDS 7.2. We need to to Process them only - * for TDS versions more than or equal to 7.2, otherwise we do not increment the offset. + * Note: In the ALL_HEADERS rule, the Query Notifications header and the + * Transaction Descriptor header were introduced in TDS 7.2. We need to to + * Process them only for TDS versions more than or equal to 7.2, otherwise + * we do not increment the offset. */ if (tdsVersion > TDS_VERSION_7_1_1) offset = ProcessStreamHeaders(buf); @@ -97,12 +98,12 @@ tamper_request_sequential(void *arg, char tamper_byte) switch (wrapper->messageType) { - case TDS_QUERY: /* Simple SQL BATCH */ + case TDS_QUERY: /* Simple SQL BATCH */ { (void) GetSQLBatchRequest(tmp); } break; - case TDS_RPC: /* Remote procedure call */ + case TDS_RPC: /* Remote procedure call */ { (void) GetRPCRequest(tmp); } @@ -152,7 +153,7 @@ static void tamper_rpc_request(void *arg, uint64_t offset, int tamper_byte) { struct TdsMessageWrapper *wrapper = (struct TdsMessageWrapper *) arg; - MemoryContext oldcontext = MemoryContextSwitchTo(MessageContext); + MemoryContext oldcontext = MemoryContextSwitchTo(MessageContext); StringInfo buf = wrapper->message; StringInfo tmp = makeStringInfo(); @@ -182,7 +183,7 @@ tamper_rpc_request(void *arg, uint64_t offset, int tamper_byte) static void pre_parsing_tamper_rpc_request_sptype(void *arg, int *num_occurrences) { - uint64_t offset = 0; + uint64_t offset = 0; struct TdsMessageWrapper *wrapper = (struct TdsMessageWrapper *) arg; if (wrapper->messageType != TDS_RPC) @@ -193,7 +194,7 @@ pre_parsing_tamper_rpc_request_sptype(void *arg, int *num_occurrences) if (GetClientTDSVersion() > TDS_VERSION_7_1_1) offset = ProcessStreamHeaders(wrapper->message); - offset += 2; /* Skip length. */ + offset += 2; /* Skip length. */ if (tamperByte != INVALID_TAMPER_BYTE) tamper_rpc_request(arg, offset, tamperByte); @@ -233,37 +234,49 @@ throw_error_comm(void *arg, int *num_occurrences) } static void -throw_error_buffer(void *arg ,int *num_occurrences) +throw_error_buffer(void *arg, int *num_occurrences) { - char buffer[3] = {'\0'}; - int can = 0; - char tem[10] = "aaaaaaaaaa"; + char buffer[3] = {'\0'}; + int can = 0; + char tem[10] = "aaaaaaaaaa"; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Warray-bounds" #pragma GCC diagnostic ignored "-Wstringop-overflow" - memcpy(buffer,tem,10); + memcpy(buffer, tem, 10); #pragma GCC diagnostic pop - if (can !=0) - elog(LOG,"Buffer overflowed \n"); + if (can != 0) + elog(LOG, "Buffer overflowed \n"); else - elog(LOG,"Did not Overflow \n"); + elog(LOG, "Did not Overflow \n"); } + /* * Type declarations * * Format: {Enum type, Type name, Callback list} * - * Enum type: type from FaultInjectorType_e + * Enum type: type from FaultInjectorType_e * Type name: user visible name for this type * Callback list: fault callback list for this type; set it to NIL */ -TEST_TYPE_LIST = { - {TestType, "Test", NIL}, - {ParseHeaderType, "TDS request header", NIL}, - {PreParsingType, "TDS pre-parsing", NIL}, - {PostParsingType, "TDS post-parsing", NIL}, - {ParseRpcType, "TDS RPC Parsing", NIL} +TEST_TYPE_LIST = +{ + { + TestType, "Test", NIL + }, + { + ParseHeaderType, "TDS request header", NIL + }, + { + PreParsingType, "TDS pre-parsing", NIL + }, + { + PostParsingType, "TDS post-parsing", NIL + }, + { + ParseRpcType, "TDS RPC Parsing", NIL + } }; /* @@ -275,15 +288,36 @@ TEST_TYPE_LIST = { * Type name: type of the test * Callback function: callback function executed when this test is triggered */ -TEST_LIST = { - {"test_fault1", TestType, 0, &test_fault1}, - {"test_fault2", TestType, 0, &test_fault2}, - {"tds_comm_throw_error", ParseHeaderType, 0, &throw_error_comm}, - {"pre_parsing_tamper_request", PreParsingType, 0, &pre_parsing_tamper_request}, - {"pre_parsing_tamper_rpc_request_sptype", PreParsingType, 0, &pre_parsing_tamper_rpc_request_sptype}, - {"parsing_tamper_rpc_parameter_datatype", ParseRpcType, 0, &parsing_tamper_rpc_parameter_datatype}, - {"pre_parsing_throw_error", PreParsingType, 0, &throw_error}, - {"post_parsing_throw_error", PostParsingType, 0, &throw_error}, - {"buffer_overflow_test",PreParsingType,0, &throw_error_buffer}, - {"", InvalidType, 0, NULL} /* keep this as last */ +TEST_LIST = +{ + { + "test_fault1", TestType, 0, &test_fault1 + }, + { + "test_fault2", TestType, 0, &test_fault2 + }, + { + "tds_comm_throw_error", ParseHeaderType, 0, &throw_error_comm + }, + { + "pre_parsing_tamper_request", PreParsingType, 0, &pre_parsing_tamper_request + }, + { + "pre_parsing_tamper_rpc_request_sptype", PreParsingType, 0, &pre_parsing_tamper_rpc_request_sptype + }, + { + "parsing_tamper_rpc_parameter_datatype", ParseRpcType, 0, &parsing_tamper_rpc_parameter_datatype + }, + { + "pre_parsing_throw_error", PreParsingType, 0, &throw_error + }, + { + "post_parsing_throw_error", PostParsingType, 0, &throw_error + }, + { + "buffer_overflow_test", PreParsingType, 0, &throw_error_buffer + }, + { + "", InvalidType, 0, NULL + } /* keep this as last */ }; diff --git a/contrib/babelfishpg_tds/src/backend/tds/err_handler.c b/contrib/babelfishpg_tds/src/backend/tds/err_handler.c index 5224f5ef61..462d0e36dc 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/err_handler.c +++ b/contrib/babelfishpg_tds/src/backend/tds/err_handler.c @@ -9,7 +9,7 @@ #include "storage/proc.h" #include "utils/elog.h" #include "utils/hsearch.h" -#include "utils/palloc.h" /* Needed for pstrdup() */ +#include "utils/palloc.h" /* Needed for pstrdup() */ #include "src/include/tds_int.h" #include "src/include/tds_response.h" @@ -18,13 +18,13 @@ static bool is_user_defined_error(int pg_error_code); -bool tds_disable_error_log_hook = false; +bool tds_disable_error_log_hook = false; static HTAB *error_map_hash = NULL; extern bool GetTdsEstateErrorData(int *number, int *severity, int *state); error_map_details error_list[] = { - #include "src/include/error_mapping.h" +#include "src/include/error_mapping.h" {"00000", NULL, 0, 0, NULL} }; @@ -43,17 +43,19 @@ get_mapped_error_list() int * get_mapped_tsql_error_code_list() { - int i; - int *list; /* Temp list to store list of mapped sql error codes and its length. */ - Bitmapset *tmp = NULL; /* To store the unique sql error codes. */ - int tmp_len = 0; /* To store number of unique sql error codes. */ - int prev_idx = -1; /* To retrieve all members of set. */ - int len = sizeof(error_list)/sizeof(error_list[0]); + int i; + int *list; /* Temp list to store list of mapped sql error + * codes and its length. */ + Bitmapset *tmp = NULL; /* To store the unique sql error codes. */ + int tmp_len = 0; /* To store number of unique sql error codes. */ + int prev_idx = -1; /* To retrieve all members of set. */ + int len = sizeof(error_list) / sizeof(error_list[0]); + for (i = 0; i < len - 1; i++) { if (!bms_is_member(error_list[i].tsql_error_code, tmp)) { - /* If given sql error code is not already present in set.*/ + /* If given sql error code is not already present in set. */ tmp = bms_add_member(tmp, error_list[i].tsql_error_code); tmp_len += 1; } @@ -78,42 +80,45 @@ get_mapped_tsql_error_code_list() void load_error_mapping() { - HASHCTL hashCtl; - int i, len = sizeof(error_list)/sizeof(error_list[0]); + HASHCTL hashCtl; + int i, + len = sizeof(error_list) / sizeof(error_list[0]); /* For now, we don't allow user to update the mapping. */ if (error_map_hash != NULL) - return ; + return; MemSet(&hashCtl, 0, sizeof(hashCtl)); hashCtl.keysize = sizeof(error_map_key); hashCtl.entrysize = sizeof(error_map); hashCtl.hcxt = TdsMemoryContext; error_map_hash = hash_create("Error code mapping cache", - len, - &hashCtl, - HASH_ELEM | HASH_CONTEXT | HASH_BLOBS); + len, + &hashCtl, + HASH_ELEM | HASH_CONTEXT | HASH_BLOBS); for (i = 0; i < len - 1; i++) { error_map_info map_info; error_map_key key_info; - bool found; - key_info.sqlerrcode = MAKE_SQLSTATE(error_list[i].sql_state[0], - error_list[i].sql_state[1], - error_list[i].sql_state[2], - error_list[i].sql_state[3], - error_list[i].sql_state[4]); - key_info.message_hash = (uint32) hash_any((unsigned char *)error_list[i].error_message, strlen(error_list[i].error_message)); + bool found; + + key_info.sqlerrcode = MAKE_SQLSTATE(error_list[i].sql_state[0], + error_list[i].sql_state[1], + error_list[i].sql_state[2], + error_list[i].sql_state[3], + error_list[i].sql_state[4]); + key_info.message_hash = (uint32) hash_any((unsigned char *) error_list[i].error_message, strlen(error_list[i].error_message)); map_info = (error_map_info) hash_search(error_map_hash, - &key_info, - HASH_ENTER, - &found); + &key_info, + HASH_ENTER, + &found); if (found) { error_map_node *head = map_info->head; - error_map_node *tmp = (error_map_node *)palloc0(sizeof(error_map_node)); - tmp->error_msg_keywords = error_list[i].error_msg_keywords; + error_map_node *tmp = (error_map_node *) palloc0(sizeof(error_map_node)); + + tmp->error_msg_keywords = error_list[i].error_msg_keywords; tmp->tsql_error_code = error_list[i].tsql_error_code; tmp->tsql_error_severity = error_list[i].tsql_error_severity; tmp->next = head; @@ -121,8 +126,9 @@ load_error_mapping() } else { - error_map_node *tmp = (error_map_node *)palloc0(sizeof(error_map_node)); - tmp->error_msg_keywords = error_list[i].error_msg_keywords; + error_map_node *tmp = (error_map_node *) palloc0(sizeof(error_map_node)); + + tmp->error_msg_keywords = error_list[i].error_msg_keywords; tmp->tsql_error_code = error_list[i].tsql_error_code; tmp->tsql_error_severity = error_list[i].tsql_error_severity; tmp->next = NULL; @@ -133,21 +139,21 @@ load_error_mapping() bool get_tsql_error_details(ErrorData *edata, - int *tsql_error_code, - int *tsql_error_severity, - int *tsql_error_state, - char *error_context) + int *tsql_error_code, + int *tsql_error_severity, + int *tsql_error_state, + char *error_context) { - error_map_info map_info; - error_map_key key_info; - bool found; + error_map_info map_info; + error_map_key key_info; + bool found; /* Skip mapping if this is a user-defined error */ if (is_user_defined_error(edata->sqlerrcode)) { if (GetTdsEstateErrorData(tsql_error_code, tsql_error_severity, tsql_error_state)) return true; - + /* Failed to find reliable user-defined error data, use default values */ *tsql_error_code = 50000; *tsql_error_severity = 16; @@ -156,25 +162,25 @@ get_tsql_error_details(ErrorData *edata, return true; } - /* - * This condition is useful when error is thrown before - * initialising the hash table. In that case, load hash - * table immediately. + /* + * This condition is useful when error is thrown before initialising the + * hash table. In that case, load hash table immediately. */ if (error_map_hash == NULL) { MemoryContext oldContext = MemoryContextSwitchTo(TdsMemoryContext); + load_error_mapping(); MemoryContextSwitchTo(oldContext); } - key_info.message_hash = (uint32) hash_any((unsigned char *)edata->message_id, (edata->message_id != NULL) ? strlen(edata->message_id) : 0); + key_info.message_hash = (uint32) hash_any((unsigned char *) edata->message_id, (edata->message_id != NULL) ? strlen(edata->message_id) : 0); key_info.sqlerrcode = edata->sqlerrcode; map_info = (error_map_info) hash_search(error_map_hash, - &key_info, - HASH_FIND, - &found); + &key_info, + HASH_FIND, + &found); /* For all system generated errors, error state is default to be 1 */ *tsql_error_state = 1; @@ -188,13 +194,13 @@ get_tsql_error_details(ErrorData *edata, TDSInstrumentation(INSTR_TDS_UNMAPPED_ERROR); elog(LOG, "Unmapped error found. Code: %d, Message: %s, File: %s, Line: %d, Context: %s", - edata->sqlerrcode, edata->message, edata->filename, edata->lineno, error_context); + edata->sqlerrcode, edata->message, edata->filename, edata->lineno, error_context); return false; } else { - bool flag = false; + bool flag = false; error_map_node *tmp = map_info->head; while (tmp) @@ -210,17 +216,22 @@ get_tsql_error_details(ErrorData *edata, } else { - /* All key words should be matched to qualify it as a correct tsql error details.*/ - char *key_word; - char *tmp_keywords = pstrdup(tmp->error_msg_keywords); + /* + * All key words should be matched to qualify it as a correct + * tsql error details. + */ + char *key_word; + char *tmp_keywords = pstrdup(tmp->error_msg_keywords); + flag = true; + /* * According to document of strtok(), passed string is modify - * by being broken into smaller strings (tokens). - * Certian platforms does not allow to modify the string - * literal. Attempting to do so will result in segmentation - * fault. So, here we are storing string literal into temp string - * and then passing it into strtok(). + * by being broken into smaller strings (tokens). Certian + * platforms does not allow to modify the string literal. + * Attempting to do so will result in segmentation fault. So, + * here we are storing string literal into temp string and + * then passing it into strtok(). */ key_word = strtok(tmp_keywords, "#"); while (key_word != NULL) @@ -243,15 +254,17 @@ get_tsql_error_details(ErrorData *edata, } tmp = tmp->next; } + /* - * If appropriate tsql error code could not be found then use PG error code as a default. + * If appropriate tsql error code could not be found then use PG error + * code as a default. */ if (!flag) { TDSInstrumentation(INSTR_TDS_UNMAPPED_ERROR); elog(LOG, "Unmapped error found. Code: %d, Message: %s, File: %s, Line: %d, Context: %s", - edata->sqlerrcode, edata->message, edata->filename, edata->lineno, error_context); + edata->sqlerrcode, edata->message, edata->filename, edata->lineno, error_context); *tsql_error_code = ERRCODE_PLTSQL_ERROR_NOT_MAPPED; *tsql_error_severity = 16; @@ -264,7 +277,10 @@ get_tsql_error_details(ErrorData *edata, void emit_tds_log(ErrorData *edata) { - int tsql_error_code, tsql_error_sev, tsql_error_state, error_lineno; + int tsql_error_code, + tsql_error_sev, + tsql_error_state, + error_lineno; /* * We've already sent the error token to the TDS client. We don't have to @@ -291,8 +307,9 @@ emit_tds_log(ErrorData *edata) /* * It is possible that we fail while processing the error (for example, * because of encoding conversion failure). Therefore, we place a PG_TRY - * block so that we can log the internal error and tds_disable_error_log_hook - * can be set to false so that further errors can be sent to client. + * block so that we can log the internal error and + * tds_disable_error_log_hook can be set to false so that further errors + * can be sent to client. */ PG_TRY(); @@ -314,11 +331,11 @@ emit_tds_log(ErrorData *edata) } TdsSendError(tsql_error_code, tsql_error_state, tsql_error_sev, - edata->message, error_lineno); + edata->message, error_lineno); /* - * If we've not reached the main query loop yet, flush the error message - * immediately. + * If we've not reached the main query loop yet, flush the error + * message immediately. */ if (!IsNormalProcessingMode()) { @@ -333,7 +350,8 @@ emit_tds_log(ErrorData *edata) PG_CATCH(); { /* Log the internal error message */ - ErrorData *next_edata; + ErrorData *next_edata; + next_edata = CopyErrorData(); elog(LOG, "internal error occurred: %s", next_edata->message); FreeErrorData(next_edata); @@ -360,6 +378,6 @@ is_user_defined_error(int pg_error_code) if (pg_error_code == ERRCODE_PLTSQL_RAISERROR || pg_error_code == ERRCODE_PLTSQL_THROW) return true; - + return false; } diff --git a/contrib/babelfishpg_tds/src/backend/tds/guc.c b/contrib/babelfishpg_tds/src/backend/tds/guc.c index ce7b46b48f..706daa093d 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/guc.c +++ b/contrib/babelfishpg_tds/src/backend/tds/guc.c @@ -26,25 +26,25 @@ #include "src/include/guc.h" /* Global variables */ -int pe_port; -char *pe_listen_addrs = NULL; -char *pe_unix_socket_directories = NULL; -int pe_unix_socket_permissions = 0; -char *pe_unix_socket_group = NULL; - -char *default_server_name = NULL; -int tds_default_numeric_precision = 38; -int tds_default_numeric_scale = 8; -bool tds_ssl_encrypt = false; -int tds_default_protocol_version = 0; -int32_t tds_default_packet_size = 4096; -int tds_debug_log_level = 1; -char* product_version = "default"; +int pe_port; +char *pe_listen_addrs = NULL; +char *pe_unix_socket_directories = NULL; +int pe_unix_socket_permissions = 0; +char *pe_unix_socket_group = NULL; + +char *default_server_name = NULL; +int tds_default_numeric_precision = 38; +int tds_default_numeric_scale = 8; +bool tds_ssl_encrypt = false; +int tds_default_protocol_version = 0; +int32_t tds_default_packet_size = 4096; +int tds_debug_log_level = 1; +char *product_version = "default"; #ifdef FAULT_INJECTOR static bool TdsFaultInjectionEnabled = false; #endif -bool enable_drop_babelfish_role = false; +bool enable_drop_babelfish_role = false; const struct config_enum_entry ssl_protocol_versions_info[] = { {"", PG_TLS_ANY, false}, @@ -78,7 +78,7 @@ TdsSslProtocolMinVersionCheck(int *newvalue, void **extra, GucSource source) else { GUC_check_errmsg("TDS SSL Min Protocol Version 0x%X more than TDS SSL Max Protocol Version 0x%x", - *newvalue, tds_ssl_max_protocol_version); + *newvalue, tds_ssl_max_protocol_version); return false; } } @@ -95,7 +95,7 @@ TdsSslProtocolMaxVersionCheck(int *newvalue, void **extra, GucSource source) else { GUC_check_errmsg("TDS SSL Max Protocol Version 0x%X less than TDS SSL Min Protocol Version 0x%x", - *newvalue, tds_ssl_min_protocol_version); + *newvalue, tds_ssl_min_protocol_version); return false; } } @@ -113,73 +113,75 @@ TdsGucDefaultPacketSizeCheck(int *newvalue, void **extra, GucSource source) return true; } -static bool +static bool check_version_number(char **newval, void **extra, GucSource source) { - char *copy_version_number; - char *token; - int part = 0, - len = 0; + char *copy_version_number; + char *token; + int part = 0, + len = 0; Assert(*newval != NULL); - if(pg_strcasecmp(*newval,"default") == 0) + if (pg_strcasecmp(*newval, "default") == 0) return true; len = strlen(*newval); copy_version_number = palloc0(len + 1); memcpy(copy_version_number, *newval, len); for (token = strtok(copy_version_number, "."); token; token = strtok(NULL, ".")) - { + { /* check each token contains only digits */ - if(strspn(token, "0123456789") != strlen(token)) + if (strspn(token, "0123456789") != strlen(token)) { ereport(WARNING, - (errmsg("babelfishpg_tds.product_version cannot be set. Please enter 4 valid numbers separated by \'.\' "))); + (errmsg("babelfishpg_tds.product_version cannot be set. Please enter 4 valid numbers separated by \'.\' "))); *newval = product_version; return true; } - + /* check Major Version is between 11 and 16 */ - if(part == 0 && (11 > atoi(token) || atoi(token) > 16)) + if (part == 0 && (11 > atoi(token) || atoi(token) > 16)) { ereport(WARNING, - (errmsg("babelfishpg_tds.product_version cannot be set. Please enter a valid major version number between 11 and 16"))); + (errmsg("babelfishpg_tds.product_version cannot be set. Please enter a valid major version number between 11 and 16"))); *newval = product_version; return true; } + /* - * Minor Version takes 1 byte in PreLogin message when doing handshake, - * here to check it is between 0 and 0xFF + * Minor Version takes 1 byte in PreLogin message when doing + * handshake, here to check it is between 0 and 0xFF */ - if(part == 1 && atoi(token) > 0xFF) + if (part == 1 && atoi(token) > 0xFF) { ereport(WARNING, - (errmsg("babelfishpg_tds.product_version cannot be set. Please enter a valid minor version number between 0 and 255"))); + (errmsg("babelfishpg_tds.product_version cannot be set. Please enter a valid minor version number between 0 and 255"))); *newval = product_version; return true; } + /* - * Micro Version takes 2 bytes in PreLogin message when doing handshake, - * here to check it is between 0 and 0xFFFF + * Micro Version takes 2 bytes in PreLogin message when doing + * handshake, here to check it is between 0 and 0xFFFF */ - if(part == 2 && atoi(token) > 0xFFFF) + if (part == 2 && atoi(token) > 0xFFFF) { ereport(WARNING, - (errmsg("babelfishpg_tds.product_version cannot be set. Please enter a valid micro version number between 0 and 65535"))); + (errmsg("babelfishpg_tds.product_version cannot be set. Please enter a valid micro version number between 0 and 65535"))); *newval = product_version; return true; } part++; } - if(part != 4) + if (part != 4) { ereport(WARNING, - (errmsg("babelfishpg_tds.product_version cannot be set. Please enter 4 valid numbers separated by \'.\' "))); + (errmsg("babelfishpg_tds.product_version cannot be set. Please enter 4 valid numbers separated by \'.\' "))); *newval = product_version; return true; } - return true; + return true; } /* @@ -190,198 +192,198 @@ TdsDefineGucs(void) { /* Define TDS specific GUCs */ DefineCustomIntVariable( - "babelfishpg_tds.port", - gettext_noop("Sets the TDS TCP port the server listens on."), - NULL, - &pe_port, - 1433, 1024, 65536, - PGC_POSTMASTER, - GUC_NOT_IN_SAMPLE, - NULL, NULL, NULL); + "babelfishpg_tds.port", + gettext_noop("Sets the TDS TCP port the server listens on."), + NULL, + &pe_port, + 1433, 1024, 65536, + PGC_POSTMASTER, + GUC_NOT_IN_SAMPLE, + NULL, NULL, NULL); DefineCustomStringVariable( - "babelfishpg_tds.listen_addresses", - gettext_noop("Sets the host name or IP address(es) to listen TDS to."), - NULL, - &pe_listen_addrs, - "*", - PGC_POSTMASTER, - GUC_NOT_IN_SAMPLE, - NULL, NULL, NULL); + "babelfishpg_tds.listen_addresses", + gettext_noop("Sets the host name or IP address(es) to listen TDS to."), + NULL, + &pe_listen_addrs, + "*", + PGC_POSTMASTER, + GUC_NOT_IN_SAMPLE, + NULL, NULL, NULL); DefineCustomStringVariable( - "babelfishpg_tds.unix_socket_directories", - gettext_noop("TDS server unix socket directories."), - NULL, - &pe_unix_socket_directories, - NULL, - PGC_POSTMASTER, - GUC_NOT_IN_SAMPLE, - NULL, NULL, NULL); + "babelfishpg_tds.unix_socket_directories", + gettext_noop("TDS server unix socket directories."), + NULL, + &pe_unix_socket_directories, + NULL, + PGC_POSTMASTER, + GUC_NOT_IN_SAMPLE, + NULL, NULL, NULL); DefineCustomIntVariable( - "babelfishpg_tds.unix_socket_permissions", - gettext_noop("TDS server unix socket permissions."), - NULL, - &pe_unix_socket_permissions, - 0777, 0, 0777, - PGC_POSTMASTER, - GUC_NOT_IN_SAMPLE, - NULL, NULL, NULL); + "babelfishpg_tds.unix_socket_permissions", + gettext_noop("TDS server unix socket permissions."), + NULL, + &pe_unix_socket_permissions, + 0777, 0, 0777, + PGC_POSTMASTER, + GUC_NOT_IN_SAMPLE, + NULL, NULL, NULL); DefineCustomStringVariable( - "babelfishpg_tds.unix_socket_group", - gettext_noop("TDS server unix socket group."), - NULL, - &pe_unix_socket_group, - NULL, - PGC_POSTMASTER, - GUC_NOT_IN_SAMPLE, - NULL, NULL, NULL); + "babelfishpg_tds.unix_socket_group", + gettext_noop("TDS server unix socket group."), + NULL, + &pe_unix_socket_group, + NULL, + PGC_POSTMASTER, + GUC_NOT_IN_SAMPLE, + NULL, NULL, NULL); DefineCustomStringVariable( - "babelfishpg_tds.default_server_name", - gettext_noop("Predefined Babelfish default server name"), - NULL, - &default_server_name, - TDS_DEFAULT_SERVER_NAME, - PGC_SIGHUP, - GUC_NOT_IN_SAMPLE, - NULL, NULL, NULL); + "babelfishpg_tds.default_server_name", + gettext_noop("Predefined Babelfish default server name"), + NULL, + &default_server_name, + TDS_DEFAULT_SERVER_NAME, + PGC_SIGHUP, + GUC_NOT_IN_SAMPLE, + NULL, NULL, NULL); DefineCustomStringVariable("babelfishpg_tds.product_version", - gettext_noop("Sets the Product Version returned by Babelfish"), - NULL, - &product_version, - "default", - PGC_USERSET, - GUC_NOT_IN_SAMPLE, - check_version_number, NULL, NULL); + gettext_noop("Sets the Product Version returned by Babelfish"), + NULL, + &product_version, + "default", + PGC_USERSET, + GUC_NOT_IN_SAMPLE, + check_version_number, NULL, NULL); DefineCustomIntVariable( - "babelfishpg_tds.tds_default_numeric_precision", - gettext_noop("Sets the default precision of numeric type to be sent in" - "the TDS column metadata if the engine does not specify one."), - NULL, - &tds_default_numeric_precision, - 38, 1, 38, - PGC_SIGHUP, - GUC_NOT_IN_SAMPLE, - NULL, NULL, NULL); + "babelfishpg_tds.tds_default_numeric_precision", + gettext_noop("Sets the default precision of numeric type to be sent in" + "the TDS column metadata if the engine does not specify one."), + NULL, + &tds_default_numeric_precision, + 38, 1, 38, + PGC_SIGHUP, + GUC_NOT_IN_SAMPLE, + NULL, NULL, NULL); DefineCustomIntVariable( - "babelfishpg_tds.tds_default_numeric_scale", - gettext_noop("Sets the default scale of numeric type to be sent in" - "the TDS column metadata if the engine does not specify one."), - NULL, - &tds_default_numeric_scale, - 8, 0, 38, - PGC_SIGHUP, - GUC_NOT_IN_SAMPLE, - NULL, NULL, NULL); + "babelfishpg_tds.tds_default_numeric_scale", + gettext_noop("Sets the default scale of numeric type to be sent in" + "the TDS column metadata if the engine does not specify one."), + NULL, + &tds_default_numeric_scale, + 8, 0, 38, + PGC_SIGHUP, + GUC_NOT_IN_SAMPLE, + NULL, NULL, NULL); DefineCustomBoolVariable( - "babelfishpg_tds.tds_ssl_encrypt", - gettext_noop("Sets the SSL Encryption option"), - NULL, - &tds_ssl_encrypt, - false, - PGC_SIGHUP, - GUC_NOT_IN_SAMPLE, - NULL, NULL, NULL); + "babelfishpg_tds.tds_ssl_encrypt", + gettext_noop("Sets the SSL Encryption option"), + NULL, + &tds_ssl_encrypt, + false, + PGC_SIGHUP, + GUC_NOT_IN_SAMPLE, + NULL, NULL, NULL); DefineCustomEnumVariable( - "babelfishpg_tds.tds_default_protocol_version", - gettext_noop("Sets a default TDS protocol version for" - "all the clients being connected"), - NULL, - &tds_default_protocol_version, - TDS_DEFAULT_VERSION, tds_protocol_versions_info, - PGC_SIGHUP, - GUC_NOT_IN_SAMPLE, - NULL, - NULL, - NULL); + "babelfishpg_tds.tds_default_protocol_version", + gettext_noop("Sets a default TDS protocol version for" + "all the clients being connected"), + NULL, + &tds_default_protocol_version, + TDS_DEFAULT_VERSION, tds_protocol_versions_info, + PGC_SIGHUP, + GUC_NOT_IN_SAMPLE, + NULL, + NULL, + NULL); DefineCustomEnumVariable( - "babelfishpg_tds.tds_ssl_max_protocol_version", - gettext_noop("Sets the minimum SSL/TLS protocol version to use" - "for tds session."), - NULL, - &tds_ssl_max_protocol_version, - PG_TLS1_2_VERSION, ssl_protocol_versions_info + 1, - PGC_SIGHUP, - GUC_NOT_IN_SAMPLE, - TdsSslProtocolMaxVersionCheck, - NULL, - NULL); + "babelfishpg_tds.tds_ssl_max_protocol_version", + gettext_noop("Sets the minimum SSL/TLS protocol version to use" + "for tds session."), + NULL, + &tds_ssl_max_protocol_version, + PG_TLS1_2_VERSION, ssl_protocol_versions_info + 1, + PGC_SIGHUP, + GUC_NOT_IN_SAMPLE, + TdsSslProtocolMaxVersionCheck, + NULL, + NULL); DefineCustomEnumVariable( - "babelfishpg_tds.tds_ssl_min_protocol_version", - gettext_noop("Sets the minimum SSL/TLS protocol version to use" - "for tds session."), - NULL, - &tds_ssl_min_protocol_version, - PG_TLS1_VERSION, ssl_protocol_versions_info, - PGC_SIGHUP, - GUC_NOT_IN_SAMPLE, - TdsSslProtocolMinVersionCheck, - NULL, - NULL); + "babelfishpg_tds.tds_ssl_min_protocol_version", + gettext_noop("Sets the minimum SSL/TLS protocol version to use" + "for tds session."), + NULL, + &tds_ssl_min_protocol_version, + PG_TLS1_VERSION, ssl_protocol_versions_info, + PGC_SIGHUP, + GUC_NOT_IN_SAMPLE, + TdsSslProtocolMinVersionCheck, + NULL, + NULL); DefineCustomIntVariable( - "babelfishpg_tds.tds_default_packet_size", - gettext_noop("Sets the default packet size for" - "all the clients being connected"), - NULL, - &tds_default_packet_size, - 4096, 512, 32767, - PGC_SIGHUP, - GUC_NOT_IN_SAMPLE, - TdsGucDefaultPacketSizeCheck, - NULL, - NULL); + "babelfishpg_tds.tds_default_packet_size", + gettext_noop("Sets the default packet size for" + "all the clients being connected"), + NULL, + &tds_default_packet_size, + 4096, 512, 32767, + PGC_SIGHUP, + GUC_NOT_IN_SAMPLE, + TdsGucDefaultPacketSizeCheck, + NULL, + NULL); DefineCustomIntVariable( - "babelfishpg_tds.tds_debug_log_level", - gettext_noop("Sets the tds debug log level"), - NULL, - &tds_debug_log_level, - 1, 0, 3, - PGC_SIGHUP, - GUC_NOT_IN_SAMPLE, - NULL, - NULL, - NULL); + "babelfishpg_tds.tds_debug_log_level", + gettext_noop("Sets the tds debug log level"), + NULL, + &tds_debug_log_level, + 1, 0, 3, + PGC_SIGHUP, + GUC_NOT_IN_SAMPLE, + NULL, + NULL, + NULL); /* * Enable user to drop a babelfish role while not in a babelfish setting. */ DefineCustomBoolVariable( - "enable_drop_babelfish_role", - gettext_noop("Enables dropping a babelfish role"), - NULL, - &enable_drop_babelfish_role, - false, - PGC_USERSET, - GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, - NULL, - NULL); + "enable_drop_babelfish_role", + gettext_noop("Enables dropping a babelfish role"), + NULL, + &enable_drop_babelfish_role, + false, + PGC_USERSET, + GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, + NULL, + NULL); /* the guc is accessible only if it's compiled with fault injection flag */ #ifdef FAULT_INJECTOR if (!TdsFaultInjectionEnabled) { DefineCustomBoolVariable( - "babelfishpg_tds.trigger_fault_enabled", - gettext_noop("Enable fault injection triggers"), - NULL, - &trigger_fault_injection, - true, - PGC_SUSET, - GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE, - NULL, NULL, NULL); + "babelfishpg_tds.trigger_fault_enabled", + gettext_noop("Enable fault injection triggers"), + NULL, + &trigger_fault_injection, + true, + PGC_SUSET, + GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE, + NULL, NULL, NULL); TdsFaultInjectionEnabled = true; } #endif diff --git a/contrib/babelfishpg_tds/src/backend/tds/support_funcs.c b/contrib/babelfishpg_tds/src/backend/tds/support_funcs.c index df3f599ae3..a8ab3b16a8 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/support_funcs.c +++ b/contrib/babelfishpg_tds/src/backend/tds/support_funcs.c @@ -13,7 +13,7 @@ /*---- Function declarations ----*/ -static void pe_create_server_ports(void); +static void pe_create_server_ports(void); static int pe_create_server_port(int family, const char *hostName, unsigned short portNumber, const char *unixSocketDir, @@ -32,8 +32,8 @@ static int Setup_AF_UNIX(const char *sock_path); static void pe_create_server_ports(void) { - int status; - bool listen_addr_saved = false; + int status; + bool listen_addr_saved = false; if (ListenAddresses) { @@ -43,7 +43,7 @@ pe_create_server_ports(void) int success = 0; /* Need a modifiable copy of ListenAddresses */ - //rawstring = pstrdup(pe_listen_addrs); + /* rawstring = pstrdup(pe_listen_addrs); */ rawstring = pstrdup(ListenAddresses); /* Parse string into list of hostnames */ diff --git a/contrib/babelfishpg_tds/src/backend/tds/tds-secure-openssl.c b/contrib/babelfishpg_tds/src/backend/tds/tds-secure-openssl.c index 47a5dc2a6f..de80e30a31 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tds-secure-openssl.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tds-secure-openssl.c @@ -50,33 +50,33 @@ #include "src/include/tds_secure.h" #ifdef USE_SSL -static int my_sock_read(BIO *h, char *buf, int size); -static int my_sock_write(BIO *h, const char *buf, int size); +static int my_sock_read(BIO * h, char *buf, int size); +static int my_sock_write(BIO * h, const char *buf, int size); #if 0 // Register tds specific function -static BIO_METHOD *my_BIO_s_socket(void); +static BIO_METHOD * my_BIO_s_socket(void); #endif static int my_SSL_set_fd(Port *port, int fd); -static DH *load_dh_file(char *filename, bool isServerStart); -static DH *load_dh_buffer(const char *, size_t); +static DH * load_dh_file(char *filename, bool isServerStart); +static DH * load_dh_buffer(const char *, size_t); static int ssl_external_passwd_cb(char *buf, int size, int rwflag, void *userdata); static int dummy_ssl_passwd_cb(char *buf, int size, int rwflag, void *userdata); #if 0 static int verify_cb(int, X509_STORE_CTX *); #endif -static void info_cb(const SSL *ssl, int type, int args); -static bool initialize_dh(SSL_CTX *context, bool isServerStart); -static bool initialize_ecdh(SSL_CTX *context, bool isServerStart); +static void info_cb(const SSL * ssl, int type, int args); +static bool initialize_dh(SSL_CTX * context, bool isServerStart); +static bool initialize_ecdh(SSL_CTX * context, bool isServerStart); static const char *SSLerrmessage(unsigned long ecode); -static SSL_CTX *SSL_context = NULL; +static SSL_CTX * SSL_context = NULL; static bool SSL_initialized = false; static bool dummy_ssl_passwd_cb_called = false; static bool ssl_is_server_start; -static BIO_METHOD *my_bio_methods = NULL; +static BIO_METHOD * my_bio_methods = NULL; -static int ssl_protocol_version_to_openssl(int v); +static int ssl_protocol_version_to_openssl(int v); static const char *ssl_protocol_version_to_string(int v); /* ------------------------------------------------------------ */ @@ -85,7 +85,7 @@ static const char *ssl_protocol_version_to_string(int v); int Tds_be_tls_init(bool isServerStart) { - STACK_OF(X509_NAME) *root_cert_list = NULL; + STACK_OF(X509_NAME) * root_cert_list = NULL; SSL_CTX *context; int ssl_ver_min = -1; int ssl_ver_max = -1; @@ -201,16 +201,16 @@ Tds_be_tls_init(bool isServerStart) if (tds_ssl_min_protocol_version) { - int ssl_ver_min = ssl_protocol_version_to_openssl(tds_ssl_min_protocol_version); + int ssl_ver_min = ssl_protocol_version_to_openssl(tds_ssl_min_protocol_version); if (ssl_ver_min == -1) { /*- translator: first %s is a GUC option name, second %s is its value */ ereport(isServerStart ? FATAL : LOG, - (errmsg("\"%s\" setting \"%s\" not supported by this build", - "babelfishpg_tds.tds_ssl_min_protocol_version", - GetConfigOption("babelfishpg_tds.tds_ssl_min_protocol_version", - false, false)))); + (errmsg("\"%s\" setting \"%s\" not supported by this build", + "babelfishpg_tds.tds_ssl_min_protocol_version", + GetConfigOption("babelfishpg_tds.tds_ssl_min_protocol_version", + false, false)))); goto error; } @@ -224,16 +224,16 @@ Tds_be_tls_init(bool isServerStart) if (tds_ssl_max_protocol_version) { - int ssl_ver_max = ssl_protocol_version_to_openssl(tds_ssl_max_protocol_version); + int ssl_ver_max = ssl_protocol_version_to_openssl(tds_ssl_max_protocol_version); if (ssl_ver_max == -1) { /*- translator: first %s is a GUC option name, second %s is its value */ ereport(isServerStart ? FATAL : LOG, - (errmsg("\"%s\" setting \"%s\" not supported by this build", - "babelfishpg_tds.tds_ssl_max_protocol_version", - GetConfigOption("babelfishpg_tds.tds_ssl_max_protocol_version", - false, false)))); + (errmsg("\"%s\" setting \"%s\" not supported by this build", + "babelfishpg_tds.tds_ssl_max_protocol_version", + GetConfigOption("babelfishpg_tds.tds_ssl_max_protocol_version", + false, false)))); goto error; } if (!SSL_CTX_set_max_proto_version(context, ssl_ver_max)) @@ -365,7 +365,7 @@ Tds_be_tls_init(bool isServerStart) } } #if 0 // TDS specific - /* TDS specific - TSQL doesn't support multual certificate authentication */ + /* TDS specific - TSQL doesn't support multual certificate authentication */ if (ssl_ca_file[0]) { /* @@ -386,6 +386,7 @@ Tds_be_tls_init(bool isServerStart) SSL_CTX_set_client_CA_list(context, root_cert_list); } #endif + /* * Success! Replace any existing SSL_context. */ @@ -396,6 +397,7 @@ Tds_be_tls_init(bool isServerStart) ssl_loaded_verify_locations = false; #if 0 // TDS specific + /* * Set flag to remember whether CA store has been loaded into SSL_context. */ @@ -521,19 +523,19 @@ Tds_be_tls_open_server(Port *port) case SSL_ERROR_SSL: switch (ERR_GET_REASON(ecode)) { - /* - * UNSUPPORTED_PROTOCOL, WRONG_VERSION_NUMBER, and - * TLSV1_ALERT_PROTOCOL_VERSION have been observed - * when trying to communicate with an old OpenSSL - * library, or when the client and server specify - * disjoint protocol ranges. NO_PROTOCOLS_AVAILABLE - * occurs if there's a local misconfiguration (which - * can happen despite our checks, if openssl.cnf - * injects a limit we didn't account for). It's not - * very clear what would make OpenSSL return the other - * codes listed here, but a hint about protocol - * versions seems like it's appropriate for all. - */ + /* + * UNSUPPORTED_PROTOCOL, WRONG_VERSION_NUMBER, and + * TLSV1_ALERT_PROTOCOL_VERSION have been observed + * when trying to communicate with an old OpenSSL + * library, or when the client and server specify + * disjoint protocol ranges. NO_PROTOCOLS_AVAILABLE + * occurs if there's a local misconfiguration (which + * can happen despite our checks, if openssl.cnf + * injects a limit we didn't account for). It's not + * very clear what would make OpenSSL return the other + * codes listed here, but a hint about protocol + * versions seems like it's appropriate for all. + */ case SSL_R_NO_PROTOCOLS_AVAILABLE: case SSL_R_UNSUPPORTED_PROTOCOL: case SSL_R_BAD_PROTOCOL_VERSION_NUMBER: @@ -859,7 +861,7 @@ Tds_be_tls_write(Port *port, void *ptr, size_t len, int *waitfor) #endif static int -my_sock_read(BIO *h, char *buf, int size) +my_sock_read(BIO * h, char *buf, int size) { int res = 0; @@ -881,7 +883,7 @@ my_sock_read(BIO *h, char *buf, int size) } static int -my_sock_write(BIO *h, const char *buf, int size) +my_sock_write(BIO * h, const char *buf, int size) { int res = 0; @@ -981,7 +983,7 @@ my_SSL_set_fd(Port *port, int fd) * to verify that the DBA-generated DH parameters file contains * what we expect it to contain. */ -static DH * +static DH * load_dh_file(char *filename, bool isServerStart) { FILE *fp; @@ -1048,7 +1050,7 @@ load_dh_file(char *filename, bool isServerStart) * the hardcoded DH parameters supplied with the backend to prevent * problems. */ -static DH * +static DH * load_dh_buffer(const char *buffer, size_t len) { BIO *bio; @@ -1114,7 +1116,7 @@ dummy_ssl_passwd_cb(char *buf, int size, int rwflag, void *userdata) * for now we accept the default checks. */ static int -verify_cb(int ok, X509_STORE_CTX *ctx) +verify_cb(int ok, X509_STORE_CTX * ctx) { return ok; } @@ -1125,7 +1127,7 @@ verify_cb(int ok, X509_STORE_CTX *ctx) * into the PostgreSQL log. */ static void -info_cb(const SSL *ssl, int type, int args) +info_cb(const SSL * ssl, int type, int args) { const char *desc; @@ -1183,7 +1185,7 @@ info_cb(const SSL *ssl, int type, int args) * information provided. */ static bool -initialize_dh(SSL_CTX *context, bool isServerStart) +initialize_dh(SSL_CTX * context, bool isServerStart) { DH *dh = NULL; @@ -1206,7 +1208,7 @@ initialize_dh(SSL_CTX *context, bool isServerStart) ereport(isServerStart ? FATAL : LOG, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("DH: could not set DH parameters: %s", - SSLerrmessage(ERR_get_error())))); + SSLerrmessage(ERR_get_error())))); DH_free(dh); return false; } @@ -1221,7 +1223,7 @@ initialize_dh(SSL_CTX *context, bool isServerStart) * need to provide the name of the curve to OpenSSL. */ static bool -initialize_ecdh(SSL_CTX *context, bool isServerStart) +initialize_ecdh(SSL_CTX * context, bool isServerStart) { #ifndef OPENSSL_NO_ECDH EC_KEY *ecdh; diff --git a/contrib/babelfishpg_tds/src/backend/tds/tds.c b/contrib/babelfishpg_tds/src/backend/tds/tds.c index 9caca362a0..4002e27179 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tds.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tds.c @@ -83,10 +83,10 @@ typedef struct TdsStatus * use the macros defined below for manipulating st_changecount, rather * than touching it directly. */ - int st_changecount; + int st_changecount; /* The entry is valid iff st_procpid > 0, unused if st_procpid == 0 */ - int st_procpid; + int st_procpid; /* Add more TDS info */ uint32_t client_version; @@ -99,25 +99,25 @@ typedef struct TdsStatus bool ansi_padding; bool ansi_nulls; bool concat_null_yields_null; - int textsize; - int datefirst; - int lock_timeout; - int transaction_isolation; + int textsize; + int datefirst; + int lock_timeout; + int transaction_isolation; - char *st_library_name; /* Library */ - char *st_host_name; /* Hostname */ - char *st_language; /* Language */ - char *st_context_info; /* CONTEXT_INFO */ + char *st_library_name; /* Library */ + char *st_host_name; /* Hostname */ + char *st_language; /* Language */ + char *st_context_info; /* CONTEXT_INFO */ uint32_t client_pid; uint64 rowcount; - int error; - int trancount; + int error; + int trancount; uint32_t protocol_version; uint32_t packet_size; - int encrypt_option; + int encrypt_option; int16 database_id; } TdsStatus; @@ -127,7 +127,7 @@ typedef struct LocalTdsStatus /* * Local version of the tds status entry. */ - TdsStatus tdsStatus; + TdsStatus tdsStatus; /* * The xid of the current transaction if available, InvalidTransactionId @@ -146,20 +146,20 @@ static TdsStatus *TdsStatusArray = NULL; static TdsStatus *MyTdsStatusEntry; static LocalTdsStatus *localTdsStatusTable = NULL; -uint32_t MyTdsClientVersion = 0; -uint32_t MyTdsClientPid = -1; -char *MyTdsLibraryName = NULL; -char *MyTdsHostName = NULL; -char *MyTdsContextInfo = NULL; -uint32_t MyTdsProtocolVersion = TDS_DEFAULT_VERSION; -uint32_t MyTdsPacketSize = 0; -int MyTdsEncryptOption = TDS_ENCRYPT_OFF; +uint32_t MyTdsClientVersion = 0; +uint32_t MyTdsClientPid = -1; +char *MyTdsLibraryName = NULL; +char *MyTdsHostName = NULL; +char *MyTdsContextInfo = NULL; +uint32_t MyTdsProtocolVersion = TDS_DEFAULT_VERSION; +uint32_t MyTdsPacketSize = 0; +int MyTdsEncryptOption = TDS_ENCRYPT_OFF; static char *TdsLibraryNameBuffer = NULL; static char *TdsHostNameBuffer = NULL; static char *TdsLanguageBuffer = NULL; static char *TdsContextInfoBuffer = NULL; -static int localNumBackends = 0; +static int localNumBackends = 0; static bool isLocalStatusTableValid = false; TdsInstrPlugin **tds_instr_plugin_ptr = NULL; @@ -171,7 +171,7 @@ extern void _PG_fini(void); static struct PLtsql_protocol_plugin pltsql_plugin_handler; PLtsql_protocol_plugin *pltsql_plugin_handler_ptr = &pltsql_plugin_handler; -static Oid tvp_lookup(const char *relname, Oid relnamespace); +static Oid tvp_lookup(const char *relname, Oid relnamespace); static relname_lookup_hook_type prev_relname_lookup_hook = NULL; /* Shmem hook */ @@ -186,7 +186,7 @@ static void tds_status_shmem_startup(void); static void tds_stats_shmem_shutdown(int code, Datum arg); static void tdsstat_read_current_status(void); -static LocalTdsStatus * tdsstat_fetch_stat_local_tdsentry (int beid); +static LocalTdsStatus *tdsstat_fetch_stat_local_tdsentry(int beid); /* * Module initialization function @@ -203,7 +203,7 @@ _PG_init(void) /* Must be loaded with shared_preload_libaries */ if (!process_shared_preload_libraries_in_progress) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("babelfishpg_tds must be loaded via shared_preload_libraries"))); + errmsg("babelfishpg_tds must be loaded via shared_preload_libraries"))); TdsDefineGucs(); @@ -278,7 +278,7 @@ TdsContextInfoBufferSize() static Size tds_memsize() { - Size size; + Size size; size = TdsStatusArraySize(); size = add_size(size, TdsLibraryNameBufferSize()); @@ -309,7 +309,7 @@ tds_shmem_request() static void tds_status_shmem_startup(void) { - bool found; + bool found; char *buffer; /* @@ -318,8 +318,8 @@ tds_status_shmem_startup(void) LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE); TdsStatusArray = (TdsStatus *) ShmemInitStruct("TDS Status Array", - TdsStatusArraySize(), - &found); + TdsStatusArraySize(), + &found); if (!found) { /* @@ -336,7 +336,7 @@ tds_status_shmem_startup(void) if (!found) { - int i; + int i; MemSet(TdsLibraryNameBuffer, 0, TdsLibraryNameBufferSize()); @@ -355,7 +355,7 @@ tds_status_shmem_startup(void) if (!found) { - int i; + int i; MemSet(TdsHostNameBuffer, 0, TdsHostNameBufferSize()); @@ -374,7 +374,7 @@ tds_status_shmem_startup(void) if (!found) { - int i; + int i; MemSet(TdsLanguageBuffer, 0, TdsLanguageBufferSize()); @@ -393,7 +393,7 @@ tds_status_shmem_startup(void) if (!found) { - int i; + int i; MemSet(TdsContextInfoBuffer, 0, TdsContextInfoBufferSize()); @@ -408,7 +408,8 @@ tds_status_shmem_startup(void) LWLockRelease(AddinShmemInitLock); - /* If we're in the postmaster (or a standalone backend...), set up a shmem + /* + * If we're in the postmaster (or a standalone backend...), set up a shmem * exit hook to persist the dirty outlines */ if (!IsUnderPostmaster) @@ -460,16 +461,16 @@ void tdsstat_bestart(void) { volatile TdsStatus *vtdsentry = MyTdsStatusEntry; - TdsStatus ltdsentry; + TdsStatus ltdsentry; - int len; - char *library_name = NULL; - char *host_name = NULL; + int len; + char *library_name = NULL; + char *host_name = NULL; const char *language = NULL; /* - * To minimize the time spent modifying the TdsStatus entry, and - * avoid risk of errors inside the critical section, we first copy the + * To minimize the time spent modifying the TdsStatus entry, and avoid + * risk of errors inside the critical section, we first copy the * shared-memory struct to a local variable, then modify the data in the * local variable, then copy the local variable back to shared memory. * Only the last step has to be inside the critical section. @@ -564,7 +565,7 @@ tdsstat_bestart(void) } static LocalTdsStatus * -tdsstat_fetch_stat_local_tdsentry (int beid) +tdsstat_fetch_stat_local_tdsentry(int beid) { LocalTdsStatus *localentry; @@ -594,7 +595,7 @@ tdsstat_read_current_status(void) volatile TdsStatus *tdsentry; LocalTdsStatus *localtable; LocalTdsStatus *localentry; - int i; + int i; if (isLocalStatusTableValid) return; /* already done */ @@ -638,7 +639,7 @@ tdsstat_read_current_status(void) if (tdsentry->st_library_name) localentry->tdsStatus.st_library_name = tdsentry->st_library_name; - + if (tdsentry->st_host_name) localentry->tdsStatus.st_host_name = tdsentry->st_host_name; @@ -736,8 +737,8 @@ bool tds_stat_get_activity(Datum *values, bool *nulls, int len, int pid, int curr_backend) { LocalTdsStatus *local_tdsentry; - TdsStatus *tdsentry; - int tsql_isolation_level; + TdsStatus *tdsentry; + int tsql_isolation_level; MemSet(values, 0, len); MemSet(nulls, false, len); @@ -760,13 +761,13 @@ tds_stat_get_activity(Datum *values, bool *nulls, int len, int pid, int curr_bac values[1] = Int32GetDatum(tdsentry->client_version); /* Library name must be valid */ - if(tdsentry->st_library_name) + if (tdsentry->st_library_name) values[2] = CStringGetTextDatum(tdsentry->st_library_name); else nulls[2] = true; /* Language must be valid */ - if(tdsentry->st_language) + if (tdsentry->st_language) values[3] = CStringGetTextDatum(tdsentry->st_language); else nulls[3] = true; @@ -785,25 +786,20 @@ tds_stat_get_activity(Datum *values, bool *nulls, int len, int pid, int curr_bac /* * In postgres, transaction isolation level mapping is as follows: - * XACT_READ_UNCOMMITTED 0 - * XACT_READ_COMMITTED 1 - * XACT_REPEATABLE_READ 2 - * XACT_SERIALIZABLE 3 + * XACT_READ_UNCOMMITTED 0 XACT_READ_COMMITTED 1 + * XACT_REPEATABLE_READ 2 XACT_SERIALIZABLE 3 * * In T-SQL, transaction isolation level mapping is as follows: - * XACT_READ_UNCOMMITTED 1 - * XACT_READ_COMMITTED 2 - * XACT_REPEATABLE_READ 3 - * XACT_SERIALIZABLE 4 - * XACT_SNAPSHOT 5 + * XACT_READ_UNCOMMITTED 1 XACT_READ_COMMITTED 2 + * XACT_REPEATABLE_READ 3 XACT_SERIALIZABLE 4 XACT_SNAPSHOT 5 * - * So adding 1 while storing value in tuples with one exception. - * We are treating T-SQL SNAPSHOT isolation as REPEATABLE_READ in - * Babelfish so handling this case separately. We don't support - * T-SQL REPEATABLE_READ isolation level in Babelfish yet so this - * logic holds for now. Once we support REPEATABLE_READ isolation - * level in Babelfish, we need to figure out if XACT_REPEATABLE_READ - * PG isolation level represents T-SQL SNAPSHOT or REPEATABLE_READ. + * So adding 1 while storing value in tuples with one exception. We are + * treating T-SQL SNAPSHOT isolation as REPEATABLE_READ in Babelfish so + * handling this case separately. We don't support T-SQL REPEATABLE_READ + * isolation level in Babelfish yet so this logic holds for now. Once we + * support REPEATABLE_READ isolation level in Babelfish, we need to figure + * out if XACT_REPEATABLE_READ PG isolation level represents T-SQL + * SNAPSHOT or REPEATABLE_READ. */ if (tdsentry->transaction_isolation == XACT_REPEATABLE_READ) tsql_isolation_level = XACT_SNAPSHOT; @@ -822,7 +818,10 @@ tds_stat_get_activity(Datum *values, bool *nulls, int len, int pid, int curr_bac values[18] = Int32GetDatum(tdsentry->error); values[19] = Int32GetDatum(tdsentry->trancount); - /* ValidateLoginRequest() already checks if protocol version is valid or not */ + /* + * ValidateLoginRequest() already checks if protocol version is valid or + * not + */ values[20] = Int32GetDatum(tdsentry->protocol_version); /* ValidateLoginRequest() already checks if packet size is valid or not */ @@ -834,7 +833,7 @@ tds_stat_get_activity(Datum *values, bool *nulls, int len, int pid, int curr_bac /* Host name must be valid */ if (len > 24) { - if(tdsentry->st_host_name) + if (tdsentry->st_host_name) values[24] = CStringGetTextDatum(tdsentry->st_host_name); else nulls[24] = true; @@ -842,7 +841,7 @@ tds_stat_get_activity(Datum *values, bool *nulls, int len, int pid, int curr_bac if (len > 25) { - if(tdsentry->st_context_info) + if (tdsentry->st_context_info) values[25] = PointerGetDatum(cstring_to_text_with_len(tdsentry->st_context_info, CONTEXTINFOLEN)); else nulls[25] = true; @@ -855,7 +854,7 @@ void TdsSetGucStatVariable(const char *guc, bool boolVal, const char *strVal, int intVal) { volatile TdsStatus *vtdsentry = MyTdsStatusEntry; - int len; + int len; PGSTAT_BEGIN_WRITE_ACTIVITY(vtdsentry); @@ -914,6 +913,7 @@ void TdsSetDatabaseStatVariable(int16 db_id) { volatile TdsStatus *vtdsentry = MyTdsStatusEntry; + PGSTAT_BEGIN_WRITE_ACTIVITY(vtdsentry); vtdsentry->database_id = db_id; @@ -928,8 +928,8 @@ TdsSetDatabaseStatVariable(int16 db_id) static Oid tvp_lookup(const char *relname, Oid relnamespace) { - Oid relid; - ListCell *lc; + Oid relid; + ListCell *lc; if (prev_relname_lookup_hook) relid = (*prev_relname_lookup_hook) (relname, relnamespace); @@ -937,10 +937,10 @@ tvp_lookup(const char *relname, Oid relnamespace) relid = get_relname_relid(relname, relnamespace); /* - * If we find a TVP whose name matches relname, return its - * underlying table's relid. Otherwise, just return relname's relid. + * If we find a TVP whose name matches relname, return its underlying + * table's relid. Otherwise, just return relname's relid. */ - foreach (lc, tvp_lookup_list) + foreach(lc, tvp_lookup_list) { TvpLookupItem *item = (TvpLookupItem *) lfirst(lc); @@ -962,7 +962,7 @@ invalidate_stat_table(void) isLocalStatusTableValid = false; } -char* +char * get_tds_host_name(void) { return MyTdsHostName; @@ -978,10 +978,10 @@ get_tds_context_info(void) } void -set_tds_context_info(bytea* context_info) +set_tds_context_info(bytea *context_info) { - int32 len; - char* data; + int32 len; + char *data; volatile TdsStatus *vtdsentry = MyTdsStatusEntry; diff --git a/contrib/babelfishpg_tds/src/backend/tds/tds_data_map.c b/contrib/babelfishpg_tds/src/backend/tds/tds_data_map.c index a3a296eac3..fcd5bdd17b 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tds_data_map.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tds_data_map.c @@ -9,217 +9,217 @@ TdsLCIDToEncodingMap TdsLCIDToEncodingMap_data[] = { - {0x0436, PG_WIN1252}, // Afrikaans: South Africa - {0x041c, PG_WIN1250}, // Albanian: Albania - {0x1401, PG_WIN1256}, // Arabic: Algeria - {0x3c01, PG_WIN1256}, // Arabic: Bahrain - {0x0c01, PG_WIN1256}, // Arabic: Egypt - {0x0801, PG_WIN1256}, // Arabic: Iraq - {0x2c01, PG_WIN1256}, // Arabic: Jordan - {0x3401, PG_WIN1256}, // Arabic: Kuwait - {0x3001, PG_WIN1256}, // Arabic: Lebanon - {0x1001, PG_WIN1256}, // Arabic: Libya - {0x1801, PG_WIN1256}, // Arabic: Morocco - {0x2001, PG_WIN1256}, // Arabic: Oman - {0x4001, PG_WIN1256}, // Arabic: Qatar - {0x0401, PG_WIN1256}, // Arabic: Saudi Arabia - {0x2801, PG_WIN1256}, //Arabic: Syria - {0x1c01, PG_WIN1256}, // Arabic: Tunisia - {0x3801, PG_WIN1256}, // Arabic: U.A.E. - {0x2401, PG_WIN1256}, // Arabic: Yemen - // {0x042b, 0},// Armenian: Armenia - {0x082c, PG_WIN1251},// Azeri: Azerbaijan (Cyrillic) - {0x042c, PG_WIN1250},// Azeri: Azerbaijan (Latin) - {0x042d, PG_WIN1252},// Basque: Spain - {0x0423, PG_WIN1251},// Belarusian: Belarus - {0x0402, PG_WIN1251},// Bulgarian: Bulgaria - {0x0403, PG_WIN1252},// Catalan: Spain - {0x0c04, PG_BIG5}, - {0x1404, PG_BIG5},// Chinese: Macao SAR (Traditional) - {0x0804, PG_GBK},// Chinese: PRC (Simplified) - {0x1004, PG_GBK},// Chinese: Singapore (Simplified) - {0x0404, PG_BIG5},// Chinese: Taiwan (Traditional) - // {0x0827, PG_WIN1257}, - {0x041a, PG_WIN1250},// Croatian: Croatia - {0x0405, PG_WIN1250},// Czech: Czech Republic - {0x0406, PG_WIN1252},// Danish: Denmark - {0x0813, PG_WIN1252},// Dutch: Belgium - {0x0413, PG_WIN1252},// Dutch: Netherlands - {0x0c09, PG_WIN1252},// English: Australia - {0x2809, PG_WIN1252},// English: Belize - {0x1009, PG_WIN1252},// English: Canada - // {0x2409, PG_WIN1252}, - {0x1809, PG_WIN1252},// English: Ireland - {0x2009, PG_WIN1252},// English: Jamaica - {0x1409, PG_WIN1252},// English: New Zealand - {0x3409, PG_WIN1252},// English: Philippines - {0x1c09, PG_WIN1252},// English: South Africa - {0x2c09, PG_WIN1252},// English: Trinidad - {0x0809, PG_WIN1252},// English: United Kingdom - {0x0409, PG_WIN1252},// English: United States - {0x3009, PG_WIN1252},// English: Zimbabwe - {0x0425, PG_WIN1257},// Estonian: Estonia - {0x0438, PG_WIN1252},// Faeroese: Faeroe Islands - {0x0429, PG_WIN1256},// Farsi: Iran - {0x040b, PG_WIN1252},// Finnish: Finland - {0x080c, PG_WIN1252},// French: Belgium - {0x0c0c, PG_WIN1252},// French: Canada - {0x040c, PG_WIN1252},// French: France - {0x140c, PG_WIN1252},// French: Luxembourg - {0x180c, PG_WIN1252},// French: Monaco - {0x100c, PG_WIN1252},// French: Switzerland - {0x042f, PG_WIN1251},// Macedonian (FYROM) - // {0x0437, 0},// Georgian: Georgia - {0x0c07, PG_WIN1252},// German: Austria - {0x0407, PG_WIN1252},// German: Germany - {0x1407, PG_WIN1252},// German: Liechtenstein - {0x1007, PG_WIN1252},// German: Luxembourg - {0x0807, PG_WIN1252},// German: Switzerland - {0x0408, PG_WIN1253},// Greek: Greece - // {0x0447, 0},// Gujarati: India - {0x040d, PG_WIN1255},// Hebrew: Israel - // {0x0439, 0},// Hindi: India - {0x040e, PG_WIN1250},// Hungarian: Hungary - {0x040f, PG_WIN1252},// Icelandic: Iceland - {0x0421, PG_WIN1252},// Indonesian: Indonesia - {0x0410, PG_WIN1252},// Italian: Italy - {0x0810, PG_WIN1252},// Italian: Switzerland - {0x0411, PG_SJIS},// Japanese: Japan - // {0x044b, 0},// Kannada: India - // {0x0457, 0},// Konkani: India - {0x0412, PG_UHC},// Korean (Extended Wansung): Korea - {0x0440, PG_WIN1251},// Kyrgyz: Kyrgyzstan - {0x0426, PG_WIN1257},// Latvian: Latvia - {0x0427, PG_WIN1257},// Lithuanian: Lithuania - {0x083e, PG_WIN1252},// Malay: Brunei Darussalam - {0x043e, PG_WIN1252},// Malay: Malaysia - // {0x044e, 0},// Marathi: India - {0x0450, PG_WIN1251},// Mongolian: Mongolia - {0x0414, PG_WIN1252},// Norwegian: Norway (BokmÃ¥l) - {0x0814, PG_WIN1252},// Norwegian: Norway (Nynorsk) - {0x0415, PG_WIN1250},// Polish: Poland - {0x0416, PG_WIN1252},// Portuguese: Brazil - {0x0816, PG_WIN1252},// Portuguese: Portugal - // {0x0446, 0},// Punjabi: India - {0x0418, PG_WIN1250},// Romanian: Romania - {0x0419, PG_WIN1251},// Russian: Russia - // {0x044f, 0},// Sanskrit: India - {0x0c1a, PG_WIN1251},// Serbian: Serbia (Cyrillic) - {0x081a, PG_WIN1250},// Serbian: Serbia (Latin) - {0x041b, PG_WIN1250},// Slovak: Slovakia - {0x0424, PG_WIN1250},// Slovenian: Slovenia - {0x2c0a, PG_WIN1252},// Spanish: Argentina - {0x400a, PG_WIN1252},// Spanish: Bolivia - {0x340a, PG_WIN1252},// Spanish: Chile - {0x240a, PG_WIN1252},// Spanish: Colombia - {0x140a, PG_WIN1252},// Spanish: Costa Rica - {0x1c0a, PG_WIN1252},// Spanish: Dominican Republic - {0x300a, PG_WIN1252},// Spanish: Ecuador - {0x440a, PG_WIN1252},// Spanish: El Salvador - {0x100a, PG_WIN1252},// Spanish: Guatemala - {0x480a, PG_WIN1252},// Spanish: Honduras - {0x080a, PG_WIN1252},// Spanish: Mexico - {0x4c0a, PG_WIN1252},// Spanish: Nicaragua - {0x180a, PG_WIN1252},// Spanish: Panama - {0x3c0a, PG_WIN1252},// Spanish: Paraguay - {0x280a, PG_WIN1252},// Spanish: Peru - {0x500a, PG_WIN1252},// Spanish: Puerto Rico - {0x0c0a, PG_WIN1252},// Spanish: Spain (Modern Sort) - {0x040a, PG_WIN1252},// Spanish: Spain (International Sort) - {0x380a, PG_WIN1252},// Spanish: Uruguay - {0x200a, PG_WIN1252},// Spanish: Venezuela - {0x0441, PG_WIN1252},// Swahili: Kenya - {0x081d, PG_WIN1252},// Swedish: Finland - {0x041d, PG_WIN1252},// Swedish: Sweden - {0x0444, PG_WIN1251},// Tatar: Tatarstan - // {0x044a, 0},// Telgu: India - {0x041e, PG_WIN874},// Thai: Thailand - {0x041f, PG_WIN1254},// Turkish: Turkey - {0x0422, PG_WIN1251},// Ukrainian: Ukraine - {0x0820, PG_WIN1256},// Urdu: India - {0x0420, PG_WIN1256},// Urdu: Pakistan - {0x0843, PG_WIN1251},// Uzbek: Uzbekistan (Cyrillic) - {0x0443, PG_WIN1250},// Uzbek: Uzbekistan (Latin) - {0x042a, PG_WIN1258}// Vietnamese: Vietnam + {0x0436, PG_WIN1252}, //Afrikaans:South Africa + {0x041c, PG_WIN1250}, //Albanian:Albania + {0x1401, PG_WIN1256}, //Arabic:Algeria + {0x3c01, PG_WIN1256}, //Arabic:Bahrain + {0x0c01, PG_WIN1256}, //Arabic:Egypt + {0x0801, PG_WIN1256}, //Arabic:Iraq + {0x2c01, PG_WIN1256}, //Arabic:Jordan + {0x3401, PG_WIN1256}, //Arabic:Kuwait + {0x3001, PG_WIN1256}, //Arabic:Lebanon + {0x1001, PG_WIN1256}, //Arabic:Libya + {0x1801, PG_WIN1256}, //Arabic:Morocco + {0x2001, PG_WIN1256}, //Arabic:Oman + {0x4001, PG_WIN1256}, //Arabic:Qatar + {0x0401, PG_WIN1256}, //Arabic:Saudi Arabia + {0x2801, PG_WIN1256}, //Arabic:Syria + {0x1c01, PG_WIN1256}, //Arabic:Tunisia + {0x3801, PG_WIN1256}, //Arabic:U.A.E. + {0x2401, PG_WIN1256}, //Arabic:Yemen + /* {0x042b, 0},// Armenian: Armenia */ + {0x082c, PG_WIN1251}, //Azeri:Azerbaijan(Cyrillic) + {0x042c, PG_WIN1250}, //Azeri:Azerbaijan(Latin) + {0x042d, PG_WIN1252}, //Basque:Spain + {0x0423, PG_WIN1251}, //Belarusian:Belarus + {0x0402, PG_WIN1251}, //Bulgarian:Bulgaria + {0x0403, PG_WIN1252}, //Catalan:Spain + {0x0c04, PG_BIG5}, + {0x1404, PG_BIG5}, //Chinese:Macao SAR(Traditional) + {0x0804, PG_GBK}, //Chinese:PRC(Simplified) + {0x1004, PG_GBK}, //Chinese:Singapore(Simplified) + {0x0404, PG_BIG5}, //Chinese:Taiwan(Traditional) + /* {0x0827, PG_WIN1257}, */ + {0x041a, PG_WIN1250}, //Croatian:Croatia + {0x0405, PG_WIN1250}, //Czech:Czech Republic + {0x0406, PG_WIN1252}, //Danish:Denmark + {0x0813, PG_WIN1252}, //Dutch:Belgium + {0x0413, PG_WIN1252}, //Dutch:Netherlands + {0x0c09, PG_WIN1252}, //English:Australia + {0x2809, PG_WIN1252}, //English:Belize + {0x1009, PG_WIN1252}, //English:Canada + /* {0x2409, PG_WIN1252}, */ + {0x1809, PG_WIN1252}, //English:Ireland + {0x2009, PG_WIN1252}, //English:Jamaica + {0x1409, PG_WIN1252}, //English:New Zealand + {0x3409, PG_WIN1252}, //English:Philippines + {0x1c09, PG_WIN1252}, //English:South Africa + {0x2c09, PG_WIN1252}, //English:Trinidad + {0x0809, PG_WIN1252}, //English:United Kingdom + {0x0409, PG_WIN1252}, //English:United States + {0x3009, PG_WIN1252}, //English:Zimbabwe + {0x0425, PG_WIN1257}, //Estonian:Estonia + {0x0438, PG_WIN1252}, //Faeroese:Faeroe Islands + {0x0429, PG_WIN1256}, //Farsi:Iran + {0x040b, PG_WIN1252}, //Finnish:Finland + {0x080c, PG_WIN1252}, //French:Belgium + {0x0c0c, PG_WIN1252}, //French:Canada + {0x040c, PG_WIN1252}, //French:France + {0x140c, PG_WIN1252}, //French:Luxembourg + {0x180c, PG_WIN1252}, //French:Monaco + {0x100c, PG_WIN1252}, //French:Switzerland + {0x042f, PG_WIN1251}, //Macedonian(FYROM) + /* {0x0437, 0},// Georgian: Georgia */ + {0x0c07, PG_WIN1252}, //German:Austria + {0x0407, PG_WIN1252}, //German:Germany + {0x1407, PG_WIN1252}, //German:Liechtenstein + {0x1007, PG_WIN1252}, //German:Luxembourg + {0x0807, PG_WIN1252}, //German:Switzerland + {0x0408, PG_WIN1253}, //Greek:Greece + /* {0x0447, 0},// Gujarati: India */ + {0x040d, PG_WIN1255}, //Hebrew:Israel + /* {0x0439, 0},// Hindi: India */ + {0x040e, PG_WIN1250}, //Hungarian:Hungary + {0x040f, PG_WIN1252}, //Icelandic:Iceland + {0x0421, PG_WIN1252}, //Indonesian:Indonesia + {0x0410, PG_WIN1252}, //Italian:Italy + {0x0810, PG_WIN1252}, //Italian:Switzerland + {0x0411, PG_SJIS}, //Japanese:Japan + /* {0x044b, 0},// Kannada: India */ + /* {0x0457, 0},// Konkani: India */ + {0x0412, PG_UHC}, //Korean(Extended Wansung):Korea + {0x0440, PG_WIN1251}, //Kyrgyz:Kyrgyzstan + {0x0426, PG_WIN1257}, //Latvian:Latvia + {0x0427, PG_WIN1257}, //Lithuanian:Lithuania + {0x083e, PG_WIN1252}, //Malay:Brunei Darussalam + {0x043e, PG_WIN1252}, //Malay:Malaysia + /* {0x044e, 0},// Marathi: India */ + {0x0450, PG_WIN1251}, //Mongolian:Mongolia + {0x0414, PG_WIN1252}, //Norwegian:Norway(Bokmà ¥ l) + {0x0814, PG_WIN1252}, //Norwegian:Norway(Nynorsk) + {0x0415, PG_WIN1250}, //Polish:Poland + {0x0416, PG_WIN1252}, //Portuguese:Brazil + {0x0816, PG_WIN1252}, //Portuguese:Portugal + /* {0x0446, 0},// Punjabi: India */ + {0x0418, PG_WIN1250}, //Romanian:Romania + {0x0419, PG_WIN1251}, //Russian:Russia + /* {0x044f, 0},// Sanskrit: India */ + {0x0c1a, PG_WIN1251}, //Serbian:Serbia(Cyrillic) + {0x081a, PG_WIN1250}, //Serbian:Serbia(Latin) + {0x041b, PG_WIN1250}, //Slovak:Slovakia + {0x0424, PG_WIN1250}, //Slovenian:Slovenia + {0x2c0a, PG_WIN1252}, //Spanish:Argentina + {0x400a, PG_WIN1252}, //Spanish:Bolivia + {0x340a, PG_WIN1252}, //Spanish:Chile + {0x240a, PG_WIN1252}, //Spanish:Colombia + {0x140a, PG_WIN1252}, //Spanish:Costa Rica + {0x1c0a, PG_WIN1252}, //Spanish:Dominican Republic + {0x300a, PG_WIN1252}, //Spanish:Ecuador + {0x440a, PG_WIN1252}, //Spanish:El Salvador + {0x100a, PG_WIN1252}, //Spanish:Guatemala + {0x480a, PG_WIN1252}, //Spanish:Honduras + {0x080a, PG_WIN1252}, //Spanish:Mexico + {0x4c0a, PG_WIN1252}, //Spanish:Nicaragua + {0x180a, PG_WIN1252}, //Spanish:Panama + {0x3c0a, PG_WIN1252}, //Spanish:Paraguay + {0x280a, PG_WIN1252}, //Spanish:Peru + {0x500a, PG_WIN1252}, //Spanish:Puerto Rico + {0x0c0a, PG_WIN1252}, //Spanish:Spain(Modern Sort) + {0x040a, PG_WIN1252}, //Spanish:Spain(International Sort) + {0x380a, PG_WIN1252}, //Spanish:Uruguay + {0x200a, PG_WIN1252}, //Spanish:Venezuela + {0x0441, PG_WIN1252}, //Swahili:Kenya + {0x081d, PG_WIN1252}, //Swedish:Finland + {0x041d, PG_WIN1252}, //Swedish:Sweden + {0x0444, PG_WIN1251}, //Tatar:Tatarstan + /* {0x044a, 0},// Telgu: India */ + {0x041e, PG_WIN874}, //Thai:Thailand + {0x041f, PG_WIN1254}, //Turkish:Turkey + {0x0422, PG_WIN1251}, //Ukrainian:Ukraine + {0x0820, PG_WIN1256}, //Urdu:India + {0x0420, PG_WIN1256}, //Urdu:Pakistan + {0x0843, PG_WIN1251}, //Uzbek:Uzbekistan(Cyrillic) + {0x0443, PG_WIN1250}, //Uzbek:Uzbekistan(Latin) + {0x042a, PG_WIN1258} //Vietnamese:Vietnam }; -size_t TdsLCIDToEncodingMap_datasize = lengthof(TdsLCIDToEncodingMap_data); +size_t TdsLCIDToEncodingMap_datasize = lengthof(TdsLCIDToEncodingMap_data); TdsIoFunctionRawData TdsIoFunctionRawData_data[] = { - {"sys", "bit", TDS_TYPE_BIT, 1, 1, TDS_SEND_BIT, TDS_RECV_BIT}, - {"sys", "tinyint", TDS_TYPE_INTEGER, 1, 1, TDS_SEND_TINYINT, TDS_RECV_TINYINT}, - {"pg_catalog", "int2", TDS_TYPE_INTEGER, 2, 1, TDS_SEND_SMALLINT, TDS_RECV_SMALLINT}, - {"pg_catalog", "int4", TDS_TYPE_INTEGER, 4, 1, TDS_SEND_INTEGER, TDS_RECV_INTEGER}, - {"pg_catalog", "int8", TDS_TYPE_INTEGER, 8, 1, TDS_SEND_BIGINT, TDS_RECV_BIGINT}, - {"pg_catalog", "float4", TDS_TYPE_FLOAT, 4, 1, TDS_SEND_FLOAT4, TDS_RECV_FLOAT4}, - {"pg_catalog", "float8", TDS_TYPE_FLOAT, 8, 1, TDS_SEND_FLOAT8, TDS_RECV_FLOAT8}, - {"pg_catalog", "bpchar", TDS_TYPE_CHAR, -1, 2, TDS_SEND_CHAR, TDS_RECV_CHAR}, - {"sys", "bpchar", TDS_TYPE_CHAR, -1, 2, TDS_SEND_CHAR, TDS_RECV_CHAR}, - {"sys", "nchar", TDS_TYPE_NCHAR, -1, 2, TDS_SEND_NCHAR, TDS_RECV_NCHAR}, - {"sys", "nvarchar", TDS_TYPE_NVARCHAR, -1, 2, TDS_SEND_NVARCHAR, TDS_RECV_NVARCHAR}, - {"sys", "varchar", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_VARCHAR}, - {"sys", "smallmoney", TDS_TYPE_MONEYN, 4, 1, TDS_SEND_SMALLMONEY, TDS_RECV_SMALLMONEY}, - {"sys", "money", TDS_TYPE_MONEYN, 8, 1, TDS_SEND_MONEY, TDS_RECV_MONEY}, - {"pg_catalog", "text", TDS_TYPE_TEXT, -1, 2, TDS_SEND_TEXT, TDS_RECV_TEXT}, - {"sys", "ntext", TDS_TYPE_NTEXT, -1, 2, TDS_SEND_NTEXT, TDS_RECV_NTEXT}, - {"pg_catalog", "date", TDS_TYPE_DATE, 3, 1, TDS_SEND_DATE, TDS_RECV_DATE}, - {"sys", "datetime", TDS_TYPE_DATETIMEN, 8, 1, TDS_SEND_DATETIME, TDS_RECV_DATETIME}, - {"pg_catalog", "numeric", TDS_TYPE_NUMERICN, 17, 1, TDS_SEND_NUMERIC, TDS_RECV_NUMERIC}, - {"sys", "decimal", TDS_TYPE_DECIMALN, 17, 1, TDS_SEND_NUMERIC, TDS_RECV_NUMERIC}, - {"sys", "smalldatetime", TDS_TYPE_DATETIMEN, 4, 1, TDS_SEND_SMALLDATETIME, TDS_RECV_SMALLDATETIME}, - {"sys", "binary", TDS_TYPE_BINARY, -1, 2, TDS_SEND_BINARY, TDS_RECV_BINARY}, - {"sys", "bbf_binary", TDS_TYPE_BINARY, -1, 2, TDS_SEND_BINARY, TDS_RECV_BINARY}, - {"sys", "varbinary", TDS_TYPE_VARBINARY, -1, 2, TDS_SEND_VARBINARY, TDS_RECV_VARBINARY}, - {"sys", "bbf_varbinary", TDS_TYPE_VARBINARY, -1, 2, TDS_SEND_VARBINARY, TDS_RECV_VARBINARY}, - {"sys", "image", TDS_TYPE_IMAGE, -1, 2, TDS_SEND_IMAGE, TDS_RECV_IMAGE}, - {"sys", "uniqueidentifier", TDS_TYPE_UNIQUEIDENTIFIER, 16, 1, TDS_SEND_UNIQUEIDENTIFIER, TDS_RECV_UNIQUEIDENTIFIER}, - {"pg_catalog", "time", TDS_TYPE_TIME, 5, 1, TDS_SEND_TIME, TDS_RECV_TIME}, - {"sys", "datetime2", TDS_TYPE_DATETIME2, 8, 1, TDS_SEND_DATETIME2, TDS_RECV_DATETIME2}, - {"pg_catalog", "xml", TDS_TYPE_XML, -1, 1, TDS_SEND_XML, TDS_RECV_XML}, - {"sys", "sql_variant", TDS_TYPE_SQLVARIANT, -1, 4, TDS_SEND_SQLVARIANT, TDS_RECV_SQLVARIANT}, - {"sys", "datetimeoffset", TDS_TYPE_DATETIMEOFFSET, 10, 1, TDS_SEND_DATETIMEOFFSET, TDS_RECV_DATETIMEOFFSET}, - {"sys", "fixeddecimal", TDS_TYPE_MONEYN, 8, 1, TDS_SEND_MONEY, TDS_RECV_INVALID}, - {"sys", "rowversion", TDS_TYPE_BINARY, 8, 2, TDS_SEND_BINARY, TDS_RECV_BINARY}, - {"sys", "timestamp", TDS_TYPE_BINARY, 8, 2, TDS_SEND_BINARY, TDS_RECV_BINARY}, + {"sys", "bit", TDS_TYPE_BIT, 1, 1, TDS_SEND_BIT, TDS_RECV_BIT}, + {"sys", "tinyint", TDS_TYPE_INTEGER, 1, 1, TDS_SEND_TINYINT, TDS_RECV_TINYINT}, + {"pg_catalog", "int2", TDS_TYPE_INTEGER, 2, 1, TDS_SEND_SMALLINT, TDS_RECV_SMALLINT}, + {"pg_catalog", "int4", TDS_TYPE_INTEGER, 4, 1, TDS_SEND_INTEGER, TDS_RECV_INTEGER}, + {"pg_catalog", "int8", TDS_TYPE_INTEGER, 8, 1, TDS_SEND_BIGINT, TDS_RECV_BIGINT}, + {"pg_catalog", "float4", TDS_TYPE_FLOAT, 4, 1, TDS_SEND_FLOAT4, TDS_RECV_FLOAT4}, + {"pg_catalog", "float8", TDS_TYPE_FLOAT, 8, 1, TDS_SEND_FLOAT8, TDS_RECV_FLOAT8}, + {"pg_catalog", "bpchar", TDS_TYPE_CHAR, -1, 2, TDS_SEND_CHAR, TDS_RECV_CHAR}, + {"sys", "bpchar", TDS_TYPE_CHAR, -1, 2, TDS_SEND_CHAR, TDS_RECV_CHAR}, + {"sys", "nchar", TDS_TYPE_NCHAR, -1, 2, TDS_SEND_NCHAR, TDS_RECV_NCHAR}, + {"sys", "nvarchar", TDS_TYPE_NVARCHAR, -1, 2, TDS_SEND_NVARCHAR, TDS_RECV_NVARCHAR}, + {"sys", "varchar", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_VARCHAR}, + {"sys", "smallmoney", TDS_TYPE_MONEYN, 4, 1, TDS_SEND_SMALLMONEY, TDS_RECV_SMALLMONEY}, + {"sys", "money", TDS_TYPE_MONEYN, 8, 1, TDS_SEND_MONEY, TDS_RECV_MONEY}, + {"pg_catalog", "text", TDS_TYPE_TEXT, -1, 2, TDS_SEND_TEXT, TDS_RECV_TEXT}, + {"sys", "ntext", TDS_TYPE_NTEXT, -1, 2, TDS_SEND_NTEXT, TDS_RECV_NTEXT}, + {"pg_catalog", "date", TDS_TYPE_DATE, 3, 1, TDS_SEND_DATE, TDS_RECV_DATE}, + {"sys", "datetime", TDS_TYPE_DATETIMEN, 8, 1, TDS_SEND_DATETIME, TDS_RECV_DATETIME}, + {"pg_catalog", "numeric", TDS_TYPE_NUMERICN, 17, 1, TDS_SEND_NUMERIC, TDS_RECV_NUMERIC}, + {"sys", "decimal", TDS_TYPE_DECIMALN, 17, 1, TDS_SEND_NUMERIC, TDS_RECV_NUMERIC}, + {"sys", "smalldatetime", TDS_TYPE_DATETIMEN, 4, 1, TDS_SEND_SMALLDATETIME, TDS_RECV_SMALLDATETIME}, + {"sys", "binary", TDS_TYPE_BINARY, -1, 2, TDS_SEND_BINARY, TDS_RECV_BINARY}, + {"sys", "bbf_binary", TDS_TYPE_BINARY, -1, 2, TDS_SEND_BINARY, TDS_RECV_BINARY}, + {"sys", "varbinary", TDS_TYPE_VARBINARY, -1, 2, TDS_SEND_VARBINARY, TDS_RECV_VARBINARY}, + {"sys", "bbf_varbinary", TDS_TYPE_VARBINARY, -1, 2, TDS_SEND_VARBINARY, TDS_RECV_VARBINARY}, + {"sys", "image", TDS_TYPE_IMAGE, -1, 2, TDS_SEND_IMAGE, TDS_RECV_IMAGE}, + {"sys", "uniqueidentifier", TDS_TYPE_UNIQUEIDENTIFIER, 16, 1, TDS_SEND_UNIQUEIDENTIFIER, TDS_RECV_UNIQUEIDENTIFIER}, + {"pg_catalog", "time", TDS_TYPE_TIME, 5, 1, TDS_SEND_TIME, TDS_RECV_TIME}, + {"sys", "datetime2", TDS_TYPE_DATETIME2, 8, 1, TDS_SEND_DATETIME2, TDS_RECV_DATETIME2}, + {"pg_catalog", "xml", TDS_TYPE_XML, -1, 1, TDS_SEND_XML, TDS_RECV_XML}, + {"sys", "sql_variant", TDS_TYPE_SQLVARIANT, -1, 4, TDS_SEND_SQLVARIANT, TDS_RECV_SQLVARIANT}, + {"sys", "datetimeoffset", TDS_TYPE_DATETIMEOFFSET, 10, 1, TDS_SEND_DATETIMEOFFSET, TDS_RECV_DATETIMEOFFSET}, + {"sys", "fixeddecimal", TDS_TYPE_MONEYN, 8, 1, TDS_SEND_MONEY, TDS_RECV_INVALID}, + {"sys", "rowversion", TDS_TYPE_BINARY, 8, 2, TDS_SEND_BINARY, TDS_RECV_BINARY}, + {"sys", "timestamp", TDS_TYPE_BINARY, 8, 2, TDS_SEND_BINARY, TDS_RECV_BINARY}, - /* Mapping TDS listener sender to basic Postgres datatypes. */ - {"pg_catalog", "oid", TDS_TYPE_INTEGER, 4, 1, TDS_SEND_INTEGER, TDS_RECV_INVALID}, - {"pg_catalog", "sql_identifier", TDS_TYPE_VARCHAR, -1, 1, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog", "name", TDS_TYPE_VARCHAR, -1, 1, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog", "character_data", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog", "bool", TDS_TYPE_BIT, 1, 1, TDS_SEND_BIT, TDS_RECV_INVALID}, - {"pg_catalog", "varchar", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog", "cardinal_number", TDS_TYPE_INTEGER, 4, 1, TDS_SEND_INTEGER, TDS_RECV_INVALID}, - {"pg_catalog", "yes_or_no", TDS_TYPE_VARCHAR, -1, 1, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog", "char", TDS_TYPE_VARCHAR, -1, 1, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog", "timestamp", TDS_TYPE_DATETIMEN, 8, 1, TDS_SEND_DATETIME, TDS_RECV_INVALID}, - {"pg_catalog", "timestamptz", TDS_TYPE_VARCHAR, -1, 1, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog", "regproc", TDS_TYPE_VARCHAR, -1, 1, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog", "cstring", TDS_TYPE_TEXT, -1, 2, TDS_SEND_TEXT, TDS_RECV_INVALID}, - {"pg_catalog", "real", TDS_TYPE_FLOAT, 4, 1, TDS_SEND_FLOAT4, TDS_RECV_INVALID}, - {"pg_catalog", "aclitem", TDS_TYPE_VARCHAR, -1, 1, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog", "int2vector", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog", "oidvector", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog","pg_node_tree", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog","pg_lsn", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog", "_oid", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog", "_text", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog", "_aclitem", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog", "_float4", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog", "_float8", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog", "_int2", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog", "_real", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog", "_char", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog","pg_dependencies", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog","pg_ndistinct", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog","anyarray", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog", "xid", TDS_TYPE_INTEGER, 4, 1, TDS_SEND_INTEGER, TDS_RECV_INVALID}, - {"pg_catalog", "cid", TDS_TYPE_INTEGER, 4, 1, TDS_SEND_INTEGER, TDS_RECV_INVALID}, - {"pg_catalog", "tid", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog", "inet", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog", "interval", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, - {"pg_catalog", "bytea", TDS_TYPE_VARBINARY, -1, 2, TDS_SEND_VARBINARY, TDS_RECV_INVALID} + /* Mapping TDS listener sender to basic Postgres datatypes. */ + {"pg_catalog", "oid", TDS_TYPE_INTEGER, 4, 1, TDS_SEND_INTEGER, TDS_RECV_INVALID}, + {"pg_catalog", "sql_identifier", TDS_TYPE_VARCHAR, -1, 1, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "name", TDS_TYPE_VARCHAR, -1, 1, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "character_data", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "bool", TDS_TYPE_BIT, 1, 1, TDS_SEND_BIT, TDS_RECV_INVALID}, + {"pg_catalog", "varchar", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "cardinal_number", TDS_TYPE_INTEGER, 4, 1, TDS_SEND_INTEGER, TDS_RECV_INVALID}, + {"pg_catalog", "yes_or_no", TDS_TYPE_VARCHAR, -1, 1, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "char", TDS_TYPE_VARCHAR, -1, 1, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "timestamp", TDS_TYPE_DATETIMEN, 8, 1, TDS_SEND_DATETIME, TDS_RECV_INVALID}, + {"pg_catalog", "timestamptz", TDS_TYPE_VARCHAR, -1, 1, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "regproc", TDS_TYPE_VARCHAR, -1, 1, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "cstring", TDS_TYPE_TEXT, -1, 2, TDS_SEND_TEXT, TDS_RECV_INVALID}, + {"pg_catalog", "real", TDS_TYPE_FLOAT, 4, 1, TDS_SEND_FLOAT4, TDS_RECV_INVALID}, + {"pg_catalog", "aclitem", TDS_TYPE_VARCHAR, -1, 1, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "int2vector", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "oidvector", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "pg_node_tree", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "pg_lsn", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "_oid", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "_text", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "_aclitem", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "_float4", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "_float8", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "_int2", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "_real", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "_char", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "pg_dependencies", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "pg_ndistinct", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "anyarray", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "xid", TDS_TYPE_INTEGER, 4, 1, TDS_SEND_INTEGER, TDS_RECV_INVALID}, + {"pg_catalog", "cid", TDS_TYPE_INTEGER, 4, 1, TDS_SEND_INTEGER, TDS_RECV_INVALID}, + {"pg_catalog", "tid", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "inet", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "interval", TDS_TYPE_VARCHAR, -1, 2, TDS_SEND_VARCHAR, TDS_RECV_INVALID}, + {"pg_catalog", "bytea", TDS_TYPE_VARBINARY, -1, 2, TDS_SEND_VARBINARY, TDS_RECV_INVALID} }; -size_t TdsIoFunctionRawData_datasize = lengthof(TdsIoFunctionRawData_data); +size_t TdsIoFunctionRawData_datasize = lengthof(TdsIoFunctionRawData_data); diff --git a/contrib/babelfishpg_tds/src/backend/tds/tds_srv.c b/contrib/babelfishpg_tds/src/backend/tds/tds_srv.c index 25da2ae2ea..a3dc60bbcc 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tds_srv.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tds_srv.c @@ -40,7 +40,7 @@ #include "src/include/err_handler.h" #include "src/include/guc.h" -static listen_init_hook_type prev_listen_init; +static listen_init_hook_type prev_listen_init; static bool LoadedSSL = false; @@ -52,17 +52,17 @@ static ErrorContextCallback tdserrcontext; TdsErrorContextData *TdsErrorContext = NULL; -static int pe_accept(pgsocket server_fd, Port *port); +static int pe_accept(pgsocket server_fd, Port *port); static void pe_listen_init(void); static void pe_close(pgsocket server_fd); static void pe_tds_init(void); -static int pe_start(Port *port); +static int pe_start(Port *port); static void pe_authenticate(Port *port, const char **username); static void pe_mainfunc(Port *port) pg_attribute_noreturn(); static void pe_send_message(ErrorData *edata); static void pe_send_ready_for_query(CommandDest dest); -static int pe_read_command(StringInfo inBuf); -static int pe_process_command(void); +static int pe_read_command(StringInfo inBuf); +static int pe_process_command(void); static void pe_end_command(QueryCompletion *qc, CommandDest dest); static void pe_report_param_status(const char *name, char *val); static void socket_close(int code, Datum arg); @@ -78,7 +78,7 @@ static ProtocolExtensionConfig pe_config = { pe_authenticate, pe_mainfunc, pe_send_message, - NULL, /* not interested in cancel key */ + NULL, /* not interested in cancel key */ NULL, NULL, pe_send_ready_for_query, @@ -161,14 +161,13 @@ pe_tds_init(void) /* * If this is a TDS client, we install the TDS specific protocol function - * hooks. - * XXX: All of them should be removed in future. + * hooks. XXX: All of them should be removed in future. */ lookup_param_hook = TdsFindParam; /* Set up a rendezvous point with pltsql plugin */ pltsql_plugin_handler_ptr_tmp = (PLtsql_protocol_plugin **) - find_rendezvous_variable("PLtsql_protocol_plugin"); + find_rendezvous_variable("PLtsql_protocol_plugin"); /* unlikely */ if (!pltsql_plugin_handler_ptr_tmp) @@ -220,19 +219,19 @@ pe_tds_init(void) static int pe_start(Port *port) { - int rc; - MemoryContext oldContext; + int rc; + MemoryContext oldContext; /* we're ready to begin the communication with the TDS client */ - if((pltsql_plugin_handler_ptr)) + if ((pltsql_plugin_handler_ptr)) pltsql_plugin_handler_ptr->is_tds_client = true; /* - * Initialise The Global Variable TdsErrorContext, which is - * to be used throughout TDS. We could have allocated the same - * in TdsMemoryContext. But, during reset connection, we reset - * the same. We don't want to reset TdsErrorContext at that point - * of time. So, allocate the memory in TopMemoryContext. + * Initialise The Global Variable TdsErrorContext, which is to be used + * throughout TDS. We could have allocated the same in TdsMemoryContext. + * But, during reset connection, we reset the same. We don't want to + * reset TdsErrorContext at that point of time. So, allocate the memory + * in TopMemoryContext. */ oldContext = MemoryContextSwitchTo(TopMemoryContext); TdsErrorContext = palloc(sizeof(TdsErrorContextData)); @@ -319,7 +318,7 @@ pe_authenticate(Port *port, const char **username) /* * Now perform authentication exchange. */ - TdsClientAuthentication(port); /* might not return, if failure */ + TdsClientAuthentication(port); /* might not return, if failure */ /* * Done with authentication. Disable the timeout, and log if needed. @@ -336,7 +335,7 @@ pe_authenticate(Port *port, const char **username) port->user_name); if (port->application_name) appendStringInfo(&logmsg, _(" application=%s,"), - port->application_name); + port->application_name); appendStringInfo(&logmsg, _(" Tds Version=0x%X."), GetClientTDSVersion()); @@ -346,7 +345,7 @@ pe_authenticate(Port *port, const char **username) set_ps_display("startup"); - ClientAuthInProgress = false; /* client_min_messages is active now */ + ClientAuthInProgress = false; /* client_min_messages is active now */ *username = port->user_name; } @@ -355,10 +354,9 @@ static void pe_mainfunc(Port *port) { /* - * This protocol doesn't need anything other than the default - * behavior of PostgresMain(). Note that PostgresMain() will - * connect to the database and in turn will call our - * pe_authenticate() function. + * This protocol doesn't need anything other than the default behavior of + * PostgresMain(). Note that PostgresMain() will connect to the database + * and in turn will call our pe_authenticate() function. */ PostgresMain(port->database_name, port->user_name); @@ -400,7 +398,7 @@ pe_send_ready_for_query(CommandDest dest) static int pe_read_command(StringInfo inBuf) { - int rc; + int rc; /* Push the error context */ tdserrcontext.callback = TdsErrorContextCallback; @@ -418,7 +416,7 @@ pe_read_command(StringInfo inBuf) static int pe_process_command() { - int result; + int result; /* Push the error context */ tdserrcontext.callback = TdsErrorContextCallback; @@ -427,12 +425,14 @@ pe_process_command() error_context_stack = &tdserrcontext; result = TdsSocketBackend(); + /* * If no transaction is on-going, enforce transaction state cleanup before - * calling pgstat_report_stat function which requires a clean transaction state. + * calling pgstat_report_stat function which requires a clean transaction + * state. */ if (!IsTransactionOrTransactionBlock()) - Cleanup_xact_PgStat(); + Cleanup_xact_PgStat(); /* Pop the error context stack */ error_context_stack = tdserrcontext.previous; diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdsbulkload.c b/contrib/babelfishpg_tds/src/backend/tds/tdsbulkload.c index 2fbe651aa7..fbe82ef7e3 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tdsbulkload.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tdsbulkload.c @@ -29,11 +29,11 @@ #include "src/include/tds_typeio.h" static StringInfo SetBulkLoadRowData(TDSRequestBulkLoad request, StringInfo message); -void ProcessBCPRequest(TDSRequest request); +void ProcessBCPRequest(TDSRequest request); static void FetchMoreBcpData(StringInfo *message, int dataLenToRead); static void FetchMoreBcpPlpData(StringInfo *message, int dataLenToRead); -static int ReadBcpPlp(ParameterToken temp, StringInfo *message, TDSRequestBulkLoad request); -uint64_t offset = 0; +static int ReadBcpPlp(ParameterToken temp, StringInfo *message, TDSRequestBulkLoad request); +uint64_t offset = 0; #define COLUMNMETADATA_HEADER_LEN sizeof(uint32_t) + sizeof(uint16) + 1 #define FIXED_LEN_TYPE_COLUMNMETADATA_LEN 1 @@ -89,23 +89,23 @@ do \ static void FetchMoreBcpData(StringInfo *message, int dataLenToRead) { - StringInfo temp; - int ret; + StringInfo temp; + int ret; /* Unlikely that message will be NULL. */ if ((*message) == NULL) ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("Protocol violation: Message data is NULL"))); + errmsg("Protocol violation: Message data is NULL"))); /* - * If previous return value was 1 then that means that we have reached the EOM. - * No data left to read, we shall throw an error if we reach here. + * If previous return value was 1 then that means that we have reached the + * EOM. No data left to read, we shall throw an error if we reach here. */ if (TdsGetRecvPacketEomStatus()) ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("Trying to read more data than available in BCP request."))); + errmsg("Trying to read more data than available in BCP request."))); temp = makeStringInfo(); appendBinaryStringInfo(temp, (*message)->data + offset, (*message)->len - offset); @@ -115,14 +115,12 @@ FetchMoreBcpData(StringInfo *message, int dataLenToRead) pfree((*message)); /* - * Keep fetching for additional packets until we have enough - * data to read. + * Keep fetching for additional packets until we have enough data to read. */ while (dataLenToRead > temp->len) { /* - * We should hold the interrupts until we read the next - * request frame. + * We should hold the interrupts until we read the next request frame. */ HOLD_CANCEL_INTERRUPTS(); ret = TdsReadNextPendingBcpRequest(temp); @@ -136,7 +134,7 @@ FetchMoreBcpData(StringInfo *message, int dataLenToRead) pfree(temp); ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("EOF on TDS socket while fetching For Bulk Load Request"))); + errmsg("EOF on TDS socket while fetching For Bulk Load Request"))); return; } } @@ -152,32 +150,30 @@ FetchMoreBcpData(StringInfo *message, int dataLenToRead) static void FetchMoreBcpPlpData(StringInfo *message, int dataLenToRead) { - int ret; + int ret; /* Unlikely that message will be NULL. */ if ((*message) == NULL) ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("Protocol violation: Message data is NULL"))); + errmsg("Protocol violation: Message data is NULL"))); /* - * If previous return value was 1 then that means that we have reached the EOM. - * No data left to read, we shall throw an error if we reach here. + * If previous return value was 1 then that means that we have reached the + * EOM. No data left to read, we shall throw an error if we reach here. */ if (TdsGetRecvPacketEomStatus()) ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("Trying to read more data than available in BCP request."))); + errmsg("Trying to read more data than available in BCP request."))); /* - * Keep fetching for additional packets until we have enough - * data to read. + * Keep fetching for additional packets until we have enough data to read. */ while (dataLenToRead + offset > (*message)->len) { /* - * We should hold the interrupts until we read the next - * request frame. + * We should hold the interrupts until we read the next request frame. */ HOLD_CANCEL_INTERRUPTS(); ret = TdsReadNextPendingBcpRequest(*message); @@ -189,7 +185,7 @@ FetchMoreBcpPlpData(StringInfo *message, int dataLenToRead) TdsErrorContext->err_text = "EOF on TDS socket while fetching For Bulk Load Request"; ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("EOF on TDS socket while fetching For Bulk Load Request"))); + errmsg("EOF on TDS socket while fetching For Bulk Load Request"))); return; } } @@ -203,24 +199,24 @@ FetchMoreBcpPlpData(StringInfo *message, int dataLenToRead) TDSRequest GetBulkLoadRequest(StringInfo message) { - TDSRequestBulkLoad request; - uint16_t colCount; - BulkLoadColMetaData *colmetadata; - uint32_t collation; + TDSRequestBulkLoad request; + uint16_t colCount; + BulkLoadColMetaData *colmetadata; + uint32_t collation; TdsErrorContext->err_text = "Fetching Bulk Load Request"; TDSInstrumentation(INSTR_TDS_BULK_LOAD_REQUEST); request = palloc0(sizeof(TDSRequestBulkLoadData)); - request->rowData = NIL; - request->reqType = TDS_REQUEST_BULK_LOAD; + request->rowData = NIL; + request->reqType = TDS_REQUEST_BULK_LOAD; - if(unlikely((uint8_t)message->data[offset] != TDS_TOKEN_COLMETADATA)) + if (unlikely((uint8_t) message->data[offset] != TDS_TOKEN_COLMETADATA)) ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The incoming tabular data stream (TDS) Bulk Load Request (BulkLoadBCP) protocol stream is incorrect. " - "unexpected token encountered processing the request."))); + errmsg("The incoming tabular data stream (TDS) Bulk Load Request (BulkLoadBCP) protocol stream is incorrect. " + "unexpected token encountered processing the request."))); offset++; @@ -245,7 +241,7 @@ GetBulkLoadRequest(StringInfo message) colmetadata[currentColumn].columnTdsType = message->data[offset++]; /* Datatype specific Column Metadata. */ - switch(colmetadata[currentColumn].columnTdsType) + switch (colmetadata[currentColumn].columnTdsType) { case TDS_TYPE_INTEGER: case TDS_TYPE_BIT: @@ -255,190 +251,194 @@ GetBulkLoadRequest(StringInfo message) case TDS_TYPE_UNIQUEIDENTIFIER: CheckMessageHasEnoughBytesToRead(&message, FIXED_LEN_TYPE_COLUMNMETADATA_LEN); colmetadata[currentColumn].maxLen = message->data[offset++]; - break; + break; case TDS_TYPE_DECIMALN: case TDS_TYPE_NUMERICN: CheckMessageHasEnoughBytesToRead(&message, NUMERIC_COLUMNMETADATA_LEN); - colmetadata[currentColumn].maxLen = message->data[offset++]; + colmetadata[currentColumn].maxLen = message->data[offset++]; colmetadata[currentColumn].precision = message->data[offset++]; - colmetadata[currentColumn].scale = message->data[offset++]; - break; + colmetadata[currentColumn].scale = message->data[offset++]; + break; case TDS_TYPE_CHAR: case TDS_TYPE_VARCHAR: case TDS_TYPE_NCHAR: case TDS_TYPE_NVARCHAR: - { - CheckMessageHasEnoughBytesToRead(&message, STRING_COLUMNMETADATA_LEN); - memcpy(&colmetadata[currentColumn].maxLen, &message->data[offset], sizeof(uint16)); - offset += sizeof(uint16); - - memcpy(&collation, &message->data[offset], sizeof(uint32_t)); - offset += sizeof(uint32_t); - colmetadata[currentColumn].sortId = message->data[offset++]; - colmetadata[currentColumn].encoding = TdsGetEncoding(collation); - } - break; - case TDS_TYPE_TEXT: - case TDS_TYPE_NTEXT: - case TDS_TYPE_IMAGE: - { - uint16_t tableLen = 0; - CheckMessageHasEnoughBytesToRead(&message, sizeof(uint32_t)); - memcpy(&colmetadata[currentColumn].maxLen, &message->data[offset], sizeof(uint32_t)); - offset += sizeof(uint32_t); - - /* Read collation(LICD) and sort-id for TEXT and NTEXT. */ - if (colmetadata[currentColumn].columnTdsType == TDS_TYPE_TEXT || - colmetadata[currentColumn].columnTdsType == TDS_TYPE_NTEXT) { - CheckMessageHasEnoughBytesToRead(&message, sizeof(uint32_t) + 1); + CheckMessageHasEnoughBytesToRead(&message, STRING_COLUMNMETADATA_LEN); + memcpy(&colmetadata[currentColumn].maxLen, &message->data[offset], sizeof(uint16)); + offset += sizeof(uint16); + memcpy(&collation, &message->data[offset], sizeof(uint32_t)); offset += sizeof(uint32_t); colmetadata[currentColumn].sortId = message->data[offset++]; colmetadata[currentColumn].encoding = TdsGetEncoding(collation); } + break; + case TDS_TYPE_TEXT: + case TDS_TYPE_NTEXT: + case TDS_TYPE_IMAGE: + { + uint16_t tableLen = 0; - CheckMessageHasEnoughBytesToRead(&message, sizeof(uint16_t)); - memcpy(&tableLen, &message->data[offset], sizeof(uint16_t)); - offset += sizeof(uint16_t); + CheckMessageHasEnoughBytesToRead(&message, sizeof(uint32_t)); + memcpy(&colmetadata[currentColumn].maxLen, &message->data[offset], sizeof(uint32_t)); + offset += sizeof(uint32_t); - /* Skip table name for now. */ - CheckMessageHasEnoughBytesToRead(&message, tableLen * 2); - offset += tableLen * 2; - } - break; + /* Read collation(LICD) and sort-id for TEXT and NTEXT. */ + if (colmetadata[currentColumn].columnTdsType == TDS_TYPE_TEXT || + colmetadata[currentColumn].columnTdsType == TDS_TYPE_NTEXT) + { + CheckMessageHasEnoughBytesToRead(&message, sizeof(uint32_t) + 1); + memcpy(&collation, &message->data[offset], sizeof(uint32_t)); + offset += sizeof(uint32_t); + colmetadata[currentColumn].sortId = message->data[offset++]; + colmetadata[currentColumn].encoding = TdsGetEncoding(collation); + } + + CheckMessageHasEnoughBytesToRead(&message, sizeof(uint16_t)); + memcpy(&tableLen, &message->data[offset], sizeof(uint16_t)); + offset += sizeof(uint16_t); + + /* Skip table name for now. */ + CheckMessageHasEnoughBytesToRead(&message, tableLen * 2); + offset += tableLen * 2; + } + break; case TDS_TYPE_XML: - { - CheckMessageHasEnoughBytesToRead(&message, 1); - colmetadata[currentColumn].maxLen = message->data[offset++]; - } - break; + { + CheckMessageHasEnoughBytesToRead(&message, 1); + colmetadata[currentColumn].maxLen = message->data[offset++]; + } + break; case TDS_TYPE_DATETIME2: - { - CheckMessageHasEnoughBytesToRead(&message, FIXED_LEN_TYPE_COLUMNMETADATA_LEN); - colmetadata[currentColumn].scale = message->data[offset++]; - colmetadata[currentColumn].maxLen = 8; - } - break; + { + CheckMessageHasEnoughBytesToRead(&message, FIXED_LEN_TYPE_COLUMNMETADATA_LEN); + colmetadata[currentColumn].scale = message->data[offset++]; + colmetadata[currentColumn].maxLen = 8; + } + break; case TDS_TYPE_TIME: - { - CheckMessageHasEnoughBytesToRead(&message, FIXED_LEN_TYPE_COLUMNMETADATA_LEN); - colmetadata[currentColumn].scale = message->data[offset++]; - colmetadata[currentColumn].maxLen = 5; - } - break; + { + CheckMessageHasEnoughBytesToRead(&message, FIXED_LEN_TYPE_COLUMNMETADATA_LEN); + colmetadata[currentColumn].scale = message->data[offset++]; + colmetadata[currentColumn].maxLen = 5; + } + break; case TDS_TYPE_DATETIMEOFFSET: - { - CheckMessageHasEnoughBytesToRead(&message, FIXED_LEN_TYPE_COLUMNMETADATA_LEN); - colmetadata[currentColumn].scale = message->data[offset++]; - colmetadata[currentColumn].maxLen = 10; - } - break; + { + CheckMessageHasEnoughBytesToRead(&message, FIXED_LEN_TYPE_COLUMNMETADATA_LEN); + colmetadata[currentColumn].scale = message->data[offset++]; + colmetadata[currentColumn].maxLen = 10; + } + break; case TDS_TYPE_BINARY: case TDS_TYPE_VARBINARY: - { - uint16 plp; - CheckMessageHasEnoughBytesToRead(&message, BINARY_COLUMNMETADATA_LEN); - memcpy(&plp, &message->data[offset], sizeof(uint16)); - offset += sizeof(uint16); - colmetadata[currentColumn].maxLen = plp; - } - break; + { + uint16 plp; + + CheckMessageHasEnoughBytesToRead(&message, BINARY_COLUMNMETADATA_LEN); + memcpy(&plp, &message->data[offset], sizeof(uint16)); + offset += sizeof(uint16); + colmetadata[currentColumn].maxLen = plp; + } + break; case TDS_TYPE_DATE: colmetadata[currentColumn].maxLen = 3; - break; + break; case TDS_TYPE_SQLVARIANT: CheckMessageHasEnoughBytesToRead(&message, SQL_VARIANT_COLUMNMETADATA_LEN); memcpy(&colmetadata[currentColumn].maxLen, &message->data[offset], sizeof(uint32_t)); offset += sizeof(uint32_t); - break; - /* - * Below cases are for variant types; in case of fixed length datatype columns, with - * a Not NUll constraint, makes use of this type as an optimisation for not receiving - * the the lengths for the column metadata and row data. - */ + break; + + /* + * Below cases are for variant types; in case of fixed length + * datatype columns, with a Not NUll constraint, makes use of + * this type as an optimisation for not receiving the the + * lengths for the column metadata and row data. + */ case VARIANT_TYPE_INT: - { - colmetadata[currentColumn].columnTdsType = TDS_TYPE_INTEGER; - colmetadata[currentColumn].variantType = true; - colmetadata[currentColumn].maxLen = TDS_MAXLEN_INT; - } - break; + { + colmetadata[currentColumn].columnTdsType = TDS_TYPE_INTEGER; + colmetadata[currentColumn].variantType = true; + colmetadata[currentColumn].maxLen = TDS_MAXLEN_INT; + } + break; case VARIANT_TYPE_BIT: - { - colmetadata[currentColumn].columnTdsType = TDS_TYPE_BIT; - colmetadata[currentColumn].variantType = true; - colmetadata[currentColumn].maxLen = TDS_MAXLEN_BIT; - } - break; + { + colmetadata[currentColumn].columnTdsType = TDS_TYPE_BIT; + colmetadata[currentColumn].variantType = true; + colmetadata[currentColumn].maxLen = TDS_MAXLEN_BIT; + } + break; case VARIANT_TYPE_BIGINT: - { - colmetadata[currentColumn].columnTdsType = TDS_TYPE_INTEGER; - colmetadata[currentColumn].variantType = true; - colmetadata[currentColumn].maxLen = TDS_MAXLEN_BIGINT; - } - break; + { + colmetadata[currentColumn].columnTdsType = TDS_TYPE_INTEGER; + colmetadata[currentColumn].variantType = true; + colmetadata[currentColumn].maxLen = TDS_MAXLEN_BIGINT; + } + break; case VARIANT_TYPE_SMALLINT: - { - colmetadata[currentColumn].columnTdsType = TDS_TYPE_INTEGER; - colmetadata[currentColumn].variantType = true; - colmetadata[currentColumn].maxLen = TDS_MAXLEN_SMALLINT; - } - break; + { + colmetadata[currentColumn].columnTdsType = TDS_TYPE_INTEGER; + colmetadata[currentColumn].variantType = true; + colmetadata[currentColumn].maxLen = TDS_MAXLEN_SMALLINT; + } + break; case VARIANT_TYPE_TINYINT: - { - colmetadata[currentColumn].columnTdsType = TDS_TYPE_INTEGER; - colmetadata[currentColumn].variantType = true; - colmetadata[currentColumn].maxLen = TDS_MAXLEN_TINYINT; - } - break; + { + colmetadata[currentColumn].columnTdsType = TDS_TYPE_INTEGER; + colmetadata[currentColumn].variantType = true; + colmetadata[currentColumn].maxLen = TDS_MAXLEN_TINYINT; + } + break; case VARIANT_TYPE_REAL: - { - colmetadata[currentColumn].columnTdsType = TDS_TYPE_FLOAT; - colmetadata[currentColumn].variantType = true; - colmetadata[currentColumn].maxLen = TDS_MAXLEN_FLOAT4; - } - break; + { + colmetadata[currentColumn].columnTdsType = TDS_TYPE_FLOAT; + colmetadata[currentColumn].variantType = true; + colmetadata[currentColumn].maxLen = TDS_MAXLEN_FLOAT4; + } + break; case VARIANT_TYPE_FLOAT: - { - colmetadata[currentColumn].columnTdsType = TDS_TYPE_FLOAT; - colmetadata[currentColumn].variantType = true; - colmetadata[currentColumn].maxLen = TDS_MAXLEN_FLOAT8; - } - break; + { + colmetadata[currentColumn].columnTdsType = TDS_TYPE_FLOAT; + colmetadata[currentColumn].variantType = true; + colmetadata[currentColumn].maxLen = TDS_MAXLEN_FLOAT8; + } + break; case VARIANT_TYPE_DATETIME: - { - colmetadata[currentColumn].columnTdsType = TDS_TYPE_DATETIMEN; - colmetadata[currentColumn].variantType = true; - colmetadata[currentColumn].maxLen = TDS_MAXLEN_DATETIME; - } - break; + { + colmetadata[currentColumn].columnTdsType = TDS_TYPE_DATETIMEN; + colmetadata[currentColumn].variantType = true; + colmetadata[currentColumn].maxLen = TDS_MAXLEN_DATETIME; + } + break; case VARIANT_TYPE_SMALLDATETIME: - { - colmetadata[currentColumn].columnTdsType = TDS_TYPE_DATETIMEN; - colmetadata[currentColumn].variantType = true; - colmetadata[currentColumn].maxLen = TDS_MAXLEN_SMALLDATETIME; - } - break; + { + colmetadata[currentColumn].columnTdsType = TDS_TYPE_DATETIMEN; + colmetadata[currentColumn].variantType = true; + colmetadata[currentColumn].maxLen = TDS_MAXLEN_SMALLDATETIME; + } + break; case VARIANT_TYPE_MONEY: - { - colmetadata[currentColumn].columnTdsType = TDS_TYPE_MONEYN; - colmetadata[currentColumn].variantType = true; - colmetadata[currentColumn].maxLen = TDS_MAXLEN_MONEY; - } - break; + { + colmetadata[currentColumn].columnTdsType = TDS_TYPE_MONEYN; + colmetadata[currentColumn].variantType = true; + colmetadata[currentColumn].maxLen = TDS_MAXLEN_MONEY; + } + break; case VARIANT_TYPE_SMALLMONEY: - { - colmetadata[currentColumn].columnTdsType = TDS_TYPE_MONEYN; - colmetadata[currentColumn].variantType = true; - colmetadata[currentColumn].maxLen = TDS_MAXLEN_SMALLMONEY; - } - break; + { + colmetadata[currentColumn].columnTdsType = TDS_TYPE_MONEYN; + colmetadata[currentColumn].variantType = true; + colmetadata[currentColumn].maxLen = TDS_MAXLEN_SMALLMONEY; + } + break; default: - ereport(ERROR, + ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The incoming tabular data stream (TDS) is incorrect. " - "Data type 0x%02X is unknown.", colmetadata[currentColumn].columnTdsType))); + errmsg("The incoming tabular data stream (TDS) is incorrect. " + "Data type 0x%02X is unknown.", colmetadata[currentColumn].columnTdsType))); } /* Column Name */ @@ -446,16 +446,16 @@ GetBulkLoadRequest(StringInfo message) memcpy(&colmetadata[currentColumn].colNameLen, &message->data[offset++], sizeof(uint8_t)); CheckMessageHasEnoughBytesToRead(&message, colmetadata[currentColumn].colNameLen * 2); - colmetadata[currentColumn].colName = (char *)palloc0(colmetadata[currentColumn].colNameLen * sizeof(char) * 2 + 1); + colmetadata[currentColumn].colName = (char *) palloc0(colmetadata[currentColumn].colNameLen * sizeof(char) * 2 + 1); memcpy(colmetadata[currentColumn].colName, &message->data[offset], - colmetadata[currentColumn].colNameLen * 2); + colmetadata[currentColumn].colNameLen * 2); colmetadata[currentColumn].colName[colmetadata[currentColumn].colNameLen * 2] = '\0'; offset += colmetadata[currentColumn].colNameLen * 2; } request->firstMessage = makeStringInfo(); appendBinaryStringInfo(request->firstMessage, message->data, message->len); - return (TDSRequest)request; + return (TDSRequest) request; } /* @@ -467,9 +467,10 @@ static StringInfo SetBulkLoadRowData(TDSRequestBulkLoad request, StringInfo message) { BulkLoadColMetaData *colmetadata = request->colMetaData; - int retStatus = 0; - uint32_t len; - StringInfo temp = palloc0(sizeof(StringInfoData)); + int retStatus = 0; + uint32_t len; + StringInfo temp = palloc0(sizeof(StringInfoData)); + request->rowCount = 0; request->rowData = NIL; request->currentBatchSize = 0; @@ -477,24 +478,25 @@ SetBulkLoadRowData(TDSRequestBulkLoad request, StringInfo message) CheckMessageHasEnoughBytesToRead(&message, 1); /* Loop over each row. */ - while((uint8_t)message->data[offset] == TDS_TOKEN_ROW - && request->currentBatchSize < pltsql_plugin_handler_ptr->get_insert_bulk_kilobytes_per_batch() * 1024 - && request->rowCount < pltsql_plugin_handler_ptr->get_insert_bulk_rows_per_batch()) + while ((uint8_t) message->data[offset] == TDS_TOKEN_ROW + && request->currentBatchSize < pltsql_plugin_handler_ptr->get_insert_bulk_kilobytes_per_batch() * 1024 + && request->rowCount < pltsql_plugin_handler_ptr->get_insert_bulk_rows_per_batch()) { - int i = 0; /* Current Column Number. */ + int i = 0; /* Current Column Number. */ BulkLoadRowData *rowData = palloc0(sizeof(BulkLoadRowData)); + request->rowCount++; rowData->columnValues = palloc0(request->colCount * sizeof(Datum)); - rowData->isNull = palloc0(request->colCount * sizeof(bool)); + rowData->isNull = palloc0(request->colCount * sizeof(bool)); offset++; request->currentBatchSize++; - while(i != request->colCount) /* Loop over each column. */ + while (i != request->colCount) /* Loop over each column. */ { len = 0; - switch(colmetadata[i].columnTdsType) + switch (colmetadata[i].columnTdsType) { case TDS_TYPE_INTEGER: case TDS_TYPE_BIT: @@ -506,116 +508,122 @@ SetBulkLoadRowData(TDSRequestBulkLoad request, StringInfo message) case TDS_TYPE_MONEYN: case TDS_TYPE_UNIQUEIDENTIFIER: case TDS_TYPE_DATETIMEOFFSET: - { - if (colmetadata[i].variantType) { - len = colmetadata[i].maxLen; + if (colmetadata[i].variantType) + { + len = colmetadata[i].maxLen; + } + else + { + CheckMessageHasEnoughBytesToRead(&message, 1); + len = message->data[offset++]; + request->currentBatchSize++; + + if (len == 0) /* null */ + { + rowData->isNull[i] = true; + i++; + continue; + } + } + CheckForInvalidLength(len, request, i); + + CheckMessageHasEnoughBytesToRead(&message, len); + + /* Build temp Stringinfo. */ + temp->data = &message->data[offset]; + temp->len = len; + temp->maxlen = colmetadata[i].maxLen; + temp->cursor = 0; + + /* + * Create and store the appropriate datum for this + * column. + */ + switch (colmetadata[i].columnTdsType) + { + case TDS_TYPE_INTEGER: + case TDS_TYPE_BIT: + rowData->columnValues[i] = TdsTypeIntegerToDatum(temp, colmetadata[i].maxLen); + break; + case TDS_TYPE_FLOAT: + rowData->columnValues[i] = TdsTypeFloatToDatum(temp, colmetadata[i].maxLen); + break; + case TDS_TYPE_TIME: + rowData->columnValues[i] = TdsTypeTimeToDatum(temp, colmetadata[i].scale, len); + break; + case TDS_TYPE_DATE: + rowData->columnValues[i] = TdsTypeDateToDatum(temp); + break; + case TDS_TYPE_DATETIME2: + rowData->columnValues[i] = TdsTypeDatetime2ToDatum(temp, colmetadata[i].scale, temp->len); + break; + case TDS_TYPE_DATETIMEN: + if (colmetadata[i].maxLen == TDS_MAXLEN_SMALLDATETIME) + rowData->columnValues[i] = TdsTypeSmallDatetimeToDatum(temp); + else + rowData->columnValues[i] = TdsTypeDatetimeToDatum(temp); + break; + case TDS_TYPE_DATETIMEOFFSET: + rowData->columnValues[i] = TdsTypeDatetimeoffsetToDatum(temp, colmetadata[i].scale, temp->len); + break; + case TDS_TYPE_MONEYN: + if (colmetadata[i].maxLen == TDS_MAXLEN_SMALLMONEY) + rowData->columnValues[i] = TdsTypeSmallMoneyToDatum(temp); + else + rowData->columnValues[i] = TdsTypeMoneyToDatum(temp); + break; + case TDS_TYPE_UNIQUEIDENTIFIER: + rowData->columnValues[i] = TdsTypeUIDToDatum(temp); + break; + } + + offset += len; + request->currentBatchSize += len; } - else + break; + case TDS_TYPE_NUMERICN: + case TDS_TYPE_DECIMALN: { + if (colmetadata[i].scale > colmetadata[i].precision) + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The incoming tabular data stream (TDS) Bulk Load Request (BulkLoadBCP) protocol stream is incorrect. " + "Row %d, column %d: The supplied value is not a valid instance of data type Numeric/Decimal. " + "Check the source data for invalid values. An example of an invalid value is data of numeric type with scale greater than precision.", + request->rowCount, i + 1))); + CheckMessageHasEnoughBytesToRead(&message, 1); + len = message->data[offset++]; request->currentBatchSize++; - - if (len == 0) /* null */ + if (len == 0) /* null */ { rowData->isNull[i] = true; i++; continue; } - } - CheckForInvalidLength(len, request, i); - - CheckMessageHasEnoughBytesToRead(&message, len); - /* Build temp Stringinfo. */ - temp->data = &message->data[offset]; - temp->len = len; - temp->maxlen = colmetadata[i].maxLen; - temp->cursor = 0; + CheckForInvalidLength(len, request, i); - /* Create and store the appropriate datum for this column. */ - switch(colmetadata[i].columnTdsType) - { - case TDS_TYPE_INTEGER: - case TDS_TYPE_BIT: - rowData->columnValues[i] = TdsTypeIntegerToDatum(temp, colmetadata[i].maxLen); - break; - case TDS_TYPE_FLOAT: - rowData->columnValues[i] = TdsTypeFloatToDatum(temp, colmetadata[i].maxLen); - break; - case TDS_TYPE_TIME: - rowData->columnValues[i] = TdsTypeTimeToDatum(temp, colmetadata[i].scale, len); - break; - case TDS_TYPE_DATE: - rowData->columnValues[i] = TdsTypeDateToDatum(temp); - break; - case TDS_TYPE_DATETIME2: - rowData->columnValues[i] = TdsTypeDatetime2ToDatum(temp, colmetadata[i].scale, temp->len); - break; - case TDS_TYPE_DATETIMEN: - if (colmetadata[i].maxLen == TDS_MAXLEN_SMALLDATETIME) - rowData->columnValues[i] = TdsTypeSmallDatetimeToDatum(temp); - else - rowData->columnValues[i] = TdsTypeDatetimeToDatum(temp); - break; - case TDS_TYPE_DATETIMEOFFSET: - rowData->columnValues[i] = TdsTypeDatetimeoffsetToDatum(temp, colmetadata[i].scale, temp->len); - break; - case TDS_TYPE_MONEYN: - if (colmetadata[i].maxLen == TDS_MAXLEN_SMALLMONEY) - rowData->columnValues[i] = TdsTypeSmallMoneyToDatum(temp); - else - rowData->columnValues[i] = TdsTypeMoneyToDatum(temp); - break; - case TDS_TYPE_UNIQUEIDENTIFIER: - rowData->columnValues[i] = TdsTypeUIDToDatum(temp); - break; - } + CheckMessageHasEnoughBytesToRead(&message, len); - offset += len; - request->currentBatchSize += len; - } - break; - case TDS_TYPE_NUMERICN: - case TDS_TYPE_DECIMALN: - { - if (colmetadata[i].scale > colmetadata[i].precision) - ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The incoming tabular data stream (TDS) Bulk Load Request (BulkLoadBCP) protocol stream is incorrect. " - "Row %d, column %d: The supplied value is not a valid instance of data type Numeric/Decimal. " - "Check the source data for invalid values. An example of an invalid value is data of numeric type with scale greater than precision.", - request->rowCount, i + 1))); + /* Build temp Stringinfo. */ + temp->data = &message->data[offset]; + temp->len = len; + temp->maxlen = colmetadata[i].maxLen; + temp->cursor = 0; - CheckMessageHasEnoughBytesToRead(&message, 1); + /* + * Create and store the appropriate datum for this + * column. + */ + rowData->columnValues[i] = TdsTypeNumericToDatum(temp, colmetadata[i].scale); - len = message->data[offset++]; - request->currentBatchSize++; - if (len == 0) /* null */ - { - rowData->isNull[i] = true; - i++; - continue; + offset += len; + request->currentBatchSize += len; } - - CheckForInvalidLength(len, request, i); - - CheckMessageHasEnoughBytesToRead(&message, len); - - /* Build temp Stringinfo. */ - temp->data = &message->data[offset]; - temp->len = len; - temp->maxlen = colmetadata[i].maxLen; - temp->cursor = 0; - - /* Create and store the appropriate datum for this column. */ - rowData->columnValues[i] = TdsTypeNumericToDatum(temp, colmetadata[i].scale); - - offset += len; - request->currentBatchSize += len; - } - break; + break; case TDS_TYPE_CHAR: case TDS_TYPE_VARCHAR: @@ -623,198 +631,221 @@ SetBulkLoadRowData(TDSRequestBulkLoad request, StringInfo message) case TDS_TYPE_NVARCHAR: case TDS_TYPE_BINARY: case TDS_TYPE_VARBINARY: - { - if (colmetadata[i].maxLen != 0xffff) { - CheckMessageHasEnoughBytesToRead(&message, sizeof(short)); - memcpy(&len, &message->data[offset], sizeof(short)); - offset += sizeof(short); - request->currentBatchSize += sizeof(short); - if (len != 0xffff) + if (colmetadata[i].maxLen != 0xffff) + { + CheckMessageHasEnoughBytesToRead(&message, sizeof(short)); + memcpy(&len, &message->data[offset], sizeof(short)); + offset += sizeof(short); + request->currentBatchSize += sizeof(short); + if (len != 0xffff) + { + CheckForInvalidLength(len, request, i); + + CheckMessageHasEnoughBytesToRead(&message, len); + + /* Build temp Stringinfo. */ + temp->data = &message->data[offset]; + temp->len = len; + temp->maxlen = colmetadata[i].maxLen; + temp->cursor = 0; + + offset += len; + request->currentBatchSize += len; + } + else /* null */ + { + rowData->isNull[i] = true; + i++; + continue; + } + } + else { - CheckForInvalidLength(len, request, i); + ParameterToken token = palloc0(sizeof(ParameterTokenData)); + + retStatus = ReadBcpPlp(token, &message, request); + + CheckPLPStatusNotOK(request, retStatus, i); + if (token->isNull) /* null */ + { + rowData->isNull[i] = true; + i++; + token->isNull = false; + continue; + } + + /* Free the previously allocated temp. */ + pfree(temp); + temp = TdsGetPlpStringInfoBufferFromToken(message->data, token); + pfree(token); + } - CheckMessageHasEnoughBytesToRead(&message, len); + /* + * Create and store the appropriate datum for this + * column. + */ + switch (colmetadata[i].columnTdsType) + { + case TDS_TYPE_CHAR: + case TDS_TYPE_VARCHAR: + rowData->columnValues[i] = TdsTypeVarcharToDatum(temp, colmetadata[i].encoding, colmetadata[i].columnTdsType); + break; + case TDS_TYPE_NCHAR: + case TDS_TYPE_NVARCHAR: + rowData->columnValues[i] = TdsTypeNCharToDatum(temp); + break; + case TDS_TYPE_BINARY: + case TDS_TYPE_VARBINARY: + rowData->columnValues[i] = TdsTypeVarbinaryToDatum(temp); + break; + } - /* Build temp Stringinfo. */ - temp->data = &message->data[offset]; - temp->len = len; - temp->maxlen = colmetadata[i].maxLen; - temp->cursor = 0; + /* + * Free temp->data only if this was created as part of + * PLP parsing. We do not free temp pointer since it + * can be re-used for the next iteration. + */ + if (colmetadata[i].maxLen == 0xffff) + pfree(temp->data); + } + break; + case TDS_TYPE_TEXT: + case TDS_TYPE_NTEXT: + case TDS_TYPE_IMAGE: + { + uint8 dataTextPtrLen; - offset += len; - request->currentBatchSize += len; + CheckMessageHasEnoughBytesToRead(&message, 1); + + /* + * Ignore the Data Text Ptr since its currently of no + * use. + */ + dataTextPtrLen = message->data[offset++]; + request->currentBatchSize++; + if (dataTextPtrLen == 0) /* null */ + { + rowData->isNull[i] = true; + i++; + continue; } - else /* null */ + + CheckMessageHasEnoughBytesToRead(&message, dataTextPtrLen + 8 + sizeof(uint32_t)); + + offset += dataTextPtrLen; + request->currentBatchSize += dataTextPtrLen; + offset += 8; /* TODO: Ignored the Data Text + * TimeStamp for now. */ + request->currentBatchSize += 8; + + memcpy(&len, &message->data[offset], sizeof(uint32_t)); + offset += sizeof(uint32_t); + request->currentBatchSize += sizeof(uint32_t); + if (len == 0) /* null */ { rowData->isNull[i] = true; i++; continue; } + + CheckForInvalidLength(len, request, i); + + CheckMessageHasEnoughBytesToRead(&message, len); + + /* Build temp Stringinfo. */ + temp->data = &message->data[offset]; + temp->len = len; + temp->maxlen = colmetadata[i].maxLen; + temp->cursor = 0; + + /* + * Create and store the appropriate datum for this + * column. + */ + switch (colmetadata[i].columnTdsType) + { + case TDS_TYPE_TEXT: + rowData->columnValues[i] = TdsTypeVarcharToDatum(temp, colmetadata[i].encoding, colmetadata[i].columnTdsType); + break; + case TDS_TYPE_NTEXT: + rowData->columnValues[i] = TdsTypeNCharToDatum(temp); + break; + case TDS_TYPE_IMAGE: + rowData->columnValues[i] = TdsTypeVarbinaryToDatum(temp); + break; + } + + offset += len; + request->currentBatchSize += len; } - else + break; + case TDS_TYPE_XML: { ParameterToken token = palloc0(sizeof(ParameterTokenData)); retStatus = ReadBcpPlp(token, &message, request); - CheckPLPStatusNotOK(request, retStatus, i); - if (token->isNull) /* null */ + if (token->isNull) /* null */ { rowData->isNull[i] = true; i++; token->isNull = false; continue; } - /* Free the previously allocated temp. */ pfree(temp); temp = TdsGetPlpStringInfoBufferFromToken(message->data, token); - pfree(token); - } - /* Create and store the appropriate datum for this column. */ - switch(colmetadata[i].columnTdsType) - { - case TDS_TYPE_CHAR: - case TDS_TYPE_VARCHAR: - rowData->columnValues[i] = TdsTypeVarcharToDatum(temp, colmetadata[i].encoding, colmetadata[i].columnTdsType); - break; - case TDS_TYPE_NCHAR: - case TDS_TYPE_NVARCHAR: - rowData->columnValues[i] = TdsTypeNCharToDatum(temp); - break; - case TDS_TYPE_BINARY: - case TDS_TYPE_VARBINARY: - rowData->columnValues[i] = TdsTypeVarbinaryToDatum(temp); - break; - } - /* - * Free temp->data only if this was created as part of PLP parsing. - * We do not free temp pointer since it can be re-used for the next iteration. - */ - if (colmetadata[i].maxLen == 0xffff) - pfree(temp->data); - } - break; - case TDS_TYPE_TEXT: - case TDS_TYPE_NTEXT: - case TDS_TYPE_IMAGE: - { - uint8 dataTextPtrLen; + /* + * Create and store the appropriate datum for this + * column. + */ + rowData->columnValues[i] = TdsTypeXMLToDatum(temp); - CheckMessageHasEnoughBytesToRead(&message, 1); - /* Ignore the Data Text Ptr since its currently of no use. */ - dataTextPtrLen = message->data[offset++]; - request->currentBatchSize++; - if (dataTextPtrLen == 0) /* null */ - { - rowData->isNull[i] = true; - i++; - continue; + /* + * We do not free temp pointer since it can be re-used + * for the next iteration. + */ + pfree(temp->data); + pfree(token); } - - CheckMessageHasEnoughBytesToRead(&message, dataTextPtrLen + 8 + sizeof(uint32_t)); - - offset += dataTextPtrLen; - request->currentBatchSize += dataTextPtrLen; - offset += 8; /* TODO: Ignored the Data Text TimeStamp for now. */ - request->currentBatchSize += 8; - - memcpy(&len, &message->data[offset], sizeof(uint32_t)); - offset += sizeof(uint32_t); - request->currentBatchSize += sizeof(uint32_t); - if (len == 0) /* null */ + break; + case TDS_TYPE_SQLVARIANT: { - rowData->isNull[i] = true; - i++; - continue; - } - - CheckForInvalidLength(len, request, i); + CheckMessageHasEnoughBytesToRead(&message, sizeof(uint32_t)); - CheckMessageHasEnoughBytesToRead(&message, len); + memcpy(&len, &message->data[offset], sizeof(uint32_t)); + offset += sizeof(uint32_t); + request->currentBatchSize += sizeof(uint32_t); - /* Build temp Stringinfo. */ - temp->data = &message->data[offset]; - temp->len = len; - temp->maxlen = colmetadata[i].maxLen; - temp->cursor = 0; + if (len == 0) /* null */ + { + rowData->isNull[i] = true; + i++; + continue; + } - /* Create and store the appropriate datum for this column. */ - switch(colmetadata[i].columnTdsType) - { - case TDS_TYPE_TEXT: - rowData->columnValues[i] = TdsTypeVarcharToDatum(temp, colmetadata[i].encoding, colmetadata[i].columnTdsType); - break; - case TDS_TYPE_NTEXT: - rowData->columnValues[i] = TdsTypeNCharToDatum(temp); - break; - case TDS_TYPE_IMAGE: - rowData->columnValues[i] = TdsTypeVarbinaryToDatum(temp); - break; - } + CheckForInvalidLength(len, request, i); - offset += len; - request->currentBatchSize += len; - } - break; - case TDS_TYPE_XML: - { - ParameterToken token = palloc0(sizeof(ParameterTokenData)); + CheckMessageHasEnoughBytesToRead(&message, len); - retStatus = ReadBcpPlp(token, &message, request); - CheckPLPStatusNotOK(request, retStatus, i); - if (token->isNull) /* null */ - { - rowData->isNull[i] = true; - i++; - token->isNull = false; - continue; - } - /* Free the previously allocated temp. */ - pfree(temp); - temp = TdsGetPlpStringInfoBufferFromToken(message->data, token); - /* Create and store the appropriate datum for this column. */ - rowData->columnValues[i] = TdsTypeXMLToDatum(temp); - - /* We do not free temp pointer since it can be re-used for the next iteration. */ - pfree(temp->data); - pfree(token); - } - break; - case TDS_TYPE_SQLVARIANT: - { - CheckMessageHasEnoughBytesToRead(&message, sizeof(uint32_t)); + /* Build temp Stringinfo. */ + temp->data = &message->data[offset]; + temp->len = len; + temp->maxlen = colmetadata[i].maxLen; + temp->cursor = 0; - memcpy(&len, &message->data[offset], sizeof(uint32_t)); - offset += sizeof(uint32_t); - request->currentBatchSize += sizeof(uint32_t); + /* + * Create and store the appropriate datum for this + * column. + */ + rowData->columnValues[i] = TdsTypeSqlVariantToDatum(temp); - if (len == 0) /* null */ - { - rowData->isNull[i] = true; - i++; - continue; + offset += len; + request->currentBatchSize += len; } - - CheckForInvalidLength(len, request, i); - - CheckMessageHasEnoughBytesToRead(&message, len); - - /* Build temp Stringinfo. */ - temp->data = &message->data[offset]; - temp->len = len; - temp->maxlen = colmetadata[i].maxLen; - temp->cursor = 0; - - /* Create and store the appropriate datum for this column. */ - rowData->columnValues[i] = TdsTypeSqlVariantToDatum(temp); - - offset += len; - request->currentBatchSize += len; - } - break; + break; } i++; } @@ -823,19 +854,19 @@ SetBulkLoadRowData(TDSRequestBulkLoad request, StringInfo message) } /* - * If row count is less than the default batch size then this is the last packet, - * the next byte should be the done token. + * If row count is less than the default batch size then this is the last + * packet, the next byte should be the done token. */ CheckMessageHasEnoughBytesToRead(&message, 1); if (request->rowCount < pltsql_plugin_handler_ptr->get_insert_bulk_rows_per_batch() - && request->currentBatchSize < pltsql_plugin_handler_ptr->get_insert_bulk_kilobytes_per_batch() * 1024 - && (uint8_t)message->data[offset] != TDS_TOKEN_DONE) + && request->currentBatchSize < pltsql_plugin_handler_ptr->get_insert_bulk_kilobytes_per_batch() * 1024 + && (uint8_t) message->data[offset] != TDS_TOKEN_DONE) ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The incoming tabular data stream (TDS) Bulk Load Request (BulkLoadBCP) protocol stream is incorrect. " + errmsg("The incoming tabular data stream (TDS) Bulk Load Request (BulkLoadBCP) protocol stream is incorrect. " "Row %d, unexpected token encountered processing the request. %d", - request->rowCount, (uint8_t)message->data[offset]))); + request->rowCount, (uint8_t) message->data[offset]))); pfree(temp); return message; @@ -849,20 +880,20 @@ SetBulkLoadRowData(TDSRequestBulkLoad request, StringInfo message) void ProcessBCPRequest(TDSRequest request) { - uint64 retValue = 0; + uint64 retValue = 0; TDSRequestBulkLoad req = (TDSRequestBulkLoad) request; - StringInfo message = req->firstMessage; + StringInfo message = req->firstMessage; TdsErrorContext->err_text = "Processing Bulk Load Request"; pgstat_report_activity(STATE_RUNNING, "Processing Bulk Load Request"); while (1) { - int nargs = 0; - Datum *values = NULL; - bool *nulls = NULL; - int count = 0; - ListCell *lc; + int nargs = 0; + Datum *values = NULL; + bool *nulls = NULL; + int count = 0; + ListCell *lc; PG_TRY(); { @@ -870,12 +901,15 @@ ProcessBCPRequest(TDSRequest request) } PG_CATCH(); { - int ret; + int ret; + HOLD_CANCEL_INTERRUPTS(); + /* - * Discard remaining TDS_BULK_LOAD packets only if End of Message has not been reached for the - * current request. Otherwise we have no TDS_BULK_LOAD packets left for the current request - * that need to be discarded. + * Discard remaining TDS_BULK_LOAD packets only if End of Message + * has not been reached for the current request. Otherwise we have + * no TDS_BULK_LOAD packets left for the current request that need + * to be discarded. */ if (!TdsGetRecvPacketEomStatus()) ret = TdsDiscardAllPendingBcpRequest(); @@ -888,6 +922,7 @@ ProcessBCPRequest(TDSRequest request) PG_RE_THROW(); } PG_END_TRY(); + /* * If the row-count is 0 then there are no rows left to be inserted. * We should begin with cleanup. @@ -904,10 +939,11 @@ ProcessBCPRequest(TDSRequest request) nulls = palloc0(nargs * sizeof(bool)); /* Flaten and create a 1-D array of Value & Datums */ - foreach (lc, req->rowData) + foreach(lc, req->rowData) { BulkLoadRowData *row = (BulkLoadRowData *) lfirst(lc); - for(int currentColumn = 0; currentColumn < req->colCount; currentColumn++) + + for (int currentColumn = 0; currentColumn < req->colCount; currentColumn++) { if (row->isNull[currentColumn]) /* null */ nulls[count] = row->isNull[currentColumn]; @@ -917,22 +953,24 @@ ProcessBCPRequest(TDSRequest request) } } - if (req->rowData) /* If any row exists then do an insert. */ + if (req->rowData) /* If any row exists then do an insert. */ { PG_TRY(); { retValue += pltsql_plugin_handler_ptr->bulk_load_callback(req->colCount, - req->rowCount, values, nulls); + req->rowCount, values, nulls); } PG_CATCH(); { - int ret; + int ret; + HOLD_CANCEL_INTERRUPTS(); /* - * Discard remaining TDS_BULK_LOAD packets only if End of Message has not been reached for the - * current request. Otherwise we have no TDS_BULK_LOAD packets left for the current request - * that need to be discarded. + * Discard remaining TDS_BULK_LOAD packets only if End of + * Message has not been reached for the current request. + * Otherwise we have no TDS_BULK_LOAD packets left for the + * current request that need to be discarded. */ if (!TdsGetRecvPacketEomStatus()) ret = TdsDiscardAllPendingBcpRequest(); @@ -948,8 +986,8 @@ ProcessBCPRequest(TDSRequest request) if (TDS_DEBUG_ENABLED(TDS_DEBUG2)) ereport(LOG, (errmsg("Bulk Load Request. Number of Rows: %d and Number of columns: %d.", - req->rowCount, req->colCount), - errhidestmt(true))); + req->rowCount, req->colCount), + errhidestmt(true))); PG_RE_THROW(); } @@ -964,12 +1002,15 @@ ProcessBCPRequest(TDSRequest request) } } - /* Send Done Token if rows processed is a positive number. Command type - execute (0xf0). */ + /* + * Send Done Token if rows processed is a positive number. Command type - + * execute (0xf0). + */ if (retValue >= 0) TdsSendDone(TDS_TOKEN_DONE, TDS_DONE_COUNT, 0xf0, retValue); - else /* Send Unknown Error. */ + else /* Send Unknown Error. */ ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("Unknown error occurred during Insert Bulk"))); + errmsg("Unknown error occurred during Insert Bulk"))); /* * Log immediately if dictated by log_statement. @@ -977,11 +1018,12 @@ ProcessBCPRequest(TDSRequest request) if (pltsql_plugin_handler_ptr->stmt_needs_logging || TDS_DEBUG_ENABLED(TDS_DEBUG2)) { ErrorContextCallback *plerrcontext = error_context_stack; + error_context_stack = plerrcontext->previous; ereport(LOG, (errmsg("Bulk Load Request. Number of Rows: %d and Number of columns: %d.", - req->rowCount, req->colCount), - errhidestmt(true))); + req->rowCount, req->colCount), + errhidestmt(true))); pltsql_plugin_handler_ptr->stmt_needs_logging = false; error_context_stack = plerrcontext; } @@ -991,12 +1033,13 @@ ProcessBCPRequest(TDSRequest request) static int ReadBcpPlp(ParameterToken temp, StringInfo *message, TDSRequestBulkLoad request) { - uint64_t plpTok; - Plp plpTemp, plpPrev = NULL; + uint64_t plpTok; + Plp plpTemp, + plpPrev = NULL; unsigned long lenCheck = 0; CheckPlpMessageHasEnoughBytesToRead(message, sizeof(plpTok)); - memcpy(&plpTok , &(*message)->data[offset], sizeof(plpTok)); + memcpy(&plpTok, &(*message)->data[offset], sizeof(plpTok)); offset += sizeof(plpTok); request->currentBatchSize += sizeof(plpTok); temp->plp = NULL; @@ -1010,13 +1053,13 @@ ReadBcpPlp(ParameterToken temp, StringInfo *message, TDSRequestBulkLoad request) while (true) { - uint32_t tempLen; + uint32_t tempLen; CheckPlpMessageHasEnoughBytesToRead(message, sizeof(tempLen)); if (offset + sizeof(tempLen) > (*message)->len) return STATUS_ERROR; - memcpy(&tempLen , &(*message)->data[offset], sizeof(tempLen)); + memcpy(&tempLen, &(*message)->data[offset], sizeof(tempLen)); offset += sizeof(tempLen); request->currentBatchSize += sizeof(tempLen); @@ -1056,4 +1099,4 @@ ReadBcpPlp(ParameterToken temp, StringInfo *message, TDSRequestBulkLoad request) } return STATUS_OK; -} \ No newline at end of file +} diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdscomm.c b/contrib/babelfishpg_tds/src/backend/tds/tdscomm.c index 73e60d84fb..810656613a 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tdscomm.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tdscomm.c @@ -31,31 +31,32 @@ #include "src/include/faultinjection.h" /* Globals */ -MemoryContext TdsMemoryContext = NULL; +MemoryContext TdsMemoryContext = NULL; static uint32_t TdsBufferSize; -static char *TdsSendBuffer; -static int TdsSendCur; /* Next index to store a byte in TdsSendBuffer */ -static int TdsSendStart; /* Next index to send a byte in TdsSendBuffer */ -static uint8_t TdsSendMessageType; /* Current TDS message in progress */ - -static bool TdsDoProcessHeader; /* Header is processed or not. */ -static char *TdsRecvBuffer; -static int TdsRecvStart; /* Next index to read a byte from TdsRecvBuffer */ -static int TdsRecvEnd; /* End of data available in TdsRecvBuffer */ -static uint8_t TdsRecvMessageType; /* Current TDS message in progress */ -static uint8_t TdsRecvPacketStatus; -static int TdsLeftInPacket; +static char *TdsSendBuffer; +static int TdsSendCur; /* Next index to store a byte in TdsSendBuffer */ +static int TdsSendStart; /* Next index to send a byte in TdsSendBuffer */ +static uint8_t TdsSendMessageType; /* Current TDS message in progress */ + +static bool TdsDoProcessHeader; /* Header is processed or not. */ +static char *TdsRecvBuffer; +static int TdsRecvStart; /* Next index to read a byte from + * TdsRecvBuffer */ +static int TdsRecvEnd; /* End of data available in TdsRecvBuffer */ +static uint8_t TdsRecvMessageType; /* Current TDS message in progress */ +static uint8_t TdsRecvPacketStatus; +static int TdsLeftInPacket; static TdsSecureSocketApi tds_secure_read; static TdsSecureSocketApi tds_secure_write; /* Internal functions */ -static void SocketSetNonblocking(bool nonblocking); -static int InternalFlush(bool); -static void TdsConsumedBytes(int bytes); +static void SocketSetNonblocking(bool nonblocking); +static int InternalFlush(bool); +static void TdsConsumedBytes(int bytes); /* Inline functions */ @@ -68,8 +69,8 @@ static void TdsConsumedBytes(int bytes); static inline int InternalPutbytes(void *bytes, size_t len) { - size_t amount; - unsigned char *s = bytes; + size_t amount; + unsigned char *s = bytes; while (len > 0) { @@ -137,7 +138,7 @@ SocketSetNonblocking(bool nonblocking) static int TdsReadsocket(void) { - TdsErrorContext->err_text = "Reading data from socket"; + TdsErrorContext->err_text = "Reading data from socket"; if (TdsRecvStart > 0) { if (TdsRecvEnd > TdsRecvStart) @@ -203,10 +204,10 @@ TdsReadsocket(void) static int TdsProcessHeader(void) { - uint16_t data16; + uint16_t data16; FAULT_INJECT(ParseHeaderType, TdsRecvBuffer); - TdsErrorContext->err_text = "Processing TDS header"; + TdsErrorContext->err_text = "Processing TDS header"; if (TdsLeftInPacket != 0) ereport(FATAL, @@ -222,7 +223,7 @@ TdsProcessHeader(void) /* Message type */ TdsRecvMessageType = TdsRecvBuffer[TdsRecvStart]; /* Packet status */ - TdsRecvPacketStatus = TdsRecvBuffer[TdsRecvStart+1]; + TdsRecvPacketStatus = TdsRecvBuffer[TdsRecvStart + 1]; /* Packet length in network byte order (includes header size) */ memcpy(&data16, TdsRecvBuffer + TdsRecvStart + 2, sizeof(data16)); @@ -236,7 +237,7 @@ TdsProcessHeader(void) TdsLeftInPacket = data16 - TDS_PACKET_HEADER_SIZE; TdsRecvStart += TDS_PACKET_HEADER_SIZE; - /* [BABEL-648] TDS packet with no TDS data is valid packet.*/ + /* [BABEL-648] TDS packet with no TDS data is valid packet. */ if (TdsLeftInPacket < 0) ereport(FATAL, (errcode(ERRCODE_PROTOCOL_VIOLATION), @@ -244,7 +245,7 @@ TdsProcessHeader(void) TdsDoProcessHeader = false; TDS_DEBUG(TDS_DEBUG3, "TDS packet MessageType %d LeftInPacket %d Status %d", - TdsRecvMessageType, TdsLeftInPacket, TdsRecvPacketStatus); + TdsRecvMessageType, TdsLeftInPacket, TdsRecvPacketStatus); TDS_DEBUG(TDS_DEBUG3, "TDS receive buffer start %d end %d", TdsRecvStart, TdsRecvEnd); return 0; } @@ -258,7 +259,7 @@ TdsProcessHeader(void) static int TdsRecvbuf(void) { - TdsErrorContext->err_text = "Loading data into input buffer"; + TdsErrorContext->err_text = "Loading data into input buffer"; /* Need to process the packet header */ if (TdsLeftInPacket == 0 && TdsRecvStart < TdsRecvEnd) { @@ -278,9 +279,10 @@ TdsRecvbuf(void) { return EOF; } - /* - * Last socket read only got header worth of data and - * if something is left to read. + + /* + * Last socket read only got header worth of data and if something + * is left to read. */ if ((TdsRecvStart == TdsRecvEnd) && (TdsLeftInPacket > 0)) { @@ -324,7 +326,8 @@ TdsGetbyte(void) static void TdsFillHeader(bool lastPacket) { - uint16_t net16; + uint16_t net16; + /* Message type */ TdsSendBuffer[0] = TdsSendMessageType; /* Packet status */ @@ -333,9 +336,9 @@ TdsFillHeader(bool lastPacket) net16 = pg_hton16(TdsSendCur - TdsSendStart); memcpy(TdsSendBuffer + 2, &net16, sizeof(net16)); net16 = 0; - memcpy(TdsSendBuffer + 4, &net16, sizeof(net16)); /* TODO get server pid */ - TdsSendBuffer[6] = 0; /* TODO generate packet id */ - TdsSendBuffer[7] = 0; /* unused */ + memcpy(TdsSendBuffer + 4, &net16, sizeof(net16)); /* TODO get server pid */ + TdsSendBuffer[6] = 0; /* TODO generate packet id */ + TdsSendBuffer[7] = 0; /* unused */ } /* -------------------------------- @@ -353,7 +356,7 @@ InternalFlush(bool lastPacket) char *bufptr = TdsSendBuffer + TdsSendStart; char *bufend = TdsSendBuffer + TdsSendCur; - TdsErrorContext->err_text = "TDS InternalFlush - Sending data to the client"; + TdsErrorContext->err_text = "TDS InternalFlush - Sending data to the client"; /* Writing the packet for the first time */ if (TdsSendStart == 0) { @@ -431,16 +434,16 @@ InternalFlush(bool lastPacket) */ void TdsCommInit(uint32_t bufferSize, - TdsSecureSocketApi secure_read, - TdsSecureSocketApi secure_write) + TdsSecureSocketApi secure_read, + TdsSecureSocketApi secure_write) { tds_secure_read = secure_read; tds_secure_write = secure_write; TdsDoProcessHeader = true; /* - * Create our own long term memory context for things like the send - * and recieve buffers and caches. + * Create our own long term memory context for things like the send and + * recieve buffers and caches. */ Assert(TdsMemoryContext == NULL); TdsMemoryContext = AllocSetContextCreate(TopMemoryContext, @@ -459,7 +462,7 @@ TdsCommInit(uint32_t bufferSize, void TdsCommReset(void) { - MemoryContext oldContext; + MemoryContext oldContext; TdsRecvMessageType = TdsSendMessageType = 0; TdsRecvPacketStatus = 0; @@ -481,9 +484,10 @@ void TdsCommShutdown(void) { Assert(TdsSendMessageType == 0); + /* - * Both send and receive buffers should not have any - * valid data at this point in time + * Both send and receive buffers should not have any valid data at this + * point in time */ Assert(TdsSendStart == 0 && TdsSendCur == TDS_PACKET_HEADER_SIZE); Assert(TdsRecvStart == TdsRecvEnd && TdsLeftInPacket == 0); @@ -508,13 +512,14 @@ void TdsSetBufferSize(uint32_t newSize) { TDS_DEBUG(TDS_DEBUG3, "TdsSetBufferSize current size %u new size %u", - TdsBufferSize, newSize); + TdsBufferSize, newSize); if (newSize == TdsBufferSize) return; + /* - * Both send and receive buffers should not have any - * valid data at this point in time + * Both send and receive buffers should not have any valid data at this + * point in time */ if (TdsSendStart != 0 || TdsSendCur != TDS_PACKET_HEADER_SIZE || @@ -522,10 +527,10 @@ TdsSetBufferSize(uint32_t newSize) TdsLeftInPacket != 0) { TDS_DEBUG(TDS_DEBUG1, "TDS buffers in inconsistent state; " - "TdsSendStart: %d TdsSendCur: %d TdsRecvStart: %d " - "TdsRecvEnd: %d TdsLeftInPacket: %d", - TdsSendStart, TdsSendCur, TdsRecvStart, - TdsRecvEnd, TdsLeftInPacket); + "TdsSendStart: %d TdsSendCur: %d TdsRecvStart: %d " + "TdsRecvEnd: %d TdsLeftInPacket: %d", + TdsSendStart, TdsSendCur, TdsRecvStart, + TdsRecvEnd, TdsLeftInPacket); ereport(FATAL, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("TDS buffers in inconsistent state"))); @@ -574,11 +579,11 @@ TdsPeekbyte(void) int TdsReadNextBuffer(void) { - TdsErrorContext->err_text = "Reading buffer from socket"; + TdsErrorContext->err_text = "Reading buffer from socket"; while ((TdsLeftInPacket > 0 && TdsRecvStart >= TdsRecvEnd) || TdsDoProcessHeader) { - if (TdsRecvbuf()) /* If nothing in buffer, then recv some */ - return EOF; /* Failed to recv data */ + if (TdsRecvbuf()) /* If nothing in buffer, then recv some */ + return EOF; /* Failed to recv data */ } return 0; } @@ -607,7 +612,7 @@ TdsGetbytes(char *s, size_t len) size_t amount; TDS_DEBUG(TDS_DEBUG3, "TdsGetbytes LeftInPacket %d RecvStart %d RecvEnd %d", - TdsLeftInPacket, TdsRecvStart, TdsRecvEnd); + TdsLeftInPacket, TdsRecvStart, TdsRecvEnd); while (len > 0) { while (TdsLeftInPacket == 0 || TdsRecvStart >= TdsRecvEnd) @@ -615,7 +620,7 @@ TdsGetbytes(char *s, size_t len) if (TdsRecvbuf()) /* If nothing in buffer, then recv some */ return EOF; /* Failed to recv data */ } - TdsErrorContext->err_text = ""; + TdsErrorContext->err_text = ""; amount = Min(TdsLeftInPacket, TdsRecvEnd - TdsRecvStart); if (amount > len) amount = len; @@ -649,7 +654,7 @@ TdsDiscardbytes(size_t len) if (TdsRecvbuf()) /* If nothing in buffer, then recv some */ return EOF; /* Failed to recv data */ } - TdsErrorContext->err_text = ""; + TdsErrorContext->err_text = ""; amount = Min(TdsLeftInPacket, TdsRecvEnd - TdsRecvStart); if (amount > len) amount = len; @@ -725,7 +730,7 @@ TdsPutInt64LE(int64_t value) int TdsPutUInt16LE(uint16_t value) { - uint16_t tmp = htoLE16(value); + uint16_t tmp = htoLE16(value); return InternalPutbytes(&tmp, sizeof(tmp)); } @@ -755,6 +760,7 @@ TdsPutInt16LE(int16_t value) return InternalPutbytes(&tmp, sizeof(tmp)); } + /* -------------------------------- * TdsPutInt32LE - send one 32-bit integer in LITTLE_ENDIAN * @@ -768,6 +774,7 @@ TdsPutInt32LE(int32_t value) return InternalPutbytes(&tmp, sizeof(tmp)); } + /* -------------------------------- * TdsPutUInt32LE - send one 32-bit unsigned integer in LITTLE_ENDIAN * @@ -781,6 +788,7 @@ TdsPutUInt32LE(uint32_t value) return InternalPutbytes(&tmp, sizeof(tmp)); } + /* -------------------------------- * TdsPutUInt64LE - send one unsigned 64-bit integer in LITTLE_ENDIAN * @@ -855,7 +863,8 @@ TdsSocketFlush(void) int TdsReadNextPendingBcpRequest(StringInfo message) { - int readBytes = 0; + int readBytes = 0; + if (TdsReadNextBuffer() == EOF) return EOF; Assert(TdsRecvMessageType == TDS_BULK_LOAD); @@ -876,7 +885,8 @@ TdsReadNextPendingBcpRequest(StringInfo message) int TdsDiscardAllPendingBcpRequest() { - int readBytes = 0; + int readBytes = 0; + while (1) { if (TdsReadNextBuffer() == EOF) @@ -907,13 +917,14 @@ TdsDiscardAllPendingBcpRequest() int TdsReadNextRequest(StringInfo message, uint8_t *status, uint8_t *messageType) { - int readBytes = 0; - bool isFirst = true; - while(1) + int readBytes = 0; + bool isFirst = true; + + while (1) { if (TdsReadNextBuffer() == EOF) return EOF; - TdsErrorContext->err_text = "Save the status from first packet header"; + TdsErrorContext->err_text = "Save the status from first packet header"; /* * If this is the first packet header for this TDS request, save the @@ -940,8 +951,9 @@ TdsReadNextRequest(StringInfo message, uint8_t *status, uint8_t *messageType) } /* - * If this is a Bulk Load Request then read only the first packet of the request. - * We will fetch the rest of the data as and when required during the processing phase. + * If this is a Bulk Load Request then read only the first packet of + * the request. We will fetch the rest of the data as and when + * required during the processing phase. */ if (TdsRecvMessageType == TDS_BULK_LOAD) { @@ -962,8 +974,8 @@ TdsReadNextRequest(StringInfo message, uint8_t *status, uint8_t *messageType) int TdsReadMessage(StringInfo message, uint8_t messageType) { - uint8_t curMsgType; - uint8_t status; + uint8_t curMsgType; + uint8_t status; /* Make sure that last write is flushed */ if (TdsSendStart != 0 || TdsSendCur != TDS_PACKET_HEADER_SIZE) @@ -973,7 +985,7 @@ TdsReadMessage(StringInfo message, uint8_t messageType) if (TdsReadNextRequest(message, &status, &curMsgType)) return EOF; - // TODO Map to proper error code for TDS client + /* TODO Map to proper error code for TDS client */ if (messageType != curMsgType) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1007,7 +1019,8 @@ TdsWriteMessage(StringInfo message, uint8_t messageType) return 0; } -bool TdsGetRecvPacketEomStatus(void) +bool +TdsGetRecvPacketEomStatus(void) { return TdsRecvPacketStatus & TDS_PACKET_HEADER_STATUS_EOM; -} \ No newline at end of file +} diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdslogin.c b/contrib/babelfishpg_tds/src/backend/tds/tdslogin.c index 1008fdd069..1a49868db8 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tdslogin.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tdslogin.c @@ -116,36 +116,36 @@ typedef struct #undef HAVE_GETADDRINFO #endif -static int SecureOpenServer(Port *port); +static int SecureOpenServer(Port *port); static void SendGSSAuthError(int severity, const char *errmsg, OM_uint32 maj_stat, OM_uint32 min_stat); static void SendGSSAuthResponse(Port *port, char *extradata, uint16_t extralen); -static int CheckGSSAuth(Port *port); +static int CheckGSSAuth(Port *port); #endif /* ENABLE_GSS */ /* Global to store default collation info */ -int TdsDefaultLcid; -int TdsDefaultCollationFlags; -uint8_t TdsDefaultSortid; -pg_enc TdsDefaultClientEncoding; +int TdsDefaultLcid; +int TdsDefaultCollationFlags; +uint8_t TdsDefaultSortid; +pg_enc TdsDefaultClientEncoding; static void TdsDefineDefaultCollationInfo(void); typedef struct LoginRequestData { /* Fixed length attributes */ - uint32_t length; - uint32_t tdsVersion; - uint32_t packetSize; - uint32_t clientProVersion; - uint32_t clientPid; - uint32_t connectionId; - uint8_t optionFlags1; /* see above */ - uint8_t optionFlags2; /* see above */ - uint8_t typeFlags; /* see above */ - uint8_t optionFlags3; /* Reserved flags, see above */ - uint32_t clientTimezone; - uint32_t clientLcid; /* Language code identifier */ + uint32_t length; + uint32_t tdsVersion; + uint32_t packetSize; + uint32_t clientProVersion; + uint32_t clientPid; + uint32_t connectionId; + uint8_t optionFlags1; /* see above */ + uint8_t optionFlags2; /* see above */ + uint8_t typeFlags; /* see above */ + uint8_t optionFlags3; /* Reserved flags, see above */ + uint32_t clientTimezone; + uint32_t clientLcid; /* Language code identifier */ /* * The variable length attributes are stored in the following order in the @@ -154,32 +154,32 @@ typedef struct LoginRequestData * store null terminated strings. Hence, we don't store the lengths. */ #define TDS_LOGIN_ATTR_HOSTNAME 0 - char *hostname; + char *hostname; #define TDS_LOGIN_ATTR_USERNAME 1 - char *username; + char *username; #define TDS_LOGIN_ATTR_PASSWORD 2 - char *password; + char *password; #define TDS_LOGIN_ATTR_APPNAME 3 - char *appname; + char *appname; #define TDS_LOGIN_ATTR_SERVERNAME 4 - char *servername; + char *servername; #define TDS_LOGIN_ATTR_UNUSED 5 #define TDS_LOGIN_ATTR_LIBRARY 6 - char *library; + char *library; #define TDS_LOGIN_ATTR_LANGUAGE 7 - char *language; + char *language; #define TDS_LOGIN_ATTR_DATABASE 8 - char *database; -#define TDS_LOGIN_ATTR_MAX 9 /* should be last */ + char *database; +#define TDS_LOGIN_ATTR_MAX 9 /* should be last */ /* the 6-byte client mac address */ - char clientId[6]; + char clientId[6]; uint16_t sspiLen; - char *sspi; + char *sspi; /* the Active Directory (AD) domain name */ - char *domainname; + char *domainname; /* TODO: Feature data */ @@ -191,9 +191,9 @@ typedef LoginRequestData *LoginRequest; typedef struct PreLoginOption { - int8_t token; - uint16_t offset; - uint16_t length; + int8_t token; + uint16_t offset; + uint16_t length; StringInfoData val; struct PreLoginOption *next; } PreLoginOption; @@ -203,17 +203,17 @@ LoginRequest loginInfo = NULL; static const char *PreLoginTokenType(uint8_t token); static void DebugPrintPreLoginStructure(PreLoginOption *request); -static int ParsePreLoginRequest(); -static int *ProcessVersionNumber(const char* inputString); +static int ParsePreLoginRequest(); +static int *ProcessVersionNumber(const char *inputString); static void SetPreLoginResponseVal(Port *port, uint8_t token, - StringInfo val, StringInfo reqVal, - bool loadSsl, int *loadEncryption); -static int MakePreLoginResponse(Port *, bool); + StringInfo val, StringInfo reqVal, + bool loadSsl, int *loadEncryption); +static int MakePreLoginResponse(Port *, bool); static void ValidateLoginRequest(LoginRequest request); -static int FetchLoginRequest(LoginRequest request); -static int ProcessLoginInternal(Port *port); -static int CheckAuthPassword(Port *port, const char **logdetail); +static int FetchLoginRequest(LoginRequest request); +static int ProcessLoginInternal(Port *port); +static int CheckAuthPassword(Port *port, const char **logdetail); static void SendLoginError(Port *port, const char *logdetail); static void GetLoginFlagsInstrumentation(LoginRequest loginInfo); static void GetTDSVersionInstrumentation(uint32_t version); @@ -258,7 +258,7 @@ PreLoginTokenType(uint8_t token) { const char *id = NULL; - switch(token) + switch (token) { case TDS_PRELOGIN_VERSION: id = "TDS_PRELOGIN_VERSION (0x00)"; @@ -299,19 +299,19 @@ DebugPrintPreLoginStructure(PreLoginOption *request) { PreLoginOption *prev; StringInfoData s; - int i = 0; + int i = 0; initStringInfo(&s); appendStringInfo(&s, "\nOption token: %s \n\t Option offset: %d \n\t Option Length: %d \n\t Version: %02x.%02x.%04x Subbuild: %04x ", - PreLoginTokenType(request->token), request->offset, request->length, - request->val.data[0], request->val.data[1], request->val.data[2], request->val.data[4]); + PreLoginTokenType(request->token), request->offset, request->length, + request->val.data[0], request->val.data[1], request->val.data[2], request->val.data[4]); prev = request->next; - while(prev != NULL) + while (prev != NULL) { appendStringInfo(&s, "\nOption token: %s \n\t Option offset: %d \n\t Option Length: %d \n\t Data : ", - PreLoginTokenType(prev->token), prev->offset, prev->length); + PreLoginTokenType(prev->token), prev->offset, prev->length); - for(i = 0; i < prev->length; i++) + for (i = 0; i < prev->length; i++) { appendStringInfo(&s, "%02x", (unsigned char) prev->val.data[i]); } @@ -331,7 +331,7 @@ DebugPrintPreLoginStructure(PreLoginOption *request) static int ParsePreLoginRequest() { - uint16_t data16; + uint16_t data16; PreLoginOption *temp; PreLoginOption *prev = NULL; @@ -339,10 +339,10 @@ ParsePreLoginRequest() while (1) { temp = palloc0(sizeof(PreLoginOption)); - if (TdsGetbytes((char *)(&temp->token), sizeof(temp->token))) + if (TdsGetbytes((char *) (&temp->token), sizeof(temp->token))) return STATUS_ERROR; - // Terminator token + /* Terminator token */ if (temp->token == -1) { temp->offset = 0; @@ -353,10 +353,10 @@ ParsePreLoginRequest() prev = prev->next; break; } - if (TdsGetbytes((char *)&data16, sizeof(data16))) + if (TdsGetbytes((char *) &data16, sizeof(data16))) return STATUS_ERROR; temp->offset = pg_ntoh16(data16); - if (TdsGetbytes((char *)&data16, sizeof(data16))) + if (TdsGetbytes((char *) &data16, sizeof(data16))) return STATUS_ERROR; temp->length = pg_ntoh16(data16); initStringInfo(&temp->val); @@ -390,20 +390,20 @@ ParsePreLoginRequest() return 0; } static int * -ProcessVersionNumber(const char* inputString) +ProcessVersionNumber(const char *inputString) { - static int version_arr[4]; - int part = 0, - len = 0; - char *copy_version_number; - char *token; + static int version_arr[4]; + int part = 0, + len = 0; + char *copy_version_number; + char *token; Assert(inputString != NULL); len = strlen(inputString); copy_version_number = palloc0(len + 1); memcpy(copy_version_number, inputString, len); for (token = strtok(copy_version_number, "."); token; token = strtok(NULL, ".")) - { + { version_arr[part] = atoi(token); part++; Assert(part <= 4); @@ -411,26 +411,29 @@ ProcessVersionNumber(const char* inputString) return version_arr; } -static int makeVersionByte(int byteNum){ - int *version_pnt; - int MajorVersion; - int MinorVersion; - int MicroVersion; +static int +makeVersionByte(int byteNum) +{ + int *version_pnt; + int MajorVersion; + int MinorVersion; + int MicroVersion; Assert(product_version != NULL); Assert(byteNum <= 3); - if(pg_strcasecmp(product_version,"default") == 0) + if (pg_strcasecmp(product_version, "default") == 0) version_pnt = ProcessVersionNumber(BABEL_COMPATIBILITY_VERSION); else version_pnt = ProcessVersionNumber(product_version); - + MajorVersion = *(version_pnt + 0); MinorVersion = *(version_pnt + 1); MicroVersion = *(version_pnt + 2); - if(byteNum == 0){ + if (byteNum == 0) + { return MajorVersion & 0xFF; - } + } else if (byteNum == 1) { return MinorVersion & 0xFF; @@ -456,9 +459,9 @@ static int makeVersionByte(int byteNum){ static void SetPreLoginResponseVal(Port *port, uint8_t token, StringInfo val, - StringInfo reqVal, bool loadSsl, int *loadEncryption) + StringInfo reqVal, bool loadSsl, int *loadEncryption) { - switch(token) + switch (token) { case TDS_PRELOGIN_VERSION: appendStringInfoChar(val, makeVersionByte(0)); @@ -469,16 +472,16 @@ SetPreLoginResponseVal(Port *port, uint8_t token, StringInfo val, appendStringInfoChar(val, 0x00); break; case TDS_PRELOGIN_ENCRYPTION: + /* - * Support full encryption if server supports & - * client has requested ENCRYPT_ON or ENCRYPT_REQ, - * or Login7 request encryption if req = TDS_ENCRYPT_OFF - * or else TDS_ENCRYPT_OFF - * No SSL support - when disabled or on Unix sockets + * Support full encryption if server supports & client has + * requested ENCRYPT_ON or ENCRYPT_REQ, or Login7 request + * encryption if req = TDS_ENCRYPT_OFF or else TDS_ENCRYPT_OFF No + * SSL support - when disabled or on Unix sockets */ if (loadSsl && port->laddr.addr.ss_family != AF_UNIX) { - if ((reqVal->data[0] == TDS_ENCRYPT_ON) || + if ((reqVal->data[0] == TDS_ENCRYPT_ON) || (reqVal->data[0] == TDS_ENCRYPT_REQ)) { appendStringInfoChar(val, TDS_ENCRYPT_ON); @@ -522,6 +525,7 @@ SetPreLoginResponseVal(Port *port, uint8_t token, StringInfo val, MyTdsEncryptOption = *loadEncryption; break; case TDS_PRELOGIN_INSTOPT: + /* * Val 00 - To indicate client's val matches server expectation * Val 01 - Otherwise 01 to indicate client should terminate @@ -540,10 +544,10 @@ SetPreLoginResponseVal(Port *port, uint8_t token, StringInfo val, TDSInstrumentation(INSTR_UNSUPPORTED_TDS_PRELOGIN_TRACEID); break; case TDS_PRELOGIN_FEDAUTHREQUIRED: + /* - * Should only be set when SSPI or FedAuth is supported - * Val 00 - SSPI supported - * Val 01 - FedAuth Supported + * Should only be set when SSPI or FedAuth is supported Val 00 - + * SSPI supported Val 01 - FedAuth Supported */ TDSInstrumentation(INSTR_UNSUPPORTED_TDS_PRELOGIN_FEDAUTHREQUIRED); break; @@ -570,18 +574,20 @@ SetPreLoginResponseVal(Port *port, uint8_t token, StringInfo val, static int MakePreLoginResponse(Port *port, bool loadSsl) { - uint16_t temp16; + uint16_t temp16; PreLoginOption *preLoginResponse; - PreLoginOption *tempRequest, *temp, *prev = NULL; - int offset = 0; - int loadEncryption = 0; + PreLoginOption *tempRequest, + *temp, + *prev = NULL; + int offset = 0; + int loadEncryption = 0; preLoginResponse = palloc0(sizeof(PreLoginOption)); /* Prepare the structure */ tempRequest = TdsPreLoginRequest; - while(tempRequest != NULL) + while (tempRequest != NULL) { if (tempRequest->token != TDS_PRELOGIN_FEDAUTHREQUIRED) { @@ -589,7 +595,7 @@ MakePreLoginResponse(Port *port, bool loadSsl) temp->token = tempRequest->token; initStringInfo(&temp->val); SetPreLoginResponseVal(port, temp->token, &temp->val, &tempRequest->val, - loadSsl, &loadEncryption); + loadSsl, &loadEncryption); temp->length = temp->val.len; /* 1 - type, 2 - offsetlen, 2 - len */ offset += 5; @@ -612,7 +618,7 @@ MakePreLoginResponse(Port *port, bool loadSsl) /* Add all the offset val */ prev = preLoginResponse; - while(prev != NULL) + while (prev != NULL) { prev->offset = offset; offset += prev->length; @@ -633,7 +639,7 @@ MakePreLoginResponse(Port *port, bool loadSsl) TdsPutbytes(&temp16, sizeof(temp16)); prev = prev->next; } - // Terminator token + /* Terminator token */ TdsPutbytes(&(prev->token), sizeof(prev->token)); prev = preLoginResponse; @@ -643,7 +649,7 @@ MakePreLoginResponse(Port *port, bool loadSsl) prev = prev->next; } - // Free the PreLogin Structures + /* Free the PreLogin Structures */ prev = TdsPreLoginRequest; while (prev != NULL) { @@ -671,28 +677,28 @@ static void ValidateLoginRequest(LoginRequest request) { /* TODO: do the sanity checks */ - - uint32_t version; + + uint32_t version; /* Use the GUC's values, if set. */ if (tds_default_protocol_version > 0) request->tdsVersion = tds_default_protocol_version; version = request->tdsVersion; - + /* TDS Version must be valid */ - if (!( version == TDS_VERSION_7_0 || - version == TDS_VERSION_7_1 || - version == TDS_VERSION_7_1_1 || - version == TDS_VERSION_7_2 || - version == TDS_VERSION_7_3_A || - version == TDS_VERSION_7_3_B || - version == TDS_VERSION_7_4)) + if (!(version == TDS_VERSION_7_0 || + version == TDS_VERSION_7_1 || + version == TDS_VERSION_7_1_1 || + version == TDS_VERSION_7_2 || + version == TDS_VERSION_7_3_A || + version == TDS_VERSION_7_3_B || + version == TDS_VERSION_7_4)) elog(FATAL, "invalid TDS Version: %X", version); GetTDSVersionInstrumentation(version); /* TDS Version 7.0 is unsupported */ - if(version == TDS_VERSION_7_0) + if (version == TDS_VERSION_7_0) elog(FATAL, "unsupported TDS Version: %X", version); /* @@ -714,16 +720,18 @@ ValidateLoginRequest(LoginRequest request) static int FetchLoginRequest(LoginRequest request) { - uint32_t attrs[TDS_LOGIN_ATTR_MAX]; - uint32_t sspiOffsetLen; - StringInfoData buf; - StringInfoData temp_utf8; - int i, read = 0; + uint32_t attrs[TDS_LOGIN_ATTR_MAX]; + uint32_t sspiOffsetLen; + StringInfoData buf; + StringInfoData temp_utf8; + int i, + read = 0; Assert(request != NULL); TdsErrorContext->reqType = TDS_LOGIN7; #ifdef WORDS_BIGENDIAN + /* * Are we going to support this? */ @@ -738,7 +746,10 @@ FetchLoginRequest(LoginRequest request) if (TdsGetbytes((char *) request, SizeOfLoginRequestFixed)) return STATUS_ERROR; - /* The length of a LOGIN7 stream MUST NOT be longer than 128K-1(byte) bytes */ + /* + * The length of a LOGIN7 stream MUST NOT be longer than 128K-1(byte) + * bytes + */ if (request->length > 128 * 1024) return STATUS_ERROR; @@ -782,10 +793,10 @@ FetchLoginRequest(LoginRequest request) return STATUS_ERROR; /* - * It follows the following data that we're going to discard for now: - * 1. Database to attach during connection process - * 2. New password for the specified login. Introduced in TDS 7.2 - * 3. Used for large SSPI data when cbSSPI==USHORT_MAX. Introduced in TDS 7.2 + * It follows the following data that we're going to discard for now: 1. + * Database to attach during connection process 2. New password for the + * specified login. Introduced in TDS 7.2 3. Used for large SSPI data when + * cbSSPI==USHORT_MAX. Introduced in TDS 7.2 */ initStringInfo(&buf); @@ -794,8 +805,8 @@ FetchLoginRequest(LoginRequest request) /* Now, read from the offsets */ for (i = 0; i < TDS_LOGIN_ATTR_MAX; i++) { - uint16_t offset = (uint16_t) attrs[i]; - uint16_t length = (uint16_t) (attrs[i] >> 16); + uint16_t offset = (uint16_t) attrs[i]; + uint16_t length = (uint16_t) (attrs[i] >> 16); if (length > 0) { @@ -810,11 +821,11 @@ FetchLoginRequest(LoginRequest request) read = offset; /* - * The hostname, username, password, appname, servername, - * library name, language and database name MUST specify - * at most 128 characters + * The hostname, username, password, appname, servername, library + * name, language and database name MUST specify at most 128 + * characters */ - if(length > 128) + if (length > 128) return STATUS_ERROR; if (i == TDS_LOGIN_ATTR_UNUSED) @@ -855,15 +866,16 @@ FetchLoginRequest(LoginRequest request) buf.len += length; /* - * The password field is an obfusticated unicode string. So, we've - * to handle it differently. + * The password field is an obfusticated unicode string. So, + * we've to handle it differently. */ if (i == TDS_LOGIN_ATTR_PASSWORD) { - int j; + int j; + for (j = 0; j < length; j++) { - uint8_t p = buf.data[j]; + uint8_t p = buf.data[j]; p = (((p & 0xff) ^ 0xA5) << 4) | (((p & 0xff) ^ 0xA5) >> 4); buf.data[j] = p & 0xff; @@ -873,7 +885,7 @@ FetchLoginRequest(LoginRequest request) TdsUTF16toUTF8StringInfo(&temp_utf8, buf.data, length); - switch(i) + switch (i) { case TDS_LOGIN_ATTR_HOSTNAME: request->hostname = pstrdup(temp_utf8.data); @@ -915,18 +927,23 @@ FetchLoginRequest(LoginRequest request) if (sspiOffsetLen > 0) { - uint16_t offset = (uint16_t) sspiOffsetLen; + uint16_t offset = (uint16_t) sspiOffsetLen; + request->sspiLen = (uint16_t) (sspiOffsetLen >> 16); if (request->sspiLen > 0) { - const char* is_windows_allowed = GetConfigOption("babelfishpg_tsql.allow_windows_login", true, false); + const char *is_windows_allowed = GetConfigOption("babelfishpg_tsql.allow_windows_login", true, false); + if (is_windows_allowed && strncasecmp(is_windows_allowed, "false", 5) == 0) ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Windows login is not supported in babelfish"))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Windows login is not supported in babelfish"))); - /* XXX: large SSPI data when length==USHORT_MAX - not supported yet */ + /* + * XXX: large SSPI data when length==USHORT_MAX - not supported + * yet + */ if (request->sspiLen == -1) { TDSInstrumentation(INSTR_UNSUPPORTED_TDS_LOGIN_CB_SSPI_LONG); @@ -1058,7 +1075,8 @@ FetchLoginRequest(LoginRequest request) * 1 = ibExtension/cbExtension fields are used. * Specifies whether ibExtension/cbExtension fields are used. */ -static void ProcessLoginFlags(LoginRequest loginInfo) +static void +ProcessLoginFlags(LoginRequest loginInfo) { GetLoginFlagsInstrumentation(loginInfo); @@ -1066,59 +1084,59 @@ static void ProcessLoginFlags(LoginRequest loginInfo) if ((loginInfo->optionFlags2 & LOGIN_OPTION_FLAGS2_ODBC) || (loginInfo->typeFlags & LOGIN_TYPE_FLAGS_OLEDB)) { - char *textSize = psprintf("%d" , (loginInfo->tdsVersion <= TDS_VERSION_7_2) ? + char *textSize = psprintf("%d", (loginInfo->tdsVersion <= TDS_VERSION_7_2) ? TEXT_SIZE_2GB : TEXT_SIZE_INFINITE); - char *rowCount = psprintf("%d" ,INT_MAX); + char *rowCount = psprintf("%d", INT_MAX); set_config_option("babelfishpg_tsql.ansi_defaults", - "ON", - PGC_USERSET, - PGC_S_OVERRIDE, - GUC_ACTION_SET, - true, - 0, - false); + "ON", + PGC_USERSET, + PGC_S_OVERRIDE, + GUC_ACTION_SET, + true, + 0, + false); set_config_option("babelfishpg_tsql.implicit_transactions", - "OFF", - PGC_USERSET, - PGC_S_OVERRIDE, - GUC_ACTION_SET, - true, - 0, - false); + "OFF", + PGC_USERSET, + PGC_S_OVERRIDE, + GUC_ACTION_SET, + true, + 0, + false); set_config_option("babelfishpg_tsql.cursor_close_on_commit", - "OFF", - PGC_USERSET, - PGC_S_OVERRIDE, - GUC_ACTION_SET, - true, - 0, - false); + "OFF", + PGC_USERSET, + PGC_S_OVERRIDE, + GUC_ACTION_SET, + true, + 0, + false); set_config_option("babelfishpg_tsql.textsize", - textSize, - PGC_USERSET, - PGC_S_OVERRIDE, - GUC_ACTION_SET, - true, - 0, - false); + textSize, + PGC_USERSET, + PGC_S_OVERRIDE, + GUC_ACTION_SET, + true, + 0, + false); set_config_option("babelfishpg_tsql.rowcount", - rowCount, - PGC_USERSET, - PGC_S_OVERRIDE, - GUC_ACTION_SET, - true, - 0, - false); + rowCount, + PGC_USERSET, + PGC_S_OVERRIDE, + GUC_ACTION_SET, + true, + 0, + false); } if (loginInfo->optionFlags3 & LOGIN_OPTION_FLAGS3_CHANGE_PASSWORD) { TDSInstrumentation(INSTR_UNSUPPORTED_TDS_LOGIN_OPTION_FLAGS3_CHANGE_PASSWORD); ereport(FATAL, - errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), - errmsg("Password change request is not supported")); + errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), + errmsg("Password change request is not supported")); } } @@ -1134,14 +1152,14 @@ static void ProcessLoginFlags(LoginRequest loginInfo) static int ProcessLoginInternal(Port *port) { - MemoryContext oldContext; + MemoryContext oldContext; LoginRequest request; - const char* gucDatabaseName = GetConfigOption("babelfishpg_tsql.database_name", true, false); + const char *gucDatabaseName = GetConfigOption("babelfishpg_tsql.database_name", true, false); if (gucDatabaseName == NULL) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("Configuration parameter \"babelfishpg_tsql.database_name\" is not defined"), - errhint("Set GUC value by specifying it in postgresql.conf or by ALTER SYSTEM"))); + errmsg("Configuration parameter \"babelfishpg_tsql.database_name\" is not defined"), + errhint("Set GUC value by specifying it in postgresql.conf or by ALTER SYSTEM"))); /* * We want to keep all login related information around even after @@ -1162,8 +1180,8 @@ ProcessLoginInternal(Port *port) ValidateLoginRequest(request); /* - * Downcase and copy the username and database name in port structure so that no one - * messes up with the local copy. + * Downcase and copy the username and database name in port structure so + * that no one messes up with the local copy. */ if (request->username != NULL) { @@ -1175,7 +1193,7 @@ ProcessLoginInternal(Port *port) } if (request->database != NULL) { - request->database = downcase_identifier(request->database, + request->database = downcase_identifier(request->database, strlen(request->database), false, false); @@ -1196,8 +1214,8 @@ ProcessLoginInternal(Port *port) } /* - * If GUC "babelfishpg_tsql.database_name" is not "none" then - * database name specified in login request is overridden by + * If GUC "babelfishpg_tsql.database_name" is not "none" then database + * name specified in login request is overridden by * "babelfish_pgtsql.database_name" */ if (gucDatabaseName != NULL && strcmp(gucDatabaseName, "none") != 0) @@ -1205,15 +1223,16 @@ ProcessLoginInternal(Port *port) if (request->sspiLen > 0) { - char tempusername[10] = ""; + char tempusername[10] = ""; + port->user_name = pstrdup(tempusername); } /* Check a user name was given. */ if (port->user_name == NULL || port->user_name[0] == '\0') ereport(FATAL, - errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), - errmsg("no PostgreSQL user name specified in startup packet")); + errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), + errmsg("no PostgreSQL user name specified in startup packet")); /* The database defaults to the user name. */ if (port->database_name == NULL || port->database_name[0] == '\0') @@ -1245,8 +1264,8 @@ ProcessLoginInternal(Port *port) { case CAC_STARTUP: ereport(FATAL, - errcode(ERRCODE_CANNOT_CONNECT_NOW), - errmsg("the database system is starting up")); + errcode(ERRCODE_CANNOT_CONNECT_NOW), + errmsg("the database system is starting up")); break; case CAC_NOTCONSISTENT: if (EnableHotStandby) @@ -1262,18 +1281,18 @@ ProcessLoginInternal(Port *port) break; case CAC_SHUTDOWN: ereport(FATAL, - errcode(ERRCODE_CANNOT_CONNECT_NOW), - errmsg("the database system is shutting down")); + errcode(ERRCODE_CANNOT_CONNECT_NOW), + errmsg("the database system is shutting down")); break; case CAC_RECOVERY: ereport(FATAL, - errcode(ERRCODE_CANNOT_CONNECT_NOW), - errmsg("the database system is in recovery mode")); + errcode(ERRCODE_CANNOT_CONNECT_NOW), + errmsg("the database system is in recovery mode")); break; case CAC_TOOMANY: ereport(FATAL, - errcode(ERRCODE_TOO_MANY_CONNECTIONS), - errmsg("sorry, too many clients already")); + errcode(ERRCODE_TOO_MANY_CONNECTIONS), + errmsg("sorry, too many clients already")); break; case CAC_OK: break; @@ -1414,8 +1433,9 @@ SendGSSAuthResponse(Port *port, char *extradata, uint16_t extralen) static char * convertUsernameToCanonicalform(char *user_name) { - char *canonicalUsername = ""; - char *chr; + char *canonicalUsername = ""; + char *chr; + if ((chr = strchr(user_name, '@')) != NULL) { canonicalUsername = psprintf("%s%s", @@ -1425,6 +1445,7 @@ convertUsernameToCanonicalform(char *user_name) } return user_name; } + /* * This function is similar to pg_GSS_recvauth() but to authenticate a TDS * client. @@ -1439,8 +1460,8 @@ CheckGSSAuth(Port *port) gflags; int ret; gss_buffer_desc gbuf; - MemoryContext oldContext; - char *at_pos = NULL; + MemoryContext oldContext; + char *at_pos = NULL; if (pg_krb_server_keyfile && strlen(pg_krb_server_keyfile) > 0) { @@ -1563,14 +1584,14 @@ CheckGSSAuth(Port *port) maj_stat, min_stat); /* - * XXX: In PG there are options to match realm names or perform ident mappings. - * We're not going to do those checks now. If required, we can implement the - * same in future. - * For now, we just get the realm(domain) name and store it in loginInfo. + * XXX: In PG there are options to match realm names or perform ident + * mappings. We're not going to do those checks now. If required, we can + * implement the same in future. For now, we just get the realm(domain) + * name and store it in loginInfo. * - * We also include the realm name along with username. And, we don't support - * stripping off the realm name from username. So, an username will always - * have the following format: username@realname. + * We also include the realm name along with username. And, we don't + * support stripping off the realm name from username. So, an username + * will always have the following format: username@realname. */ oldContext = MemoryContextSwitchTo(TopMemoryContext); @@ -1598,13 +1619,13 @@ SendLoginError(Port *port, const char *logdetail) if (request->sspiLen > 0) ereport(FATAL, - errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), - errmsg("GSSAPI authentication failed")); + errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), + errmsg("GSSAPI authentication failed")); else ereport(FATAL, - errcode(ERRCODE_SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION), - errmsg("Login failed for user \"%s\"", - request->username)); + errcode(ERRCODE_SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION), + errmsg("Login failed for user \"%s\"", + request->username)); } /* @@ -1621,7 +1642,7 @@ void TdsClientAuthentication(Port *port) { int status = STATUS_ERROR; - const char *logdetail = NULL; + const char *logdetail = NULL; #ifdef ENABLE_GSS StringInfoData ps_data; #endif @@ -1631,20 +1652,20 @@ TdsClientAuthentication(Port *port) #ifdef ENABLE_GSS /* NTLMSSP Authentication Isn't Supported yet. */ - if (strcmp(loginInfo->sspi ,"NTLMSSP") == 0) + if (strcmp(loginInfo->sspi, "NTLMSSP") == 0) { TDSInstrumentation(INSTR_UNSUPPORTED_TDS_LOGIN_NTLMSSP); ereport(FATAL, - (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), - errmsg("Authentication method \"NTLMSSP\" not supported"))); + (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), + errmsg("Authentication method \"NTLMSSP\" not supported"))); } /* We might or might not have the gss workspace already */ if (port->gss == NULL) port->gss = (pg_gssinfo *) MemoryContextAllocZero(TopMemoryContext, - sizeof(pg_gssinfo)); + sizeof(pg_gssinfo)); port->gss->auth = true; status = CheckGSSAuth(port); @@ -1708,20 +1729,20 @@ TdsClientAuthentication(Port *port) NI_NUMERICHOST); #ifdef USE_SSL - ereport(FATAL, - (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), - errmsg("pg_hba.conf rejects connection for host \"%s\", user \"%s\", database \"%s\", %s", - hostinfo, port->user_name, - port->database_name, - port->ssl_in_use ? _("SSL on") : _("SSL off")))); + ereport(FATAL, + (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), + errmsg("pg_hba.conf rejects connection for host \"%s\", user \"%s\", database \"%s\", %s", + hostinfo, port->user_name, + port->database_name, + port->ssl_in_use ? _("SSL on") : _("SSL off")))); #else - ereport(FATAL, - (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), - errmsg("pg_hba.conf rejects connection for host \"%s\", user \"%s\", database \"%s\"", - hostinfo, port->user_name, - port->database_name))); + ereport(FATAL, + (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), + errmsg("pg_hba.conf rejects connection for host \"%s\", user \"%s\", database \"%s\"", + hostinfo, port->user_name, + port->database_name))); #endif - break; + break; } case uaImplicitReject: @@ -1763,27 +1784,27 @@ TdsClientAuthentication(Port *port) 0)) #ifdef USE_SSL - ereport(FATAL, - (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), - errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\", %s", - hostinfo, port->user_name, - port->database_name, - port->ssl_in_use ? _("SSL on") : _("SSL off")), - HOSTNAME_LOOKUP_DETAIL(port))); + ereport(FATAL, + (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), + errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\", %s", + hostinfo, port->user_name, + port->database_name, + port->ssl_in_use ? _("SSL on") : _("SSL off")), + HOSTNAME_LOOKUP_DETAIL(port))); #else - ereport(FATAL, - (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), - errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\"", - hostinfo, port->user_name, - port->database_name), - HOSTNAME_LOOKUP_DETAIL(port))); + ereport(FATAL, + (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), + errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\"", + hostinfo, port->user_name, + port->database_name), + HOSTNAME_LOOKUP_DETAIL(port))); #endif - pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen, - hostinfo, sizeof(hostinfo), - NULL, 0, - NI_NUMERICHOST); - break; + pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen, + hostinfo, sizeof(hostinfo), + NULL, 0, + NI_NUMERICHOST); + break; } case uaSSPI: case uaPeer: @@ -1811,10 +1832,11 @@ TdsClientAuthentication(Port *port) } break; case uaGSS: + /* - * If pg_hba.conf specifies that the entry should be authenticated using - * GSSAPI. If we reach here, we should've already authenticated using - * GSSAPI. So, we can just check the status.. + * If pg_hba.conf specifies that the entry should be authenticated + * using GSSAPI. If we reach here, we should've already + * authenticated using GSSAPI. So, we can just check the status.. */ if (status != STATUS_OK) { @@ -1846,9 +1868,9 @@ TdsClientAuthentication(Port *port) } /* - * If pg_hba.conf specifies that the entry should be authenticated using - * password and the request doesn't contain a password, we should - * throw an error. + * If pg_hba.conf specifies that the entry should be authenticated + * using password and the request doesn't contain a password, we + * should throw an error. */ if (!loginInfo->password) { @@ -1879,43 +1901,43 @@ TdsClientAuthentication(Port *port) SendLoginError(port, logdetail); /* - * Authentication succeeded. But, we cannot send the login acknowledgement - * response until we successfully initialize POSTGRES. If we encounter an - * error during initialization we've to send the error along with a login - * failed response to the TDS client. Check InitPostgres for different - * initialization failure scenarios. + * Authentication succeeded. But, we cannot send the login + * acknowledgement response until we successfully initialize POSTGRES. If + * we encounter an error during initialization we've to send the error + * along with a login failed response to the TDS client. Check + * InitPostgres for different initialization failure scenarios. */ } void TdsClientInit(void) { - /* set up process-exit hook to close the socket */ - /* on_proc_exit(socket_close, 0); TODO Enable it later */ - - /* - * In backends (as soon as forked) we operate the underlying socket in - * nonblocking mode and use latches to implement blocking semantics if - * needed. That allows us to provide safely interruptible reads and - * writes. - * - * Use COMMERROR on failure, because ERROR would try to send the error to - * the client, which might require changing the mode again, leading to - * infinite recursion. - */ + /* set up process-exit hook to close the socket */ + /* on_proc_exit(socket_close, 0); TODO Enable it later */ + + /* + * In backends (as soon as forked) we operate the underlying socket in + * nonblocking mode and use latches to implement blocking semantics if + * needed. That allows us to provide safely interruptible reads and + * writes. + * + * Use COMMERROR on failure, because ERROR would try to send the error to + * the client, which might require changing the mode again, leading to + * infinite recursion. + */ #ifndef WIN32 - if (!pg_set_noblock(MyProcPort->sock)) - ereport(COMMERROR, - (errmsg("could not set socket to nonblocking mode: %m"))); + if (!pg_set_noblock(MyProcPort->sock)) + ereport(COMMERROR, + (errmsg("could not set socket to nonblocking mode: %m"))); #endif - FeBeWaitSet = CreateWaitEventSet(TopMemoryContext, 3); - AddWaitEventToSet(FeBeWaitSet, WL_SOCKET_WRITEABLE, MyProcPort->sock, - NULL, NULL); - AddWaitEventToSet(FeBeWaitSet, WL_LATCH_SET, -1, MyLatch, NULL); - AddWaitEventToSet(FeBeWaitSet, WL_POSTMASTER_DEATH, -1, NULL, NULL); - TdsCommInit(TDS_DEFAULT_INIT_PACKET_SIZE, - tds_secure_read, tds_secure_write); + FeBeWaitSet = CreateWaitEventSet(TopMemoryContext, 3); + AddWaitEventToSet(FeBeWaitSet, WL_SOCKET_WRITEABLE, MyProcPort->sock, + NULL, NULL); + AddWaitEventToSet(FeBeWaitSet, WL_LATCH_SET, -1, MyLatch, NULL); + AddWaitEventToSet(FeBeWaitSet, WL_POSTMASTER_DEATH, -1, NULL, NULL); + TdsCommInit(TDS_DEFAULT_INIT_PACKET_SIZE, + tds_secure_read, tds_secure_write); } /* @@ -1945,8 +1967,8 @@ SecureOpenServer(Port *port) int TdsProcessLogin(Port *port, bool loadedSsl) { - int rc = 0; - int loadEncryption = 0; + int rc = 0; + int loadEncryption = 0; /* Set the LOGIN7 request type for error context */ TdsErrorContext->phase = 0; @@ -1979,8 +2001,8 @@ TdsProcessLogin(Port *port, bool loadedSsl) PG_END_TRY(); /* - * If SSL handshake failure has occurred then no need to go ahead with login, - * Just return from here. + * If SSL handshake failure has occurred then no need to go ahead with + * login, Just return from here. */ if (rc < 0) return rc; @@ -2002,7 +2024,7 @@ TdsProcessLogin(Port *port, bool loadedSsl) TdsErrorContext->err_text = ""; if (rc < 0) - return rc; + return rc; /* Free up the SSL strcture if TDS_ENCRYPT_OFF is set */ if (loadEncryption == TDS_ENCRYPT_OFF) @@ -2023,16 +2045,16 @@ TdsSendLoginAck(Port *port) char *dbname = NULL; int prognameLen = pg_mbstrlen(default_server_name); LoginRequest request; - StringInfoData buf; + StringInfoData buf; uint8 temp8; uint32_t collationInfo; - char collationBytesNew[5]; - char *useDbCommand = NULL; - char *user = NULL; - Oid roleid = InvalidOid; - MemoryContext oldContext; - uint32_t tdsVersion = pg_hton32(loginInfo->tdsVersion); - char srvVersionBytes[4]; + char collationBytesNew[5]; + char *useDbCommand = NULL; + char *user = NULL; + Oid roleid = InvalidOid; + MemoryContext oldContext; + uint32_t tdsVersion = pg_hton32(loginInfo->tdsVersion); + char srvVersionBytes[4]; PG_TRY(); { @@ -2042,7 +2064,10 @@ TdsSendLoginAck(Port *port) TdsErrorContext->err_text = "Initialising Collation Info"; - /* Checking if babelfishpg_tsql extension is loaded before reading babelfishpg_tsql.server_collation_oid GUC*/ + /* + * Checking if babelfishpg_tsql extension is loaded before reading + * babelfishpg_tsql.server_collation_oid GUC + */ StartTransactionCommand(); PushActiveSnapshot(GetTransactionSnapshot()); if (get_extension_oid("babelfishpg_tsql", true) == InvalidOid) @@ -2051,11 +2076,13 @@ TdsSendLoginAck(Port *port) CommitTransactionCommand(); TdsDefineDefaultCollationInfo(); + /* - * Collation(total 5bytes) is made of below fields. And we have to send 5 bytes as part of + * Collation(total 5bytes) is made of below fields. And we have to + * send 5 bytes as part of enviornment change token. LCID(20 bits) + + * collationFlags(8 bits) + version(4 bits) + sortId (8 bits) Here, we + * are storing 5 bytes individually and then send it as part of * enviornment change token. - * LCID(20 bits) + collationFlags(8 bits) + version(4 bits) + sortId (8 bits) - * Here, we are storing 5 bytes individually and then send it as part of enviornment change token. */ collationInfo = TdsDefaultLcid | (TdsDefaultCollationFlags << 20); collationBytesNew[0] = (char) collationInfo & 0x000000ff; @@ -2071,20 +2098,24 @@ TdsSendLoginAck(Port *port) TdsErrorContext->err_text = "Verifying and Sending Login Acknowledgement"; /* Start a server->client message */ - /* TODO: Why do we do this? All messages the backend sends have this type */ + + /* + * TODO: Why do we do this? All messages the backend sends have this + * type + */ TdsSetMessageType(TDS_RESPONSE); /* Append the ENVCHANGE and INFO messages */ /* TODO: find all the real values for EnvChange and Info messages */ /* - * In TDS the packet Size is rounded down to the nearest - * multiple of 4. + * In TDS the packet Size is rounded down to the nearest multiple of + * 4. */ if (request->packetSize == TDS_USE_SERVER_DEFAULT_PACKET_SIZE) { - char old[10]; - char new[10]; + char old[10]; + char new[10]; /* set the packet size as server default */ request->packetSize = tds_default_packet_size; @@ -2095,12 +2126,12 @@ TdsSendLoginAck(Port *port) } else if (request->packetSize != tds_default_packet_size) { - char old[10]; /* the values are between 512 and 32767 */ - char new[10]; + char old[10]; /* the values are between 512 and 32767 */ + char new[10]; /* - * SQL Server rounds down the packet Size to the nearest - * multiple of 4. + * SQL Server rounds down the packet Size to the nearest multiple + * of 4. */ request->packetSize = (((int) request->packetSize / 4) * 4); @@ -2109,14 +2140,16 @@ TdsSendLoginAck(Port *port) TdsSendEnvChange(TDS_ENVID_BLOCKSIZE, new, old); } - /* Check if the user is a valid babelfish login. - * We will only allow following users to login: - * 1. An existing PG user that we have initialised with sys.babelfish_initialize() - * 2. A Postgres SUPERUSER. - * 3. New users created using CREATE LOGIN command through TDS endpoint. */ + /* + * Check if the user is a valid babelfish login. We will only allow + * following users to login: 1. An existing PG user that we have + * initialised with sys.babelfish_initialize() 2. A Postgres + * SUPERUSER. 3. New users created using CREATE LOGIN command through + * TDS endpoint. + */ if (port->user_name != NULL && port->user_name[0] != '\0') { - bool login_exist; + bool login_exist; StartTransactionCommand(); roleid = get_role_oid(port->user_name, false); @@ -2124,7 +2157,7 @@ TdsSendLoginAck(Port *port) CommitTransactionCommand(); /* Throw error if this user is not one of the type mentioned above */ - if(!login_exist && !superuser_arg(roleid)) + if (!login_exist && !superuser_arg(roleid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("\"%s\" is not a Babelfish user", port->user_name))); @@ -2134,12 +2167,12 @@ TdsSendLoginAck(Port *port) if (request->database != NULL && request->database[0] != '\0') { - Oid db_id; + Oid db_id; /* - * Before preparing the query, first check whether we got a - * valid database name and it exists. Otherwise, there'll be - * risk of SQL injection. + * Before preparing the query, first check whether we got a valid + * database name and it exists. Otherwise, there'll be risk of + * SQL injection. */ StartTransactionCommand(); db_id = pltsql_plugin_handler_ptr->pltsql_get_database_oid(request->database); @@ -2147,17 +2180,20 @@ TdsSendLoginAck(Port *port) MemoryContextSwitchTo(oldContext); if (!OidIsValid(db_id)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_DATABASE), - errmsg("database \"%s\" does not exist", request->database))); + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_DATABASE), + errmsg("database \"%s\" does not exist", request->database))); - /* Any delimitated/quoted db name identifier requested in login must be already handled before this point. */ + /* + * Any delimitated/quoted db name identifier requested in login + * must be already handled before this point. + */ useDbCommand = psprintf("USE [%s]", request->database); dbname = pstrdup(request->database); } else { - char *temp = NULL; + char *temp = NULL; StartTransactionCommand(); temp = pltsql_plugin_handler_ptr->pltsql_get_login_default_db(port->user_name); @@ -2188,8 +2224,8 @@ TdsSendLoginAck(Port *port) pfree(dbname); /* - * Request has a database name provided, so we execute - * a "USE []" through pgtsql inline handler + * Request has a database name provided, so we execute a "USE + * []" through pgtsql inline handler */ StartTransactionCommand(); ExecuteSQLBatch(useDbCommand); @@ -2198,27 +2234,29 @@ TdsSendLoginAck(Port *port) pfree(useDbCommand); /* - * Set the GUC for language, it will take care of - * changing the GUC, doing language validity checks - * and sending INFO and ENV change tokens + * Set the GUC for language, it will take care of changing the GUC, + * doing language validity checks and sending INFO and ENV change + * tokens */ if (request->language != NULL) { - int ret; + int ret; + /* - * For varchar GUCs we call pltsql_truncate_identifier which calls get_namespace_oid - * which does catalog access, hence we require to be inside a transaction command. + * For varchar GUCs we call pltsql_truncate_identifier which calls + * get_namespace_oid which does catalog access, hence we require + * to be inside a transaction command. */ StartTransactionCommand(); ret = set_config_option_ext("babelfishpg_tsql.language", - request->language, - PGC_USERSET, - PGC_S_CLIENT, - roleid, - GUC_ACTION_SET, - true /* changeVal */, - 0 /* elevel */, - false /* is_reload */); + request->language, + PGC_USERSET, + PGC_S_CLIENT, + roleid, + GUC_ACTION_SET, + true /* changeVal */ , + 0 /* elevel */ , + false /* is_reload */ ); CommitTransactionCommand(); if (ret != 1) { @@ -2230,25 +2268,26 @@ TdsSendLoginAck(Port *port) /* Set the GUC for application_name. */ if (request->appname != NULL) { - int ret; + int ret; char *tmpAppName = pstrdup(request->appname); pg_clean_ascii(tmpAppName); /* - * For varchar GUCs we call pltsql_truncate_identifier which calls get_namespace_oid - * which does catalog access, hence we require to be inside a transaction command. + * For varchar GUCs we call pltsql_truncate_identifier which calls + * get_namespace_oid which does catalog access, hence we require + * to be inside a transaction command. */ StartTransactionCommand(); ret = set_config_option_ext("application_name", - tmpAppName, - PGC_USERSET, - PGC_S_CLIENT, - roleid, - GUC_ACTION_SET, - true /* changeVal */, - 0 /* elevel */, - false /* is_reload */); + tmpAppName, + PGC_USERSET, + PGC_S_CLIENT, + roleid, + GUC_ACTION_SET, + true /* changeVal */ , + 0 /* elevel */ , + false /* is_reload */ ); CommitTransactionCommand(); if (ret != 1) @@ -2259,23 +2298,23 @@ TdsSendLoginAck(Port *port) } TdsSendEnvChangeBinary(TDS_ENVID_COLLATION, - collationBytesNew, sizeof(collationBytesNew), - NULL, 0); + collationBytesNew, sizeof(collationBytesNew), + NULL, 0); /* Append the LOGINACK message */ - TDS_DEBUG(TDS_DEBUG2, "TdsSendLoginAck: token=0x%02x", TDS_TOKEN_LOGINACK); + TDS_DEBUG(TDS_DEBUG2, "TdsSendLoginAck: token=0x%02x", TDS_TOKEN_LOGINACK); temp8 = TDS_TOKEN_LOGINACK; TdsPutbytes(&temp8, sizeof(temp8)); - temp16 = 1 /* interface */ - + sizeof(tdsVersion) - + 1 /* prognameLen */ - + prognameLen * 2 - + sizeof(srvVersionBytes); + temp16 = 1 /* interface */ + + sizeof(tdsVersion) + + 1 /* prognameLen */ + + prognameLen * 2 + + sizeof(srvVersionBytes); TdsPutbytes(&temp16, sizeof(temp16)); temp8 = 0x01; - TdsPutbytes(&temp8, sizeof(temp8)); /* interface ??? */ + TdsPutbytes(&temp8, sizeof(temp8)); /* interface ??? */ TdsPutbytes(&tdsVersion, sizeof(tdsVersion)); TdsPutbytes(&prognameLen, sizeof(temp8)); @@ -2287,7 +2326,7 @@ TdsSendLoginAck(Port *port) srvVersionBytes[1] = makeVersionByte(1); srvVersionBytes[2] = makeVersionByte(2); srvVersionBytes[3] = makeVersionByte(3); - + TdsPutbytes(&srvVersionBytes, sizeof(srvVersionBytes)); pfree(buf.data); @@ -2297,11 +2336,13 @@ TdsSendLoginAck(Port *port) TdsFlush(); - /* Now, set the network packet size that'll be used further TDS + /* + * Now, set the network packet size that'll be used further TDS * communication. * - * CAUTION: If required, this internally repallocs memory for TDS send and - * receive buffers. So, we should do this after sending the login response. + * CAUTION: If required, this internally repallocs memory for TDS send + * and receive buffers. So, we should do this after sending the login + * response. */ TdsErrorContext->err_text = "Resetting the TDS Buffer size"; TdsSetBufferSize(request->packetSize); @@ -2326,7 +2367,7 @@ TdsSendLoginAck(Port *port) PG_END_TRY(); } -/* +/* * GetClientTDSVersion - exposes TDS version of client being connected. */ uint32_t @@ -2335,14 +2376,14 @@ GetClientTDSVersion(void) /* This should not happen. */ if (loginInfo == NULL) ereport(FATAL, - (errcode(ERRCODE_INTERNAL_ERROR), errmsg("Login Info should not be NULL"))); + (errcode(ERRCODE_INTERNAL_ERROR), errmsg("Login Info should not be NULL"))); return loginInfo->tdsVersion; } /* * This function will return the AD domain name. */ -char* +char * get_tds_login_domainname(void) { if (loginInfo) @@ -2354,7 +2395,7 @@ get_tds_login_domainname(void) /* * To initialise information of default collation based on "babelfishpg_tsql.server_collation_oid" GUC. */ -static void +static void TdsDefineDefaultCollationInfo(void) { coll_info_t cinfo; diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdsprinttup.c b/contrib/babelfishpg_tds/src/backend/tds/tdsprinttup.c index 4b32f8a223..006f2bca15 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tdsprinttup.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tdsprinttup.c @@ -15,7 +15,7 @@ */ static void TdsPrinttupStartup(DestReceiver *self, int operation, - TupleDesc typeinfo); + TupleDesc typeinfo); static void TdsShutdown(DestReceiver *self); static void TdsDestroy(DestReceiver *self); @@ -78,8 +78,8 @@ TdsPrinttupStartup(DestReceiver *self, int operation, TupleDesc typeinfo) ALLOCSET_DEFAULT_SIZES); TdsSendRowDescription(typeinfo, - FetchPortalTargetList(portal), - portal->formats); + FetchPortalTargetList(portal), + portal->formats); return; } diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdsprotocol.c b/contrib/babelfishpg_tds/src/backend/tds/tdsprotocol.c index cb4a640786..038c244dda 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tdsprotocol.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tdsprotocol.c @@ -17,7 +17,7 @@ #include "postgres.h" #include "access/htup_details.h" /* for GETSTRUCT() to extract tuple data */ -#include "access/printtup.h" /* for SetRemoteDestReceiverParams() */ +#include "access/printtup.h" /* for SetRemoteDestReceiverParams() */ #include "access/table.h" #include "access/relation.h" #include "access/relscan.h" @@ -61,18 +61,18 @@ */ typedef struct ResetConnectionData { - StringInfo message; - uint8_t messageType; - uint8_t status; + StringInfo message; + uint8_t messageType; + uint8_t status; } ResetConnectionData; -typedef ResetConnectionData* ResetConnection; +typedef ResetConnectionData *ResetConnection; /* * Local structures */ TdsRequestCtrlData *TdsRequestCtrl = NULL; -ResetConnection resetCon = NULL; +ResetConnection resetCon = NULL; /* Local functions */ static void ResetTDSConnection(void); @@ -85,7 +85,8 @@ static void disable_statement_timeout(void); * TDSDiscardAll - copy of DiscardAll */ static -void TdsDiscardAll() +void +TdsDiscardAll() { /* * Disallow DISCARD ALL in a transaction block. This is arguably @@ -129,8 +130,8 @@ ResetTDSConnection(void) AbortOutOfAnyTransaction(); /* - * Save the transaction isolation level that should be restored after connection - * reset. + * Save the transaction isolation level that should be restored after + * connection reset. */ isolationOld = GetConfigOption("default_transaction_isolation", false, false); @@ -144,8 +145,8 @@ ResetTDSConnection(void) CommitTransactionCommand(); /* - * Now reset the TDS top memory context and re-initialize everything. Also, - * restore the transaction isolation level. + * Now reset the TDS top memory context and re-initialize everything. + * Also, restore the transaction isolation level. */ MemoryContextReset(TdsMemoryContext); TdsCommReset(); @@ -173,10 +174,10 @@ ResetTDSConnection(void) static TDSRequest GetTDSRequest(bool *resetProtocol) { - uint8_t messageType; - uint8_t status; - TDSRequest request; - StringInfoData message; + uint8_t messageType; + uint8_t status; + TDSRequest request; + StringInfoData message; initStringInfo(&message); @@ -184,13 +185,13 @@ GetTDSRequest(bool *resetProtocol) * Setup error traceback support for ereport() */ TdsErrorContext->err_text = "Fetching TDS Request"; - TdsErrorContext->spType = "Unknown (Pre-Parsing Request)"; + TdsErrorContext->spType = "Unknown (Pre-Parsing Request)"; TdsErrorContext->txnType = "Unknown (Pre-Parsing Request)"; PG_TRY(); { /* - * If we've saved the TDS request earlier, process the same instead of trying - * to fetch a new request. + * If we've saved the TDS request earlier, process the same instead of + * trying to fetch a new request. */ if (resetCon != NULL) { @@ -207,13 +208,13 @@ GetTDSRequest(bool *resetProtocol) else { /* - * If TdsRequestCtrl->request is not NULL then - * there are mutliple RPCs in a Batch and we would restore the message - * Otherwise we would fetch the next packet.] + * If TdsRequestCtrl->request is not NULL then there are mutliple + * RPCs in a Batch and we would restore the message Otherwise we + * would fetch the next packet.] */ - if(TdsRequestCtrl->request == NULL) + if (TdsRequestCtrl->request == NULL) { - int ret; + int ret; /* * We should hold the interrupts untill we read the entire @@ -242,21 +243,23 @@ GetTDSRequest(bool *resetProtocol) TdsErrorContext->reqType = messageType; - #ifdef FAULT_INJECTOR +#ifdef FAULT_INJECTOR { - TdsMessageWrapper wrapper; + TdsMessageWrapper wrapper; + wrapper.message = &message; wrapper.messageType = messageType; FAULT_INJECT(PreParsingType, &wrapper); } - #endif +#endif Assert(messageType != 0); /* - * If we have to reset the connection, we save the TDS request in top memory - * context before exit so that we can process the request later. + * If we have to reset the connection, we save the TDS request in top + * memory context before exit so that we can process the request + * later. */ if (status & TDS_PACKET_HEADER_STATUS_RESETCON) { @@ -271,14 +274,14 @@ GetTDSRequest(bool *resetProtocol) resetCon->status = (status & ~TDS_PACKET_HEADER_STATUS_RESETCON); ResetTDSConnection(); - TdsErrorContext->err_text = "Fetching TDS Request"; + TdsErrorContext->err_text = "Fetching TDS Request"; *resetProtocol = true; return NULL; } /* - * XXX: We don't support the following feature. But, throw an error to - * detect the case in case we get such a request. + * XXX: We don't support the following feature. But, throw an error + * to detect the case in case we get such a request. */ if (status & TDS_PACKET_HEADER_STATUS_RESETCONSKIPTRAN) ereport(ERROR, @@ -294,8 +297,8 @@ GetTDSRequest(bool *resetProtocol) } /* - * Enable statement timeout. Note we add this function here to - * include the time taken by the protocol in the timeout. + * Enable statement timeout. Note we add this function here to include + * the time taken by the protocol in the timeout. */ enable_statement_timeout(); @@ -314,7 +317,7 @@ GetTDSRequest(bool *resetProtocol) request = GetRPCRequest(&message); } break; - case TDS_TXN: /* Transaction management request */ + case TDS_TXN: /* Transaction management request */ { request = GetTxnMgmtRequest(&message); } @@ -324,7 +327,7 @@ GetTDSRequest(bool *resetProtocol) request = GetBulkLoadRequest(&message); } break; - case TDS_ATTENTION: /* Attention request */ + case TDS_ATTENTION: /* Attention request */ { /* Return an empty request with the attention type. */ request = palloc0(sizeof(TDSRequest)); @@ -364,8 +367,8 @@ ProcessTDSRequest(TDSRequest request) /* * We shouldn't be in this state as we handle the aborted case on - * babelfishpg_tsql extension itself. But, if we somehow end up - * in this state, throw error and disconnect immediately. + * babelfishpg_tsql extension itself. But, if we somehow end up in this + * state, throw error and disconnect immediately. */ if (IsAbortedTransactionBlockState()) elog(FATAL, "terminating connection due to unexpected TSQL transaction state"); @@ -418,8 +421,8 @@ ProcessTDSRequest(TDSRequest request) } PG_CATCH(); { - int token_type; - int command_type = TDS_CMD_UNKNOWN; + int token_type; + int command_type = TDS_CMD_UNKNOWN; disable_statement_timeout(); CommitTransactionCommand(); @@ -441,7 +444,7 @@ ProcessTDSRequest(TDSRequest request) void TdsProtocolInit(void) { - MemoryContext oldContext; + MemoryContext oldContext; SetConfigOption("babelfishpg_tsql.sql_dialect", "tsql", PGC_SU_BACKEND, PGC_S_OVERRIDE); SetConfigOption("babelfishpg_tsql.enable_tsql_information_schema", "true", PGC_USERSET, PGC_S_SESSION); @@ -486,8 +489,9 @@ TdsProtocolFinish(void) int TdsSocketBackend(void) { - bool resetProtocol; - bool loop = true; + bool resetProtocol; + bool loop = true; + while (loop) { PG_TRY(); @@ -496,13 +500,15 @@ TdsSocketBackend(void) { case TDS_REQUEST_PHASE_INIT: { - MemoryContext oldContext; + MemoryContext oldContext; + resetProtocol = false; TdsErrorContext->phase = "TDS_REQUEST_PHASE_INIT"; + /* - * Switch to the request context. We reset this context once - * once TDSfunctionCache is loaded + * Switch to the request context. We reset this + * context once once TDSfunctionCache is loaded */ oldContext = MemoryContextSwitchTo(TdsMemoryContext); @@ -512,9 +518,9 @@ TdsSocketBackend(void) /* * Loading the cache tables in TdsMemoryContext Memory - * context and is loaded only once during the INIT step. - * TODO: Cache invalidate & reload if some enteries have - * changed + * context and is loaded only once during the INIT + * step. TODO: Cache invalidate & reload if some + * enteries have changed */ TdsLoadTypeFunctionCache(); TdsLoadEncodingLCIDCache(); @@ -523,7 +529,10 @@ TdsSocketBackend(void) MemoryContextSwitchTo(oldContext); - /* we should have exec callbacks initialized by this time */ + /* + * we should have exec callbacks initialized by this + * time + */ if (!(pltsql_plugin_handler_ptr->sql_batch_callback)) elog(FATAL, "sql_batch_callback is not initialized"); if (!(pltsql_plugin_handler_ptr->sp_executesql_callback)) @@ -563,24 +572,26 @@ TdsSocketBackend(void) } case TDS_REQUEST_PHASE_FETCH: { - MemoryContext oldContext; + MemoryContext oldContext; + TdsErrorContext->phase = "TDS_REQUEST_PHASE_FETCH"; /* - * Switch to the request context. We reset this context once - * we send the response. + * Switch to the request context. We reset this + * context once we send the response. */ oldContext = MemoryContextSwitchTo(TdsRequestCtrl->requestContext); /* - * Also consider releasing our catalog snapshot if any, so that it's - * not preventing advance of global xmin while we wait for the client. + * Also consider releasing our catalog snapshot if + * any, so that it's not preventing advance of global + * xmin while we wait for the client. */ InvalidateCatalogSnapshotConditionally(); /* - * We should hold the interrupts untill we read the entire - * request. + * We should hold the interrupts untill we read the + * entire request. */ resetProtocol = false; TdsRequestCtrl->request = GetTDSRequest(&resetProtocol); @@ -627,22 +638,22 @@ TdsSocketBackend(void) Assert(CurrentMemoryContext == MessageContext); /* - * If there are RPC packets left to - * fetch in the packet then we go back - * to the fetch phase + * If there are RPC packets left to fetch in the + * packet then we go back to the fetch phase */ - if(TdsRequestCtrl->request->reqType == TDS_REQUEST_SP_NUMBER && RPCBatchExists(TdsRequestCtrl->request->sp)) + if (TdsRequestCtrl->request->reqType == TDS_REQUEST_SP_NUMBER && RPCBatchExists(TdsRequestCtrl->request->sp)) TdsRequestCtrl->phase = TDS_REQUEST_PHASE_FETCH; else + /* - * No more message to send to the TCOP loop. Send the - * response. + * No more message to send to the TCOP loop. Send + * the response. */ TdsRequestCtrl->phase = TDS_REQUEST_PHASE_FLUSH; /* - * Break here. We will Flush or Fetch the next request in the - * next iteration of PostgresMain function. + * Break here. We will Flush or Fetch the next request + * in the next iteration of PostgresMain function. */ loop = false; break; @@ -668,23 +679,23 @@ TdsSocketBackend(void) TdsErrorContext->phase = "TDS_REQUEST_PHASE_ERROR"; /* - * We've already sent an error token. If required, we can send - * more error tokens before flushing the response. + * We've already sent an error token. If required, we can + * send more error tokens before flushing the response. * N.B. We can reach this state only for some unexpected - * error condition. For normal execution error, babelfishpg_tsql - * extension already handles the error and doesn't - * rethrow to TDS. So, if we're getting some error at this - * level, we should investigate the error. + * error condition. For normal execution error, + * babelfishpg_tsql extension already handles the error + * and doesn't rethrow to TDS. So, if we're getting some + * error at this level, we should investigate the error. */ /* - * Send the done token that follows error - * XXX: Does it matter whether it's DONE or DONEPROC? This - * is anyway not an expected place to throw an error. Find - * a valid usecase before making this logic more complicated. + * Send the done token that follows error XXX: Does it + * matter whether it's DONE or DONEPROC? This is anyway + * not an expected place to throw an error. Find a valid + * usecase before making this logic more complicated. */ TdsSendDone(TDS_TOKEN_DONE, TDS_DONE_ERROR, - TDS_CMD_UNKNOWN, 0); + TDS_CMD_UNKNOWN, 0); /* We're done. Send the response. */ TdsRequestCtrl->phase = TDS_REQUEST_PHASE_FLUSH; @@ -696,9 +707,9 @@ TdsSocketBackend(void) TdsRequestCtrl->phase = TDS_REQUEST_PHASE_ERROR; /* - * We need to rethrow the error as the error handling code in - * the main postgres tcop loop does a lot of necessary cleanups. - * But, if we want to do any further cleanup or take any further + * We need to rethrow the error as the error handling code in the + * main postgres tcop loop does a lot of necessary cleanups. But, + * if we want to do any further cleanup or take any further * action, we can do that here as a pre-processing or in * TDS_REQUEST_PHASE_ERROR state as post-processing. */ @@ -713,10 +724,11 @@ TdsSocketBackend(void) int TestGetTdsRequest(uint8_t reqType, const char *expectedStr) { - int res = 0; - bool resetProtocol; - TDSRequest request = GetTDSRequest(&resetProtocol); - switch(reqType) + int res = 0; + bool resetProtocol; + TDSRequest request = GetTDSRequest(&resetProtocol); + + switch (reqType) { case TDS_TXN: res = TestTxnMgmtRequest(request, expectedStr); @@ -753,4 +765,4 @@ disable_statement_timeout(void) { if (get_timeout_active(STATEMENT_TIMEOUT)) disable_timeout(STATEMENT_TIMEOUT, false); -} \ No newline at end of file +} diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdsresponse.c b/contrib/babelfishpg_tds/src/backend/tds/tdsresponse.c index f6ba774bc4..d9e278bfa2 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tdsresponse.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tdsresponse.c @@ -16,7 +16,7 @@ #include "postgres.h" #include "access/htup_details.h" /* for GETSTRUCT() to extract tuple data */ -#include "access/printtup.h" /* for SetRemoteDestReceiverParams() */ +#include "access/printtup.h" /* for SetRemoteDestReceiverParams() */ #include "access/xact.h" /* for IsTransactionOrTransactionBlock() */ #include "access/genam.h" #include "access/heapam.h" @@ -96,19 +96,19 @@ typedef struct typedef struct TdsExecutionStateData { - int current_stack; - int error_stack_offset; - int cur_error_number; - int cur_error_severity; - int cur_error_state; + int current_stack; + int error_stack_offset; + int cur_error_number; + int cur_error_severity; + int cur_error_state; } TdsExecutionStateData; typedef TdsExecutionStateData *TdsExecutionState; /* Local variables */ -static bool TdsHavePendingDone = false; -static bool TdsPendingDoneNocount; -static uint8_t TdsPendingDoneToken; +static bool TdsHavePendingDone = false; +static bool TdsPendingDoneNocount; +static uint8_t TdsPendingDoneToken; static uint16_t TdsPendingDoneStatus; static uint16_t TdsPendingDoneCurCmd; static uint64_t TdsPendingDoneRowCnt; @@ -118,10 +118,10 @@ static TdsExecutionState tds_estate = NULL; * This denotes whether we've sent an error token and the next done token * should have the error flag marked. */ -static bool markErrorFlag = false; +static bool markErrorFlag = false; static TdsColumnMetaData *colMetaData = NULL; -static List *relMetaDataInfoList = NULL; +static List *relMetaDataInfoList = NULL; static void FillTabNameWithNumParts(StringInfo buf, uint8 numParts, TdsRelationMetaDataInfo relMetaDataInfo); static void FillTabNameWithoutNumParts(StringInfo buf, uint8 numParts, TdsRelationMetaDataInfo relMetaDataInfo); @@ -141,16 +141,17 @@ SendPendingDone(bool more) Assert(!TdsRequestCtrl || more || TdsHavePendingDone); /* - * If this is the last token, then the done token should be either DONE - * or DONEPROC. + * If this is the last token, then the done token should be either DONE or + * DONEPROC. */ Assert(!TdsRequestCtrl || more || (TdsPendingDoneToken == TDS_TOKEN_DONEPROC || - TdsPendingDoneToken == TDS_TOKEN_DONE)); + TdsPendingDoneToken == TDS_TOKEN_DONE)); if (TdsHavePendingDone) { - uint32_t tdsVersion = GetClientTDSVersion(); + uint32_t tdsVersion = GetClientTDSVersion(); + TdsHavePendingDone = false; /* In NOCOUNT=ON mode we need to suppress the DONE_COUNT */ @@ -181,14 +182,14 @@ SendPendingDone(bool more) /* * If we're sending a done token that follows an error token, then - * we must clear the error stack offset. Because, after that we'll - * be back to normal execution. + * we must clear the error stack offset. Because, after that + * we'll be back to normal execution. */ tds_estate->error_stack_offset = 0; /* - * If a statement throws an error, the row count should be - * always 0. + * If a statement throws an error, the row count should be always + * 0. */ Assert(TdsPendingDoneRowCnt == 0); } @@ -199,12 +200,13 @@ SendPendingDone(bool more) TdsPutbytes(&TdsPendingDoneCurCmd, sizeof(TdsPendingDoneCurCmd)); /* - * For Client TDS Version less than or equal to 7.1 Done Row Count is of 4 bytes - * and for TDS versions higher than 7.1 it is of 8 bytes. + * For Client TDS Version less than or equal to 7.1 Done Row Count is + * of 4 bytes and for TDS versions higher than 7.1 it is of 8 bytes. */ if (tdsVersion <= TDS_VERSION_7_1_1) { - uint32_t TdsPendingDoneRowCnt_32; + uint32_t TdsPendingDoneRowCnt_32; + if (TdsPendingDoneRowCnt > PG_UINT32_MAX) ereport(FATAL, (errmsg("Row Count execeeds UINT32_MAX"))); else @@ -223,12 +225,12 @@ SendPendingDone(bool more) static AttrNumber * getPkeyAttnames(Relation rel, int16 *indnkeyatts) { - Relation indexRelation; - ScanKeyData skey; - SysScanDesc scan; - HeapTuple indexTuple; - int i; - AttrNumber *result = NULL; + Relation indexRelation; + ScanKeyData skey; + SysScanDesc scan; + HeapTuple indexTuple; + int i; + AttrNumber *result = NULL; /* initialize indnkeyatts to 0 in case no primary key exists */ *indnkeyatts = 0; @@ -275,23 +277,21 @@ getPkeyAttnames(Relation rel, int16 *indnkeyatts) static void FillTabNameWithNumParts(StringInfo buf, uint8 numParts, TdsRelationMetaDataInfo relMetaDataInfo) { - StringInfoData tempBuf; + StringInfoData tempBuf; initStringInfo(&tempBuf); /* - * XXX: In case a multi-part table name is used in the query, we should send - * the same fully qualified name here in multiple parts. For example, if the - * following format is used in query: - * select * from t1; - * we should send only part with partname 't1'. However, if the following - * format is used: - * select * from [dbo].[t1]; - * we should send two parts with partname 'dbo' and 't1'; + * XXX: In case a multi-part table name is used in the query, we should + * send the same fully qualified name here in multiple parts. For + * example, if the following format is used in query: select * from t1; we + * should send only part with partname 't1'. However, if the following + * format is used: select * from [dbo].[t1]; we should send two parts with + * partname 'dbo' and 't1'; * - * In order to get this information, we definitely need some parser support. - * Probably, we can save this information in portal while parsing the table - * names. + * In order to get this information, we definitely need some parser + * support. Probably, we can save this information in portal while parsing + * the table names. * * For now, always send it in two parts namespace.table name and hope that * client won't complain about the same. @@ -300,8 +300,8 @@ FillTabNameWithNumParts(StringInfo buf, uint8 numParts, TdsRelationMetaDataInfo appendBinaryStringInfo(buf, (char *) &numParts, sizeof(numParts)); while (numParts-- > 0) { - uint16_t partNameLen; - char *partName = relMetaDataInfo->partName[numParts]; + uint16_t partNameLen; + char *partName = relMetaDataInfo->partName[numParts]; resetStringInfo(&tempBuf); TdsUTF8toUTF16StringInfo(&tempBuf, partName, strlen(partName)); @@ -321,24 +321,26 @@ FillTabNameWithNumParts(StringInfo buf, uint8 numParts, TdsRelationMetaDataInfo static void FillTabNameWithoutNumParts(StringInfo buf, uint8 numParts, TdsRelationMetaDataInfo relMetaDataInfo) { - uint16_t TableNameLen = 0; - StringInfoData tempBuf; - char *tableName = ""; + uint16_t TableNameLen = 0; + StringInfoData tempBuf; + char *tableName = ""; + initStringInfo(&tempBuf); /* - * NumParts and PartName are not included in the response for TDS protocol versions - * lower than 7.1 revision (including TDS 7.1 revision 1 in case of ColumnMetadata Token). - * If the Table Name is in parts then we create a single string and convert it to - * UTF16 before putting it on the wire. For example for a table dbo.t1 - * we should send one single tableName as dbo.t1 + * NumParts and PartName are not included in the response for TDS protocol + * versions lower than 7.1 revision (including TDS 7.1 revision 1 in case + * of ColumnMetadata Token). If the Table Name is in parts then we create + * a single string and convert it to UTF16 before putting it on the wire. + * For example for a table dbo.t1 we should send one single tableName as + * dbo.t1 */ while (numParts-- > 0) tableName = psprintf("%s.%s", tableName, relMetaDataInfo->partName[numParts]); if (strlen(tableName)) - tableName++; /* skip the first '.' */ + tableName++; /* skip the first '.' */ TableNameLen += htoLE16((uint16_t) pg_mbstrlen(tableName)); TdsUTF8toUTF16StringInfo(&tempBuf, tableName, strlen(tableName)); @@ -408,352 +410,406 @@ resolve_numeric_typmod_from_exp(Node *expr) switch (nodeTag(expr)) { case T_Const: - { - Const *con = (Const *) expr; - Numeric num; - - /* TODO: - * We used a workaround here, that we will assume typmod is 0 - * if the value we have is not numeric. See walkaround in T_FuncExpr part - * of this function. JIRA: BABEL-1007 - */ - if (con->consttype != NUMERICOID || con->constisnull) - return 0; // Typmod doesn't really matter since it's a const NULL. - else { - num = (Numeric) con->constvalue; - return numeric_get_typmod(num); - } - } - case T_Var: - { - Var *var = (Var*) expr; - return var->vartypmod; - } - case T_OpExpr: - { - OpExpr *op = (OpExpr *) expr; - Node *arg1, *arg2 = NULL; - int32 typmod1 = -1, typmod2 = -1; - uint8_t scale1, scale2, precision1, precision2; - uint8_t scale, precision; - uint8_t integralDigitCount = 0; - /* - * If one of the operands is part of aggregate function SUM() or AVG(), - * set has_aggregate_operand to true; in those cases - * resultant precision and scale calculation would be a bit different - */ - bool has_aggregate_operand = false; + Const *con = (Const *) expr; + Numeric num; - Assert(list_length(op->args) == 2 || list_length(op->args) == 1); - if (list_length(op->args) == 2) - { - arg1 = linitial(op->args); - arg2 = lsecond(op->args); - typmod1 = resolve_numeric_typmod_from_exp(arg1); - typmod2 = resolve_numeric_typmod_from_exp(arg2); - scale1 = (typmod1 - VARHDRSZ) & 0xffff; - precision1 = ((typmod1 - VARHDRSZ) >> 16) & 0xffff; - scale2 = (typmod2 - VARHDRSZ) & 0xffff; - precision2 = ((typmod2 - VARHDRSZ) >> 16) & 0xffff; - } - else if (list_length(op->args) == 1) - { - arg1 = linitial(op->args); - typmod1 = resolve_numeric_typmod_from_exp(arg1); - scale1 = (typmod1 - VARHDRSZ) & 0xffff; - precision1 = ((typmod1 - VARHDRSZ) >> 16) & 0xffff; - scale2 = 0; - precision2 = 0; + /* + * TODO: We used a workaround here, that we will assume typmod + * is 0 if the value we have is not numeric. See walkaround in + * T_FuncExpr part of this function. JIRA: BABEL-1007 + */ + if (con->consttype != NUMERICOID || con->constisnull) + { + return 0; + /* Typmod doesn 't really matter since it' s a const NULL. */ + } + else + { + num = (Numeric) con->constvalue; + return numeric_get_typmod(num); + } } - else + case T_Var: { - /* Shoudn't get here, just need this code to suppress the compiler warnings */ - precision1 = tds_default_numeric_precision; - precision2 = tds_default_numeric_precision; - scale1 = tds_default_numeric_scale; - scale2 = tds_default_numeric_scale; - } + Var *var = (Var *) expr; - /* - * BABEL-2048 Handling arithmetic overflow exception - * when one of the operands is of NON-numeric datatype. - * Use tds_default_numeric_precision/scale if both operands - * are without typmod which probabaly won't happen. - * If one of the operand doesn't have typmod, apply - * the same typmod as the other operand. This makes sense - * because it's equivalent to casting the operand without - * typmod to the other operand's type and typmod then - * do the operation. - */ - if (typmod1 == -1 && typmod2 == -1) - { - precision = tds_default_numeric_precision; - scale = tds_default_numeric_scale; - return ((precision << 16) | scale) + VARHDRSZ; - } - else if (typmod1 == -1) - { - precision1 = precision2; - scale1 = scale2; + return var->vartypmod; } - else if (typmod2 == -1) + case T_OpExpr: { - precision2 = precision1; - scale2 = scale1; - } + OpExpr *op = (OpExpr *) expr; + Node *arg1, + *arg2 = NULL; + int32 typmod1 = -1, + typmod2 = -1; + uint8_t scale1, + scale2, + precision1, + precision2; + uint8_t scale, + precision; + uint8_t integralDigitCount = 0; - /* - * Refer to details of precision and scale calculation in the following link: - * https://github.com/MicrosoftDocs/sql-docs/blob/live/docs/t-sql/data-types/precision-scale-and-length-transact-sql.md - */ - has_aggregate_operand = arg1->type == T_Aggref || - (list_length(op->args) == 2 && arg2->type == T_Aggref); - - switch (op->opfuncid) - { - case NUMERIC_ADD_OID: - case NUMERIC_SUB_OID: - integralDigitCount = Max(precision1 - scale1, precision2 - scale2); - scale = Max(scale1, scale2); - precision = integralDigitCount + 1 + scale; - /* - * For addition and subtraction, skip scale adjustment when none of the - * operands is part of any aggregate function - */ - if (has_aggregate_operand && - integralDigitCount < (Min(TDS_MAX_NUM_PRECISION, precision) - scale)) - scale = Min(precision, TDS_MAX_NUM_PRECISION) - integralDigitCount; + /* + * If one of the operands is part of aggregate function SUM() + * or AVG(), set has_aggregate_operand to true; in those cases + * resultant precision and scale calculation would be a bit + * different + */ + bool has_aggregate_operand = false; + Assert(list_length(op->args) == 2 || list_length(op->args) == 1); + if (list_length(op->args) == 2) + { + arg1 = linitial(op->args); + arg2 = lsecond(op->args); + typmod1 = resolve_numeric_typmod_from_exp(arg1); + typmod2 = resolve_numeric_typmod_from_exp(arg2); + scale1 = (typmod1 - VARHDRSZ) & 0xffff; + precision1 = ((typmod1 - VARHDRSZ) >> 16) & 0xffff; + scale2 = (typmod2 - VARHDRSZ) & 0xffff; + precision2 = ((typmod2 - VARHDRSZ) >> 16) & 0xffff; + } + else if (list_length(op->args) == 1) + { + arg1 = linitial(op->args); + typmod1 = resolve_numeric_typmod_from_exp(arg1); + scale1 = (typmod1 - VARHDRSZ) & 0xffff; + precision1 = ((typmod1 - VARHDRSZ) >> 16) & 0xffff; + scale2 = 0; + precision2 = 0; + } + else + { /* - * precisionn adjustment to TDS_MAX_NUM_PRECISION - */ - if (precision > TDS_MAX_NUM_PRECISION) - precision = TDS_MAX_NUM_PRECISION; - break; - case NUMERIC_MUL_OID: - scale = scale1 + scale2; - precision = precision1 + precision2 + 1; - /* - * For multiplication, skip scale adjustment when atleast one of the - * operands is part of aggregate function + * Shoudn't get here, just need this code to suppress the + * compiler warnings */ - if (has_aggregate_operand && precision > TDS_MAX_NUM_PRECISION) - precision = TDS_MAX_NUM_PRECISION; - break; - case NUMERIC_DIV_OID: - scale = Max(6, scale1 + precision2 + 1); - precision = precision1 - scale1 + scale2 + scale; - break; - case NUMERIC_MOD_OID: - case NUMERIC_MOD_OID2: - scale = Max(scale1, scale2); - precision = Min(precision1-scale1, precision2 -scale2) + scale; - break; - case NUMERIC_UPLUS_OID: - case NUMERIC_UMINUS_OID: - scale = scale1; - precision = precision1; - break; - default: - return -1; - } + precision1 = tds_default_numeric_precision; + precision2 = tds_default_numeric_precision; + scale1 = tds_default_numeric_scale; + scale2 = tds_default_numeric_scale; + } - /* - * Mitigate precision overflow if integral precision <= 38 - * Otherwise it simply won't fit in 38 precision and let an - * overflow error be thrown in PrepareRowDescription. - */ - if (precision > TDS_MAX_NUM_PRECISION) - { - if (precision - scale > 32 && scale > 6) + /* + * BABEL-2048 Handling arithmetic overflow exception when one + * of the operands is of NON-numeric datatype. Use + * tds_default_numeric_precision/scale if both operands are + * without typmod which probabaly won't happen. If one of the + * operand doesn't have typmod, apply the same typmod as the + * other operand. This makes sense because it's equivalent to + * casting the operand without typmod to the other operand's + * type and typmod then do the operation. + */ + if (typmod1 == -1 && typmod2 == -1) { - /* - * Result might be rounded to 6 decimal places or the overflow error - * will be thrown if the integral part can't fit into 32 digits. - */ - precision = TDS_MAX_NUM_PRECISION; - scale = 6; + precision = tds_default_numeric_precision; + scale = tds_default_numeric_scale; + return ((precision << 16) | scale) + VARHDRSZ; } - else if (precision - scale <= TDS_MAX_NUM_PRECISION) + else if (typmod1 == -1) { - /* - * scale adjustment by delta is only applicable for division - * and (multiplcation having no aggregate operand) - */ - int delta = precision - TDS_MAX_NUM_PRECISION; - precision = TDS_MAX_NUM_PRECISION; - scale = Max(scale - delta, 0); + precision1 = precision2; + scale1 = scale2; } + else if (typmod2 == -1) + { + precision2 = precision1; + scale2 = scale1; + } + /* - * Control reaching here for only arithmetic overflow cases + * Refer to details of precision and scale calculation in the + * following link: + * https://github.com/MicrosoftDocs/sql-docs/blob/live/docs/t-sql/data-types/precision-scale-and-length-transact-sql.md */ + has_aggregate_operand = arg1->type == T_Aggref || + (list_length(op->args) == 2 && arg2->type == T_Aggref); + + switch (op->opfuncid) + { + case NUMERIC_ADD_OID: + case NUMERIC_SUB_OID: + integralDigitCount = Max(precision1 - scale1, precision2 - scale2); + scale = Max(scale1, scale2); + precision = integralDigitCount + 1 + scale; + + /* + * For addition and subtraction, skip scale adjustment + * when none of the operands is part of any aggregate + * function + */ + if (has_aggregate_operand && + integralDigitCount < (Min(TDS_MAX_NUM_PRECISION, precision) - scale)) + scale = Min(precision, TDS_MAX_NUM_PRECISION) - integralDigitCount; + + /* + * precisionn adjustment to TDS_MAX_NUM_PRECISION + */ + if (precision > TDS_MAX_NUM_PRECISION) + precision = TDS_MAX_NUM_PRECISION; + break; + case NUMERIC_MUL_OID: + scale = scale1 + scale2; + precision = precision1 + precision2 + 1; + + /* + * For multiplication, skip scale adjustment when + * atleast one of the operands is part of aggregate + * function + */ + if (has_aggregate_operand && precision > TDS_MAX_NUM_PRECISION) + precision = TDS_MAX_NUM_PRECISION; + break; + case NUMERIC_DIV_OID: + scale = Max(6, scale1 + precision2 + 1); + precision = precision1 - scale1 + scale2 + scale; + break; + case NUMERIC_MOD_OID: + case NUMERIC_MOD_OID2: + scale = Max(scale1, scale2); + precision = Min(precision1 - scale1, precision2 - scale2) + scale; + break; + case NUMERIC_UPLUS_OID: + case NUMERIC_UMINUS_OID: + scale = scale1; + precision = precision1; + break; + default: + return -1; + } + + /* + * Mitigate precision overflow if integral precision <= 38 + * Otherwise it simply won't fit in 38 precision and let an + * overflow error be thrown in PrepareRowDescription. + */ + if (precision > TDS_MAX_NUM_PRECISION) + { + if (precision - scale > 32 && scale > 6) + { + /* + * Result might be rounded to 6 decimal places or the + * overflow error will be thrown if the integral part + * can't fit into 32 digits. + */ + precision = TDS_MAX_NUM_PRECISION; + scale = 6; + } + else if (precision - scale <= TDS_MAX_NUM_PRECISION) + { + /* + * scale adjustment by delta is only applicable for + * division and (multiplcation having no aggregate + * operand) + */ + int delta = precision - TDS_MAX_NUM_PRECISION; + + precision = TDS_MAX_NUM_PRECISION; + scale = Max(scale - delta, 0); + } + + /* + * Control reaching here for only arithmetic overflow + * cases + */ + } + return ((precision << 16) | scale) + VARHDRSZ; } - return ((precision << 16) | scale) + VARHDRSZ; - } case T_FuncExpr: - { - FuncExpr *func = (FuncExpr *) expr; - Oid func_oid = InvalidOid; - int rettypmod = -1; + { + FuncExpr *func = (FuncExpr *) expr; + Oid func_oid = InvalidOid; + int rettypmod = -1; - /* Be smart about length-coercion functions... */ - if (exprIsLengthCoercion(expr, &rettypmod)) - return rettypmod; + /* Be smart about length-coercion functions... */ + if (exprIsLengthCoercion(expr, &rettypmod)) + return rettypmod; - /* - * Look up the return type typmod from a persistent - * store using the function oid. - */ - func_oid = func->funcid; - Assert(func_oid != InvalidOid); - - if(func->funcresulttype != VOIDOID) - rettypmod = pltsql_plugin_handler_ptr->pltsql_read_numeric_typmod(func_oid, - func->args == NIL ? 0 : func->args->length, - func->funcresulttype); - return rettypmod; - } + /* + * Look up the return type typmod from a persistent store + * using the function oid. + */ + func_oid = func->funcid; + Assert(func_oid != InvalidOid); + + if (func->funcresulttype != VOIDOID) + rettypmod = pltsql_plugin_handler_ptr->pltsql_read_numeric_typmod(func_oid, + func->args == NIL ? 0 : func->args->length, + func->funcresulttype); + return rettypmod; + } case T_NullIfExpr: - { - /* - * Nullif returns a null value if the two specified expressions are equal, - * Otherwise it returns the first argument. - */ - NullIfExpr *nullif = (NullIfExpr *) expr; - Node *arg1; + { + /* + * Nullif returns a null value if the two specified + * expressions are equal, Otherwise it returns the first + * argument. + */ + NullIfExpr *nullif = (NullIfExpr *) expr; + Node *arg1; - Assert(nullif->args != NIL); + Assert(nullif->args != NIL); - arg1 = linitial(nullif->args); - return resolve_numeric_typmod_from_exp(arg1); - } + arg1 = linitial(nullif->args); + return resolve_numeric_typmod_from_exp(arg1); + } case T_CoalesceExpr: - { - /* Find max possible integral_precision and scale (fractional precision) in a CoalesceExpr */ - CoalesceExpr *coale = (CoalesceExpr *) expr; - ListCell *lc; - Node *arg; - int32 arg_typmod; - uint8_t precision, max_integral_precision = 0, scale, max_scale = 0; - - Assert(coale->args != NIL); - - /* Loop through the list of Coalesce arguments */ - foreach(lc, coale->args) { - arg = lfirst(lc); - arg_typmod = resolve_numeric_typmod_from_exp(arg); - /* return -1 if we fail to resolve one of the arg's typmod */ - if (arg_typmod == -1) - return -1; - /* skip the const NULL, which should have 0 returned as typmod */ - if (arg_typmod == 0) - continue; - scale = (arg_typmod - VARHDRSZ) & 0xffff; - precision = ((arg_typmod - VARHDRSZ) >> 16) & 0xffff; - max_scale = Max(scale, max_scale); - max_integral_precision = Max(precision - scale, max_integral_precision); + /* + * Find max possible integral_precision and scale (fractional + * precision) in a CoalesceExpr + */ + CoalesceExpr *coale = (CoalesceExpr *) expr; + ListCell *lc; + Node *arg; + int32 arg_typmod; + uint8_t precision, + max_integral_precision = 0, + scale, + max_scale = 0; + + Assert(coale->args != NIL); + + /* Loop through the list of Coalesce arguments */ + foreach(lc, coale->args) + { + arg = lfirst(lc); + arg_typmod = resolve_numeric_typmod_from_exp(arg); + /* return -1 if we fail to resolve one of the arg's typmod */ + if (arg_typmod == -1) + return -1; + + /* + * skip the const NULL, which should have 0 returned as + * typmod + */ + if (arg_typmod == 0) + continue; + scale = (arg_typmod - VARHDRSZ) & 0xffff; + precision = ((arg_typmod - VARHDRSZ) >> 16) & 0xffff; + max_scale = Max(scale, max_scale); + max_integral_precision = Max(precision - scale, max_integral_precision); + } + return (((max_integral_precision + max_scale) << 16) | max_scale) + VARHDRSZ; } - return (((max_integral_precision + max_scale) << 16) | max_scale) + VARHDRSZ; - } case T_CaseExpr: - { - /* Find max possible integral_precision and scale (fractional precision) in a CoalesceExpr */ - CaseExpr *case_expr = (CaseExpr *) expr; - ListCell *lc; - CaseWhen *casewhen; - Node *casewhen_result; - int32 typmod; - uint8_t precision, max_integral_precision = 0, scale, max_scale = 0; - - Assert(case_expr->args != NIL); - - /* Loop through the list of WHEN clauses */ - foreach(lc, case_expr->args) { - casewhen = lfirst(lc); - casewhen_result = (Node *) casewhen->result; - typmod = resolve_numeric_typmod_from_exp(casewhen_result); - /* return -1 if we fail to resolve one of the result's typmod */ - if (typmod == -1) - return -1; - /* skip the const NULL, which should have 0 returned as typmod */ - if (typmod == 0) - continue; - scale = (typmod - VARHDRSZ) & 0xffff; - precision = ((typmod - VARHDRSZ) >> 16) & 0xffff; - max_scale = Max(scale, max_scale); - max_integral_precision = Max(precision - scale, max_integral_precision); + /* + * Find max possible integral_precision and scale (fractional + * precision) in a CoalesceExpr + */ + CaseExpr *case_expr = (CaseExpr *) expr; + ListCell *lc; + CaseWhen *casewhen; + Node *casewhen_result; + int32 typmod; + uint8_t precision, + max_integral_precision = 0, + scale, + max_scale = 0; + + Assert(case_expr->args != NIL); + + /* Loop through the list of WHEN clauses */ + foreach(lc, case_expr->args) + { + casewhen = lfirst(lc); + casewhen_result = (Node *) casewhen->result; + typmod = resolve_numeric_typmod_from_exp(casewhen_result); + + /* + * return -1 if we fail to resolve one of the result's + * typmod + */ + if (typmod == -1) + return -1; + + /* + * skip the const NULL, which should have 0 returned as + * typmod + */ + if (typmod == 0) + continue; + scale = (typmod - VARHDRSZ) & 0xffff; + precision = ((typmod - VARHDRSZ) >> 16) & 0xffff; + max_scale = Max(scale, max_scale); + max_integral_precision = Max(precision - scale, max_integral_precision); + } + return (((max_integral_precision + max_scale) << 16) | max_scale) + VARHDRSZ; } - return (((max_integral_precision + max_scale) << 16) | max_scale) + VARHDRSZ; - } case T_Aggref: - { - /* select max(a) from t; max(a) is an Aggref */ - Aggref *aggref = (Aggref *) expr; - TargetEntry *te; - char *aggFuncName; - int32 typmod; - uint8_t precision, scale; + { + /* select max(a) from t; max(a) is an Aggref */ + Aggref *aggref = (Aggref *) expr; + TargetEntry *te; + char *aggFuncName; + int32 typmod; + uint8_t precision, + scale; - Assert(aggref->args != NIL); + Assert(aggref->args != NIL); - te = (TargetEntry *) linitial(aggref->args); - typmod = resolve_numeric_typmod_from_exp((Node *) te->expr); - aggFuncName = get_func_name(aggref->aggfnoid); + te = (TargetEntry *) linitial(aggref->args); + typmod = resolve_numeric_typmod_from_exp((Node *) te->expr); + aggFuncName = get_func_name(aggref->aggfnoid); - scale = (typmod - VARHDRSZ) & 0xffff; - precision = ((typmod - VARHDRSZ) >> 16) & 0xffff; + scale = (typmod - VARHDRSZ) & 0xffff; + precision = ((typmod - VARHDRSZ) >> 16) & 0xffff; - /* - * If we recieve typmod as -1 we should fallback to default scale and precision - * Rather than using -1 typmod to calculate scale and precision which leads to - * TDS protocol error. - */ - if (typmod == -1) - { - scale = tds_default_numeric_scale; - precision = tds_default_numeric_precision; - } - /* - * [BABEL-3074] NUMERIC overflow causes TDS error for aggregate - * function sum(); resultant precision should be tds_default_numeric_precision - */ - if (aggFuncName && strlen(aggFuncName) == 3 && + /* + * If we recieve typmod as -1 we should fallback to default + * scale and precision Rather than using -1 typmod to + * calculate scale and precision which leads to TDS protocol + * error. + */ + if (typmod == -1) + { + scale = tds_default_numeric_scale; + precision = tds_default_numeric_precision; + } + + /* + * [BABEL-3074] NUMERIC overflow causes TDS error for + * aggregate function sum(); resultant precision should be + * tds_default_numeric_precision + */ + if (aggFuncName && strlen(aggFuncName) == 3 && (strncmp(aggFuncName, "sum", 3) == 0)) - precision = tds_default_numeric_precision; + precision = tds_default_numeric_precision; - /* - * For aggregate function avg(); resultant precision should be - * tds_default_numeric_precision and resultant scale = max(input scale, 6) - */ - if (aggFuncName && strlen(aggFuncName) == 3 && + /* + * For aggregate function avg(); resultant precision should be + * tds_default_numeric_precision and resultant scale = + * max(input scale, 6) + */ + if (aggFuncName && strlen(aggFuncName) == 3 && (strncmp(aggFuncName, "avg", 3) == 0)) - { - precision = tds_default_numeric_precision; - scale = Max(scale, 6); - } + { + precision = tds_default_numeric_precision; + scale = Max(scale, 6); + } - pfree(aggFuncName); - return ((precision << 16) | scale) + VARHDRSZ; - } + pfree(aggFuncName); + return ((precision << 16) | scale) + VARHDRSZ; + } case T_PlaceHolderVar: - { - PlaceHolderVar *phv = (PlaceHolderVar *) expr; + { + PlaceHolderVar *phv = (PlaceHolderVar *) expr; - return resolve_numeric_typmod_from_exp((Node *) phv->phexpr); - } + return resolve_numeric_typmod_from_exp((Node *) phv->phexpr); + } case T_RelabelType: - { - RelabelType *rlt = (RelabelType *) expr; + { + RelabelType *rlt = (RelabelType *) expr; - if (rlt->resulttypmod != -1) - return rlt->resulttypmod; - else - return resolve_numeric_typmod_from_exp((Node *) rlt->arg); - } - /* TODO handle more Expr types if needed */ + if (rlt->resulttypmod != -1) + return rlt->resulttypmod; + else + return resolve_numeric_typmod_from_exp((Node *) rlt->arg); + } + /* TODO handle more Expr types if needed */ default: return -1; } @@ -786,13 +842,14 @@ TdsResponseReset(void) ParameterToken MakeEmptyParameterToken(char *name, int atttypid, int32 atttypmod, int attcollation) { - ParameterToken temp = palloc0(sizeof(ParameterTokenData)); - TdsIoFunctionInfo finfo; - TdsColumnMetaData *col; - Oid serverCollationOid; - uint32_t tdsVersion = GetClientTDSVersion(); + ParameterToken temp = palloc0(sizeof(ParameterTokenData)); + TdsIoFunctionInfo finfo; + TdsColumnMetaData *col; + Oid serverCollationOid; + uint32_t tdsVersion = GetClientTDSVersion(); coll_info_t cinfo = TdsLookupCollationTableCallback(InvalidOid); + serverCollationOid = cinfo.oid; if (unlikely(serverCollationOid == InvalidOid)) elog(FATAL, "Oid of default collation is not valid, This might mean that value of server_collation_name GUC is invalid"); @@ -811,7 +868,7 @@ MakeEmptyParameterToken(char *name, int atttypid, int32 atttypmod, int attcollat switch (finfo->sendFuncId) { - /* TODO boolean is equivalent to TSQL BIT type */ + /* TODO boolean is equivalent to TSQL BIT type */ case TDS_SEND_BIT: SetColMetadataForFixedType(col, TDS_TYPE_BIT, TDS_MAXLEN_BIT); temp->maxLen = 1; @@ -849,7 +906,7 @@ MakeEmptyParameterToken(char *name, int atttypid, int32 atttypmod, int attcollat break; case TDS_SEND_NCHAR: SetColMetadataForCharTypeHelper(col, TDS_TYPE_NCHAR, - attcollation, (atttypmod-4) * 2); + attcollation, (atttypmod - 4) * 2); /* if attypmod is -1, consider the datatype as NCHAR(MAX) */ if (atttypmod == -1) temp->maxLen = 0xFFFF; @@ -857,7 +914,7 @@ MakeEmptyParameterToken(char *name, int atttypid, int32 atttypmod, int attcollat case TDS_SEND_VARCHAR: SetColMetadataForCharTypeHelper(col, TDS_TYPE_VARCHAR, attcollation, (atttypmod == -1) ? - atttypmod : (atttypmod - 4)); + atttypmod : (atttypmod - 4)); /* if attypmod is -1, consider the datatype as VARCHAR(MAX) */ if (atttypmod == -1) temp->maxLen = 0xFFFF; @@ -865,7 +922,7 @@ MakeEmptyParameterToken(char *name, int atttypid, int32 atttypmod, int attcollat case TDS_SEND_NVARCHAR: SetColMetadataForCharTypeHelper(col, TDS_TYPE_NVARCHAR, attcollation, (atttypmod == -1) ? - atttypmod : (atttypmod - 4) * 2); + atttypmod : (atttypmod - 4) * 2); /* if attypmod is -1, consider the datatype as NVARCHAR(MAX) */ if (atttypmod == -1) temp->maxLen = 0xFFFF; @@ -888,15 +945,16 @@ MakeEmptyParameterToken(char *name, int atttypid, int32 atttypmod, int attcollat break; case TDS_SEND_DATE: if (tdsVersion < TDS_VERSION_7_3_A) + /* - * If client being connected is using TDS version lower than 7.3A - * then TSQL treats DATE as NVARCHAR. - * Max len here would be 20 ('YYYY-MM-DD'). - * and Making use of default collation Oid. + * If client being connected is using TDS version lower than + * 7.3A then TSQL treats DATE as NVARCHAR. Max len here would + * be 20 ('YYYY-MM-DD'). and Making use of default collation + * Oid. */ SetColMetadataForCharTypeHelper(col, TDS_TYPE_NVARCHAR, serverCollationOid, 20); else - { + { SetColMetadataForDateType(col, TDS_TYPE_DATE); temp->maxLen = 3; } @@ -907,11 +965,13 @@ MakeEmptyParameterToken(char *name, int atttypid, int32 atttypmod, int attcollat break; case TDS_SEND_NUMERIC: { - uint8_t precision = 18, scale = 0; + uint8_t precision = 18, + scale = 0; /* - * Get the precision and scale out of the typmod value if typmod is valid - * Otherwise tds_default_numeric_precision/scale will be used. + * Get the precision and scale out of the typmod value if + * typmod is valid Otherwise + * tds_default_numeric_precision/scale will be used. */ if (atttypmod > VARHDRSZ) { @@ -941,7 +1001,11 @@ MakeEmptyParameterToken(char *name, int atttypid, int32 atttypmod, int attcollat temp->maxLen = 0xFFFF; break; case TDS_SEND_VARBINARY: - /* Generate the typmod from hex const input because typmod won't be specified */ + + /* + * Generate the typmod from hex const input because typmod won't + * be specified + */ SetColMetadataForBinaryType(col, TDS_TYPE_VARBINARY, (atttypmod == -1) ? atttypmod : atttypmod - VARHDRSZ); /* if attypmod is -1, consider the datatype as VARBINARY(MAX) */ @@ -954,19 +1018,21 @@ MakeEmptyParameterToken(char *name, int atttypid, int32 atttypmod, int attcollat break; case TDS_SEND_TIME: if (tdsVersion < TDS_VERSION_7_3_A) + /* - * If client being connected is using TDS version lower than 7.3A - * then TSQL treats TIME as NVARCHAR. - * Max len here would be 32 ('hh:mm:ss[.nnnnnnn]'). - * and Making use of default collation Oid. + * If client being connected is using TDS version lower than + * 7.3A then TSQL treats TIME as NVARCHAR. Max len here would + * be 32 ('hh:mm:ss[.nnnnnnn]'). and Making use of default + * collation Oid. */ SetColMetadataForCharTypeHelper(col, TDS_TYPE_NVARCHAR, serverCollationOid, 32); else { /* - * if time data has no specific scale specified in the query, default scale - * to be considered is 7 always. However, setting default scale to 6 since - * postgres supports upto 6 digits after decimal point + * if time data has no specific scale specified in the query, + * default scale to be considered is 7 always. However, + * setting default scale to 6 since postgres supports upto 6 + * digits after decimal point */ if (atttypmod == -1) atttypmod = DATETIMEOFFSETMAXSCALE; @@ -976,19 +1042,21 @@ MakeEmptyParameterToken(char *name, int atttypid, int32 atttypmod, int attcollat break; case TDS_SEND_DATETIME2: if (tdsVersion < TDS_VERSION_7_3_A) + /* - * If client being connected is using TDS version lower than 7.3A - * then TSQL treats DATETIME2 as NVARCHAR. - * Max len here would be 54('YYYY-MM-DD hh:mm:ss[.nnnnnnn]'). - * and Making use of default collation Oid. + * If client being connected is using TDS version lower than + * 7.3A then TSQL treats DATETIME2 as NVARCHAR. Max len here + * would be 54('YYYY-MM-DD hh:mm:ss[.nnnnnnn]'). and Making + * use of default collation Oid. */ SetColMetadataForCharTypeHelper(col, TDS_TYPE_NVARCHAR, serverCollationOid, 54); else { /* - * if Datetime2 data has no specific scale specified in the query, default scale - * to be considered is 7 always. However, setting default scale to 6 since - * postgres supports upto 6 digits after decimal point + * if Datetime2 data has no specific scale specified in the + * query, default scale to be considered is 7 always. However, + * setting default scale to 6 since postgres supports upto 6 + * digits after decimal point */ if (atttypmod == -1) atttypmod = DATETIMEOFFSETMAXSCALE; @@ -1000,9 +1068,10 @@ MakeEmptyParameterToken(char *name, int atttypid, int32 atttypmod, int attcollat if (tdsVersion > TDS_VERSION_7_1_1) SetColMetadataForFixedType(col, TDS_TYPE_XML, 0); else + /* - * If client being connected is using TDS version lower than or equal to 7.1 - * then TSQL treats XML as NText. + * If client being connected is using TDS version lower than + * or equal to 7.1 then TSQL treats XML as NText. */ SetColMetadataForTextTypeHelper(col, TDS_TYPE_NTEXT, attcollation, (atttypmod - 4) * 2); @@ -1012,11 +1081,12 @@ MakeEmptyParameterToken(char *name, int atttypid, int32 atttypmod, int attcollat break; case TDS_SEND_DATETIMEOFFSET: if (tdsVersion < TDS_VERSION_7_3_A) + /* - * If client being connected is using TDS version lower than 7.3A - * then TSQL treats DATETIMEOFFSET as NVARCHAR. - * Max len here would be 64('YYYY-MM-DD hh:mm:ss[.nnnnnnn] [+|-]hh:mm'). - * and Making use of default collation Oid. + * If client being connected is using TDS version lower than + * 7.3A then TSQL treats DATETIMEOFFSET as NVARCHAR. Max len + * here would be 64('YYYY-MM-DD hh:mm:ss[.nnnnnnn] + * [+|-]hh:mm'). and Making use of default collation Oid. */ SetColMetadataForCharTypeHelper(col, TDS_TYPE_NVARCHAR, serverCollationOid, 64); else @@ -1028,9 +1098,10 @@ MakeEmptyParameterToken(char *name, int atttypid, int32 atttypmod, int attcollat } break; default: + /* - * TODO: Need to create a mapping table for user defined - * data types and handle it here. + * TODO: Need to create a mapping table for user defined data + * types and handle it here. */ ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1059,12 +1130,12 @@ MakeEmptyParameterToken(char *name, int atttypid, int32 atttypmod, int attcollat void SendColumnMetadataToken(int natts, bool sendRowStat) { - StringInfoData tempBuf; - int attno; - uint32_t tdsVersion = GetClientTDSVersion(); + StringInfoData tempBuf; + int attno; + uint32_t tdsVersion = GetClientTDSVersion(); - /* Now send out the COLMETADATA token */ - TDS_DEBUG(TDS_DEBUG2, "SendColumnMetadataToken: token=0x%02x", TDS_TOKEN_COLMETADATA); + /* Now send out the COLMETADATA token */ + TDS_DEBUG(TDS_DEBUG2, "SendColumnMetadataToken: token=0x%02x", TDS_TOKEN_COLMETADATA); TdsPutInt8(TDS_TOKEN_COLMETADATA); TdsPutInt16LE(sendRowStat ? natts + 1 : natts); @@ -1072,16 +1143,18 @@ SendColumnMetadataToken(int natts, bool sendRowStat) for (attno = 0; attno < natts; attno++) { - uint8 temp8; - TdsColumnMetaData *col = &colMetaData[attno]; + uint8 temp8; + TdsColumnMetaData *col = &colMetaData[attno]; /* - * Instead of hardcoding the userType to 0 at various strucutures inside col->metaEntry - * we can write 0x0000 (for versions lower than TDS 7.2) or 0x00000000 (for TDS 7.2 and higher) - * directly on the wire depending version; + * Instead of hardcoding the userType to 0 at various strucutures + * inside col->metaEntry we can write 0x0000 (for versions lower than + * TDS 7.2) or 0x00000000 (for TDS 7.2 and higher) directly on the + * wire depending version; * - * TODO: TDS doc mentions some non-zero values for timestamp and aliases - * NOTE: We have always sent UserType as 0 and clients have never complained about it. + * TODO: TDS doc mentions some non-zero values for timestamp and + * aliases NOTE: We have always sent UserType as 0 and clients have + * never complained about it. */ if (tdsVersion <= TDS_VERSION_7_1_1) TdsPutInt16LE(0); @@ -1092,15 +1165,16 @@ SendColumnMetadataToken(int natts, bool sendRowStat) if (col->sendTableName) { - uint8 numParts; + uint8 numParts; if (col->relinfo != NULL) { numParts = 2; resetStringInfo(&tempBuf); + /* - * In column Metatdata Token -- NumParts, a multi-part table name, - * was intoduced in TDS 7.2 + * In column Metatdata Token -- NumParts, a multi-part table + * name, was intoduced in TDS 7.2 */ if (tdsVersion > TDS_VERSION_7_1_1) FillTabNameWithNumParts(&tempBuf, numParts, col->relinfo); @@ -1112,9 +1186,10 @@ SendColumnMetadataToken(int natts, bool sendRowStat) { /* Expression columns doesn't have table name */ numParts = 1; + /* - * In column Metatdata Token -- NumParts, a multi-part table name, - * was introduced in TDS 7.2 + * In column Metatdata Token -- NumParts, a multi-part table + * name, was introduced in TDS 7.2 */ if (tdsVersion > TDS_VERSION_7_1_1) TdsPutbytes(&numParts, sizeof(numParts)); @@ -1123,14 +1198,14 @@ SendColumnMetadataToken(int natts, bool sendRowStat) } /* - * If it is an expression column, send "0" as the column len + * If it is an expression column, send "0" as the column len * - * NOTE: Relaxing this condition to send "0" as the column len - * when column name is "?column?" (default column alias for - * columns with no name in engine) + * NOTE: Relaxing this condition to send "0" as the column len when + * column name is "?column?" (default column alias for columns with no + * name in engine) * - * This is needed to send a column name for a column which is - * not part of a table but has an alias [BABEL-544] + * This is needed to send a column name for a column which is not part + * of a table but has an alias [BABEL-544] * */ if (strcmp(col->colName.data, "?column?") == 0) @@ -1149,7 +1224,7 @@ SendColumnMetadataToken(int natts, bool sendRowStat) resetStringInfo(&tempBuf); TdsUTF8toUTF16StringInfo(&tempBuf, col->colName.data, - col->colName.len); + col->colName.len); TdsPutbytes(&temp8, sizeof(temp8)); TdsPutbytes(tempBuf.data, tempBuf.len); } @@ -1158,19 +1233,19 @@ SendColumnMetadataToken(int natts, bool sendRowStat) if (sendRowStat) { /* - * XXX: Since the column information for a ROWSTAT column is fixed, the - * value (except the userType) is hard-coded for now. Should this come from the engine? - * This is also sent for FOR BROWSE queries. + * XXX: Since the column information for a ROWSTAT column is fixed, + * the value (except the userType) is hard-coded for now. Should this + * come from the engine? This is also sent for FOR BROWSE queries. */ - char arr[] = { + char arr[] = { 0x00, 0x00, 0x38, 0x07, 0x52, 0x00, 0x4f, 0x00, 0x57, 0x00, 0x53, 0x00, 0x54, 0x00, 0x41, 0x00, 0x54, 0x00 }; /* - * Instead of hardcoding the userType to 0 in the above array we can write - * 0x0000 (for versions lower than TDS 7.2) or 0x00000000 (for TDS 7.2 and higher) - * directly on the wire depending version; + * Instead of hardcoding the userType to 0 in the above array we can + * write 0x0000 (for versions lower than TDS 7.2) or 0x00000000 (for + * TDS 7.2 and higher) directly on the wire depending version; */ if (tdsVersion <= TDS_VERSION_7_1_1) TdsPutInt16LE(0); @@ -1192,9 +1267,9 @@ SendColumnMetadataToken(int natts, bool sendRowStat) void SendTabNameToken(void) { - StringInfoData buf; - ListCell *lc; - uint32_t tdsVersion = GetClientTDSVersion(); + StringInfoData buf; + ListCell *lc; + uint32_t tdsVersion = GetClientTDSVersion(); if (relMetaDataInfoList == NIL) return; @@ -1203,12 +1278,12 @@ SendTabNameToken(void) foreach(lc, relMetaDataInfoList) { - TdsRelationMetaDataInfo relMetaDataInfo = (TdsRelationMetaDataInfo) lfirst(lc); - uint8 numParts = 2; + TdsRelationMetaDataInfo relMetaDataInfo = (TdsRelationMetaDataInfo) lfirst(lc); + uint8 numParts = 2; /* - * In Table Name token -- NumParts, a multi-part table name, - * was intoduced in tds 7.1 revision 1. + * In Table Name token -- NumParts, a multi-part table name, was + * intoduced in tds 7.1 revision 1. */ if (tdsVersion > TDS_VERSION_7_1) FillTabNameWithNumParts(&buf, numParts, relMetaDataInfo); @@ -1216,7 +1291,7 @@ SendTabNameToken(void) FillTabNameWithoutNumParts(&buf, numParts, relMetaDataInfo); } - TDS_DEBUG(TDS_DEBUG2, "SendTabNameToken: token=0x%02x", TDS_TOKEN_TABNAME); + TDS_DEBUG(TDS_DEBUG2, "SendTabNameToken: token=0x%02x", TDS_TOKEN_TABNAME); TdsPutInt8(TDS_TOKEN_TABNAME); TdsPutInt16LE((uint16_t) buf.len); TdsPutbytes(buf.data, buf.len); @@ -1243,22 +1318,22 @@ SendTabNameToken(void) void SendColInfoToken(int natts, bool sendRowStat) { - StringInfoData buf; - StringInfoData tempBuf; - int attno; + StringInfoData buf; + StringInfoData tempBuf; + int attno; - TDS_DEBUG(TDS_DEBUG2, "SendColInfoToken: token=0x%02x", TDS_TOKEN_COLINFO); + TDS_DEBUG(TDS_DEBUG2, "SendColInfoToken: token=0x%02x", TDS_TOKEN_COLINFO); TdsPutInt8(TDS_TOKEN_COLINFO); initStringInfo(&buf); initStringInfo(&tempBuf); for (attno = 0; attno < natts; attno++) { - TdsColumnMetaData *col = &colMetaData[attno]; - uint8 colNum, - tableNum, - status = 0; - uint8 temp8; + TdsColumnMetaData *col = &colMetaData[attno]; + uint8 colNum, + tableNum, + status = 0; + uint8 temp8; colNum = attno + 1; @@ -1278,7 +1353,7 @@ SendColInfoToken(int natts, bool sendRowStat) status |= COLUMN_STATUS_DIFFERENT_NAME; { - int tempatt; + int tempatt; for (tempatt = 0; tempatt < col->relinfo->numkeyattrs; tempatt++) if (col->attrNum == col->relinfo->keyattrs[tempatt]) @@ -1287,33 +1362,33 @@ SendColInfoToken(int natts, bool sendRowStat) } /* column num, table num, status */ - appendBinaryStringInfo(&buf, (const char *)&colNum, sizeof(colNum)); - appendBinaryStringInfo(&buf, (const char *)&tableNum, sizeof(tableNum)); - appendBinaryStringInfo(&buf, (const char *)&status, sizeof(status)); + appendBinaryStringInfo(&buf, (const char *) &colNum, sizeof(colNum)); + appendBinaryStringInfo(&buf, (const char *) &tableNum, sizeof(tableNum)); + appendBinaryStringInfo(&buf, (const char *) &status, sizeof(status)); if (status & COLUMN_STATUS_DIFFERENT_NAME) { Assert(col->baseColName != NULL); temp8 = (uint8_t) pg_mbstrlen(col->baseColName); - appendBinaryStringInfo(&buf, (const char *)&temp8, sizeof(uint8)); + appendBinaryStringInfo(&buf, (const char *) &temp8, sizeof(uint8)); TdsUTF8toUTF16StringInfo(&buf, col->baseColName, strlen(col->baseColName)); } } if (sendRowStat) { - uint8 colNum, - tableNum, - status = 0; + uint8 colNum, + tableNum, + status = 0; colNum = natts + 1; tableNum = 0; status |= COLUMN_STATUS_EXPRESSION | COLUMN_STATUS_HIDDEN; /* column num, table num, status */ - appendBinaryStringInfo(&buf, (const char *)&colNum, sizeof(colNum)); - appendBinaryStringInfo(&buf, (const char *)&tableNum, sizeof(tableNum)); - appendBinaryStringInfo(&buf, (const char *)&status, sizeof(status)); + appendBinaryStringInfo(&buf, (const char *) &colNum, sizeof(colNum)); + appendBinaryStringInfo(&buf, (const char *) &tableNum, sizeof(tableNum)); + appendBinaryStringInfo(&buf, (const char *) &status, sizeof(status)); } TdsPutInt16LE((uint16_t) buf.len); @@ -1323,44 +1398,47 @@ SendColInfoToken(int natts, bool sendRowStat) } static -int TdsGetGenericTypmod(Node *expr) +int +TdsGetGenericTypmod(Node *expr) { - int rettypmod = -1; + int rettypmod = -1; if (!expr) return rettypmod; - switch(nodeTag(expr)) + switch (nodeTag(expr)) { case T_FuncExpr: { - FuncExpr *func; - Oid func_oid = InvalidOid; + FuncExpr *func; + Oid func_oid = InvalidOid; func = (FuncExpr *) expr; /* - * Look up the return type typmod from a persistent - * store using function oid. + * Look up the return type typmod from a persistent store + * using function oid. */ func_oid = func->funcid; Assert(func_oid != InvalidOid); if (func->funcresulttype != VOIDOID) rettypmod = pltsql_plugin_handler_ptr->pltsql_get_generic_typmod(func_oid, - func->args == NIL ? 0 : func->args->length, func->funcresulttype); + func->args == NIL ? 0 : func->args->length, func->funcresulttype); } break; default: + /* - * TODO: expectation is that apart from Func type expressions, we never get - * typmod = -1 when we reach TDS extension for CHAR/NCHAR datatypes. We - * should figure out a determinstic typmod for all other expression types - * inside the engine or babelfishpg_tsql extension. + * TODO: expectation is that apart from Func type expressions, we + * never get typmod = -1 when we reach TDS extension for + * CHAR/NCHAR datatypes. We should figure out a determinstic + * typmod for all other expression types inside the engine or + * babelfishpg_tsql extension. */ ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION), - errmsg("The string size for the given CHAR/NCHAR data is not defined. " - "Please use an explicit CAST or CONVERT to CHAR(n)/NCHAR(n)"))); + errmsg("The string size for the given CHAR/NCHAR data is not defined. " + "Please use an explicit CAST or CONVERT to CHAR(n)/NCHAR(n)"))); break; } @@ -1380,12 +1458,13 @@ void PrepareRowDescription(TupleDesc typeinfo, List *targetlist, int16 *formats, bool extendedInfo, bool fetchPkeys) { - int natts = typeinfo->natts; - int attno; - MemoryContext oldContext; - ListCell *tlist_item = list_head(targetlist); - bool sendTableName = false; - uint8_t precision = 18, scale = 0; + int natts = typeinfo->natts; + int attno; + MemoryContext oldContext; + ListCell *tlist_item = list_head(targetlist); + bool sendTableName = false; + uint8_t precision = 18, + scale = 0; relMetaDataInfoList = NIL; @@ -1394,27 +1473,27 @@ PrepareRowDescription(TupleDesc typeinfo, List *targetlist, int16 *formats, SendPendingDone(true); /* - * The colMetaData is also used in the TdsPrintTup() callback - * below so we place it into the memory context that will be - * reset once per TCOP main loop iteration. + * The colMetaData is also used in the TdsPrintTup() callback below so we + * place it into the memory context that will be reset once per TCOP main + * loop iteration. */ oldContext = MemoryContextSwitchTo(MessageContext); colMetaData = palloc0(sizeof(TdsColumnMetaData) * natts); /* - * We collect all the information first so that we don't have - * to abort half way through the COLMETADATA tag in case of - * an error (like unsupported data type). + * We collect all the information first so that we don't have to abort + * half way through the COLMETADATA tag in case of an error (like + * unsupported data type). */ for (attno = 0; attno < natts; attno++) { - Oid serverCollationOid; - TdsIoFunctionInfo finfo; - Form_pg_attribute att = TupleDescAttr(typeinfo, attno); - Oid atttypid = att->atttypid; - int32 atttypmod = att->atttypmod; - TdsColumnMetaData *col = &colMetaData[attno]; - uint32_t tdsVersion = GetClientTDSVersion(); + Oid serverCollationOid; + TdsIoFunctionInfo finfo; + Form_pg_attribute att = TupleDescAttr(typeinfo, attno); + Oid atttypid = att->atttypid; + int32 atttypmod = att->atttypmod; + TdsColumnMetaData *col = &colMetaData[attno]; + uint32_t tdsVersion = GetClientTDSVersion(); TargetEntry *tle = NULL; coll_info_t cinfo = TdsLookupCollationTableCallback(InvalidOid); @@ -1426,13 +1505,13 @@ PrepareRowDescription(TupleDesc typeinfo, List *targetlist, int16 *formats, * Get the IO function info from our type cache */ finfo = TdsLookupTypeFunctionsByOid(atttypid, &atttypmod); - // atttypid = getBaseTypeAndTypmod(atttypid, &atttypmod); + /* atttypid = getBaseTypeAndTypmod(atttypid, &atttypmod); */ #if 0 { /* Test a reverse lookup */ - TdsIoFunctionInfo finfo2; - int32_t typeid = finfo->ttmtdstypeid; - int32_t typelen = finfo->ttmtdstypelen; + TdsIoFunctionInfo finfo2; + int32_t typeid = finfo->ttmtdstypeid; + int32_t typelen = finfo->ttmtdstypelen; elog(LOG, "found finfo for Oid %d: tdstype=%d tdstyplen=%d", atttypid, typeid, typelen); @@ -1475,12 +1554,13 @@ PrepareRowDescription(TupleDesc typeinfo, List *targetlist, int16 *formats, switch (finfo->sendFuncId) { - /* - * In case of Not NULL constraint on the column, send the variant type. - * This is only done for the Fixed length datat types except uniqueidentifier. - * - * TODO PG boolean is equivalent to TSQL BIT type - */ + /* + * In case of Not NULL constraint on the column, send the + * variant type. This is only done for the Fixed length datat + * types except uniqueidentifier. + * + * TODO PG boolean is equivalent to TSQL BIT type + */ case TDS_SEND_BIT: if (col->attNotNull) SetColMetadataForFixedType(col, VARIANT_TYPE_BIT, TDS_MAXLEN_BIT); @@ -1525,14 +1605,14 @@ PrepareRowDescription(TupleDesc typeinfo, List *targetlist, int16 *formats, break; case TDS_SEND_CHAR: if (atttypmod == -1 && tle != NULL) - atttypmod = TdsGetGenericTypmod((Node *)tle->expr); - + atttypmod = TdsGetGenericTypmod((Node *) tle->expr); + SetColMetadataForCharTypeHelper(col, TDS_TYPE_CHAR, att->attcollation, (atttypmod - 4)); break; case TDS_SEND_NCHAR: if (atttypmod == -1 && tle != NULL) - atttypmod = TdsGetGenericTypmod((Node *)tle->expr); + atttypmod = TdsGetGenericTypmod((Node *) tle->expr); SetColMetadataForCharTypeHelper(col, TDS_TYPE_NCHAR, att->attcollation, (atttypmod - 4) * 2); @@ -1540,12 +1620,12 @@ PrepareRowDescription(TupleDesc typeinfo, List *targetlist, int16 *formats, case TDS_SEND_VARCHAR: SetColMetadataForCharTypeHelper(col, TDS_TYPE_VARCHAR, att->attcollation, (atttypmod == -1) ? - atttypmod : (atttypmod - 4)); + atttypmod : (atttypmod - 4)); break; case TDS_SEND_NVARCHAR: SetColMetadataForCharTypeHelper(col, TDS_TYPE_NVARCHAR, att->attcollation, (atttypmod == -1) ? - atttypmod : (atttypmod - 4) * 2); + atttypmod : (atttypmod - 4) * 2); break; case TDS_SEND_MONEY: if (col->attNotNull) @@ -1571,13 +1651,14 @@ PrepareRowDescription(TupleDesc typeinfo, List *targetlist, int16 *formats, break; case TDS_SEND_DATE: if (tdsVersion < TDS_VERSION_7_3_A) + /* - * If client being connected is using TDS version lower than 7.3A - * then TSQL treats DATE as NVARCHAR. - * Max len here would be 20 ('YYYY-MM-DD'). + * If client being connected is using TDS version lower + * than 7.3A then TSQL treats DATE as NVARCHAR. Max len + * here would be 20 ('YYYY-MM-DD'). */ SetColMetadataForCharTypeHelper(col, TDS_TYPE_NVARCHAR, serverCollationOid, 20); - else + else SetColMetadataForDateType(col, TDS_TYPE_DATE); break; case TDS_SEND_DATETIME: @@ -1589,15 +1670,17 @@ PrepareRowDescription(TupleDesc typeinfo, List *targetlist, int16 *formats, case TDS_SEND_NUMERIC: { /* - * Try to resolve the typmod from tle->expr when typmod is not specified - * TDS client requires a valid typmod other than -1. + * Try to resolve the typmod from tle->expr when typmod is + * not specified TDS client requires a valid typmod other + * than -1. */ if (atttypmod == -1 && tle != NULL) atttypmod = resolve_numeric_typmod_from_exp((Node *) tle->expr); /* - * Get the precision and scale out of the typmod value if typmod is valid - * Otherwise tds_default_numeric_precision/scale will be used. + * Get the precision and scale out of the typmod value if + * typmod is valid Otherwise + * tds_default_numeric_precision/scale will be used. */ if (atttypmod > VARHDRSZ) { @@ -1605,8 +1688,8 @@ PrepareRowDescription(TupleDesc typeinfo, List *targetlist, int16 *formats, precision = ((atttypmod - VARHDRSZ) >> 16) & 0xffff; if (precision > TDS_MAX_NUM_PRECISION) { - ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("Arithmetic overflow error for data type numeric."))); + ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("Arithmetic overflow error for data type numeric."))); } } else @@ -1628,21 +1711,35 @@ PrepareRowDescription(TupleDesc typeinfo, List *targetlist, int16 *formats, sendTableName |= col->sendTableName; break; case TDS_SEND_BINARY: - /* Explicitly set typemod for rowversion because typmod won't be specified */ + + /* + * Explicitly set typemod for rowversion because typmod won't + * be specified + */ if (finfo->ttmtdstypelen == ROWVERSION_SIZE) atttypmod = ROWVERSION_SIZE + VARHDRSZ; - /* The default binary data length is 1 when maxLen isn't specified */ + + /* + * The default binary data length is 1 when maxLen isn't + * specified + */ SetColMetadataForBinaryType(col, TDS_TYPE_BINARY, (atttypmod == -1) ? 1 : atttypmod - VARHDRSZ); break; case TDS_SEND_VARBINARY: - /* Generate the typmod from hex const input because typmod won't be specified */ + + /* + * Generate the typmod from hex const input because typmod + * won't be specified + */ if (atttypmod == -1 && tle != NULL && IsA(tle->expr, Const)) { - Const *con= (Const *) tle->expr; + Const *con = (Const *) tle->expr; + if (!con->constisnull) { - bytea *source = (bytea *) con->constvalue; + bytea *source = (bytea *) con->constvalue; + atttypmod = VARSIZE_ANY(source); } } @@ -1654,20 +1751,22 @@ PrepareRowDescription(TupleDesc typeinfo, List *targetlist, int16 *formats, break; case TDS_SEND_TIME: if (tdsVersion < TDS_VERSION_7_3_A) + /* - * If client being connected is using TDS version lower than 7.3A - * then TSQL treats TIME as NVARCHAR. - * Max len here would be 32 ('hh:mm:ss[.nnnnnnn]'). - * and Making use of default collation Oid. + * If client being connected is using TDS version lower + * than 7.3A then TSQL treats TIME as NVARCHAR. Max len + * here would be 32 ('hh:mm:ss[.nnnnnnn]'). and Making use + * of default collation Oid. */ SetColMetadataForCharTypeHelper(col, TDS_TYPE_NVARCHAR, serverCollationOid, 32); else { /* - * if time data has no specific scale specified in the query, default scale - * to be considered is 7 always. However, setting default scale to 6 since - * postgres supports upto 6 digits after decimal point - */ + * if time data has no specific scale specified in the + * query, default scale to be considered is 7 always. + * However, setting default scale to 6 since postgres + * supports upto 6 digits after decimal point + */ if (atttypmod == -1) atttypmod = DATETIMEOFFSETMAXSCALE; SetColMetadataForTimeType(col, TDS_TYPE_TIME, atttypmod); @@ -1675,20 +1774,22 @@ PrepareRowDescription(TupleDesc typeinfo, List *targetlist, int16 *formats, break; case TDS_SEND_DATETIME2: if (tdsVersion < TDS_VERSION_7_3_A) + /* - * If client being connected is using TDS version lower than 7.3A - * then TSQL treats DATETIME2 as NVARCHAR. - * Max len here would be 54('YYYY-MM-DD hh:mm:ss[.nnnnnnn]'). + * If client being connected is using TDS version lower + * than 7.3A then TSQL treats DATETIME2 as NVARCHAR. Max + * len here would be 54('YYYY-MM-DD hh:mm:ss[.nnnnnnn]'). * and Making use of default collation Oid. */ SetColMetadataForCharTypeHelper(col, TDS_TYPE_NVARCHAR, serverCollationOid, 54); else { /* - * if Datetime2 data has no specific scale specified in the query, default scale - * to be considered is 7 always. However, setting default scale to 6 since - * postgres supports upto 6 digits after decimal point - */ + * if Datetime2 data has no specific scale specified in + * the query, default scale to be considered is 7 always. + * However, setting default scale to 6 since postgres + * supports upto 6 digits after decimal point + */ if (atttypmod == -1) atttypmod = DATETIMEOFFSETMAXSCALE; SetColMetadataForTimeType(col, TDS_TYPE_DATETIME2, atttypmod); @@ -1700,8 +1801,8 @@ PrepareRowDescription(TupleDesc typeinfo, List *targetlist, int16 *formats, else { /* - * If client being connected is using TDS version lower than or equal to 7.1 - * then TSQL treats XML as NText. + * If client being connected is using TDS version lower + * than or equal to 7.1 then TSQL treats XML as NText. */ SetColMetadataForTextTypeHelper(col, TDS_TYPE_NTEXT, att->attcollation, (atttypmod - 4) * 2); @@ -1713,11 +1814,12 @@ PrepareRowDescription(TupleDesc typeinfo, List *targetlist, int16 *formats, break; case TDS_SEND_DATETIMEOFFSET: if (tdsVersion < TDS_VERSION_7_3_A) + /* - * If client being connected is using TDS version lower than 7.3A - * then TSQL treats DATETIMEOFFSET as NVARCHAR. - * Max len here would be 64('YYYY-MM-DD hh:mm:ss[.nnnnnnn] [+|-]hh:mm'). - * and Making use of default collation Oid. + * If client being connected is using TDS version lower + * than 7.3A then TSQL treats DATETIMEOFFSET as NVARCHAR. + * Max len here would be 64('YYYY-MM-DD hh:mm:ss[.nnnnnnn] + * [+|-]hh:mm'). and Making use of default collation Oid. */ SetColMetadataForCharTypeHelper(col, TDS_TYPE_NVARCHAR, serverCollationOid, 64); else @@ -1728,9 +1830,10 @@ PrepareRowDescription(TupleDesc typeinfo, List *targetlist, int16 *formats, } break; default: + /* - * TODO: Need to create a mapping table for user defined - * data types and handle it here. + * TODO: Need to create a mapping table for user defined data + * types and handle it here. */ ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1742,16 +1845,16 @@ PrepareRowDescription(TupleDesc typeinfo, List *targetlist, int16 *formats, if (extendedInfo || sendTableName) { - uint8 tableNum = 0; + uint8 tableNum = 0; oldContext = MemoryContextSwitchTo(MessageContext); relMetaDataInfoList = NULL; for (attno = 0; attno < natts; attno++) { - TdsColumnMetaData *col = &colMetaData[attno]; - ListCell *lc; - bool found = false; + TdsColumnMetaData *col = &colMetaData[attno]; + ListCell *lc; + bool found = false; if (col->relOid == 0) { @@ -1766,8 +1869,8 @@ PrepareRowDescription(TupleDesc typeinfo, List *targetlist, int16 *formats, /* look for a relation entry match */ foreach(lc, relMetaDataInfoList) { - TdsRelationMetaDataInfo relMetaDataInfo = (TdsRelationMetaDataInfo) lfirst(lc); - Oid relOid = relMetaDataInfo->relOid; + TdsRelationMetaDataInfo relMetaDataInfo = (TdsRelationMetaDataInfo) lfirst(lc); + Oid relOid = relMetaDataInfo->relOid; if (relOid == col->relOid) { @@ -1780,9 +1883,9 @@ PrepareRowDescription(TupleDesc typeinfo, List *targetlist, int16 *formats, /* if not found, add one */ if (!found) { - Relation rel; - TdsRelationMetaDataInfo relMetaDataInfo; - char *physical_schema_name; + Relation rel; + TdsRelationMetaDataInfo relMetaDataInfo; + char *physical_schema_name; relMetaDataInfo = (TdsRelationMetaDataInfo) palloc(sizeof(TdsRelationMetaDataInfoData)); tableNum++; @@ -1806,16 +1909,21 @@ PrepareRowDescription(TupleDesc typeinfo, List *targetlist, int16 *formats, physical_schema_name = get_namespace_name(RelationGetNamespace(rel)); /* - * Here, we are assuming that we must have received a valid schema name from the engine. - * So first try to find the logical schema name corresponding to received physical schema name. - * If we could not find the logical schema name then we can say that received schema name is - * shared schema and we do not have to translate it to logical schema name. + * Here, we are assuming that we must have received a valid + * schema name from the engine. So first try to find the + * logical schema name corresponding to received physical + * schema name. If we could not find the logical schema name + * then we can say that received schema name is shared schema + * and we do not have to translate it to logical schema name. */ - if (pltsql_plugin_handler_ptr && + if (pltsql_plugin_handler_ptr && pltsql_plugin_handler_ptr->pltsql_get_logical_schema_name) relMetaDataInfo->partName[1] = (char *) pltsql_plugin_handler_ptr->pltsql_get_logical_schema_name(physical_schema_name, true); - /* If we could not find logical schema name then send physical schema name only assuming its shared schema. */ + /* + * If we could not find logical schema name then send physical + * schema name only assuming its shared schema. + */ if (relMetaDataInfo->partName[1] == NULL) relMetaDataInfo->partName[1] = strdup(physical_schema_name); @@ -1842,31 +1950,34 @@ PrepareRowDescription(TupleDesc typeinfo, List *targetlist, int16 *formats, void SendReturnValueTokenInternal(ParameterToken token, uint8 status, FmgrInfo *finfo, Datum datum, bool isNull, - bool forceCoercion) + bool forceCoercion) { - uint8 temp8; - uint16 temp16; - StringInfo name; - FmgrInfo temp; - uint32_t tdsVersion = GetClientTDSVersion(); + uint8 temp8; + uint16 temp16; + StringInfo name; + FmgrInfo temp; + uint32_t tdsVersion = GetClientTDSVersion(); SendPendingDone(true); /* token type */ - TDS_DEBUG(TDS_DEBUG2, "SendReturnValueTokenInternal: token=0x%02x", TDS_TOKEN_RETURNVALUE); + TDS_DEBUG(TDS_DEBUG2, "SendReturnValueTokenInternal: token=0x%02x", TDS_TOKEN_RETURNVALUE); temp8 = TDS_TOKEN_RETURNVALUE; TdsPutbytes(&temp8, sizeof(temp8)); /* param ordinal */ if (tdsVersion <= TDS_VERSION_7_1_1) + /* - * "BY OBSERVATION" The param ordinal is set to 13 instead of starting from 0 - * for clients with TDS verstion lower than or equal to TDS 7.1 revision 1; + * "BY OBSERVATION" The param ordinal is set to 13 instead of starting + * from 0 for clients with TDS verstion lower than or equal to TDS 7.1 + * revision 1; * - * This isn't mentioned in any of the documentations and making this change is necessary - * Since without this change we get TDS Protocol error from the Driver for RPCs. + * This isn't mentioned in any of the documentations and making this + * change is necessary Since without this change we get TDS Protocol + * error from the Driver for RPCs. */ - temp16 = 13; /* TODO: why 13? */ + temp16 = 13; /* TODO: why 13? */ else temp16 = token->paramOrdinal; TdsPutbytes(&temp16, sizeof(temp16)); @@ -1896,12 +2007,14 @@ SendReturnValueTokenInternal(ParameterToken token, uint8 status, TdsPutbytes(&status, sizeof(status)); /* - * Instead of hardcoding the userType to 0 at various strucutures inside col->metaEntry - * we can write 0x0000 (for versions lower than TDS 7.2) or 0x00000000 (for TDS 7.2 and higher) - * directly on the wire depending version; + * Instead of hardcoding the userType to 0 at various strucutures inside + * col->metaEntry we can write 0x0000 (for versions lower than TDS 7.2) or + * 0x00000000 (for TDS 7.2 and higher) directly on the wire depending + * version; * * TODO: TDS doc mentions some non-zero values for timestamp and aliases - * NOTE: We have always sent UserType as 0 and clients have never complained about it. + * NOTE: We have always sent UserType as 0 and clients have never + * complained about it. */ if (tdsVersion <= TDS_VERSION_7_1_1) TdsPutInt16LE(0); @@ -1918,6 +2031,7 @@ SendReturnValueTokenInternal(ParameterToken token, uint8 status, case TDS_TYPE_TEXT: case TDS_TYPE_NTEXT: case TDS_TYPE_IMAGE: + /* * MS-TDS doc, section 2.2.4.2.1.3 - Null is represented by a * length of -1 (0xFFFFFFFF). @@ -1931,6 +2045,7 @@ SendReturnValueTokenInternal(ParameterToken token, uint8 status, case TDS_TYPE_BINARY: case TDS_TYPE_VARBINARY: case TDS_TYPE_XML: + /* * MS-TDS doc, section 2.2.4.2.1.3 - Null is represented by a * length of -1 (0xFFFF). @@ -1941,6 +2056,7 @@ SendReturnValueTokenInternal(ParameterToken token, uint8 status, TdsPutUInt16LE(0xFFFF); break; default: + /* * MS-TDS doc, section 2.2.4.2.1.2 - Null is represented by a * length of 0. (Fixed length datatypes) @@ -1955,26 +2071,29 @@ SendReturnValueTokenInternal(ParameterToken token, uint8 status, } else if (forceCoercion) { - int32 result = -1; - Oid castFuncOid = InvalidOid; - CoercionPathType pathtype; + int32 result = -1; + Oid castFuncOid = InvalidOid; + CoercionPathType pathtype; /* - * In TDS, we should send the OUT parameters with the length/scale/precision - * specified by the caller. In that case, we may need to do a self-casting. - * Here are the steps: - * 1. Find the self-cast function if it's available. - * 2. Call the typmodin function that returns the attypmod corresponding - * to the caller provided length/scale/precision. - * 3. Call the self-cast function to cast the datum with the above attypmod. + * In TDS, we should send the OUT parameters with the + * length/scale/precision specified by the caller. In that case, we + * may need to do a self-casting. Here are the steps: 1. Find the + * self-cast function if it's available. 2. Call the typmodin function + * that returns the attypmod corresponding to the caller provided + * length/scale/precision. 3. Call the self-cast function to cast the + * datum with the above attypmod. */ - /* Check if the type has a function for length/scale/precision coercion */ + /* + * Check if the type has a function for length/scale/precision + * coercion + */ pathtype = find_typmod_coercion_function(token->paramMeta.pgTypeOid, &castFuncOid); /* - * If we found a function to perform the coercion, do it. We don't support - * other types of coearcion, so just ignore it. + * If we found a function to perform the coercion, do it. We don't + * support other types of coearcion, so just ignore it. */ if (pathtype == COERCION_PATH_FUNC) result = GetTypModForToken(token); @@ -1991,8 +2110,9 @@ SendReturnValueTokenInternal(ParameterToken token, uint8 status, /* should in a transaction, because we'll do a catalog lookup */ if (!finfo && IsTransactionState()) { - Oid typoutputfunc; - bool typIsVarlena; + Oid typoutputfunc; + bool typIsVarlena; + Assert(token->paramMeta.pgTypeOid != InvalidOid); getTypeOutputInfo(token->paramMeta.pgTypeOid, &typoutputfunc, &typIsVarlena); fmgr_info(typoutputfunc, &temp); @@ -2000,18 +2120,18 @@ SendReturnValueTokenInternal(ParameterToken token, uint8 status, } /* send the data */ - (token->paramMeta.sendFunc)(finfo, datum, (void *) &token->paramMeta); + (token->paramMeta.sendFunc) (finfo, datum, (void *) &token->paramMeta); } int GetTypModForToken(ParameterToken token) { - int32 typmod = -1; - Datum *datums = NULL; - ArrayType *arrtypmod = NULL; - char *cstr = NULL; - int n; - Oid pgtypemodin; + int32 typmod = -1; + Datum *datums = NULL; + ArrayType *arrtypmod = NULL; + char *cstr = NULL; + int n; + Oid pgtypemodin; /* * Forcing coercion needs catalog access. Hence, we should be in a @@ -2020,9 +2140,9 @@ GetTypModForToken(ParameterToken token) Assert(IsTransactionState()); /* - * Prepare the argument for calling the typmodin function. We need - * to pass the argument as an array. Each type will have different - * number of elements in the array. + * Prepare the argument for calling the typmodin function. We need to + * pass the argument as an array. Each type will have different number of + * elements in the array. */ n = 0; switch (token->paramMeta.metaEntry.type1.tdsTypeId) @@ -2082,7 +2202,7 @@ GetTypModForToken(ParameterToken token) break; case TDS_TYPE_IMAGE: ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION), - errmsg("Data type 0x22(Image) is a deprecated LOB.\ + errmsg("Data type 0x22(Image) is a deprecated LOB.\ Deprecated types are not supported as output parameters."))); break; default: @@ -2111,10 +2231,10 @@ GetTypModForToken(ParameterToken token) void TdsSendEnvChange(int envid, const char *new_val, const char *old_val) { - StringInfoData newUtf16; - StringInfoData oldUtf16; - int16_t totalLen; - uint8 temp8; + StringInfoData newUtf16; + StringInfoData oldUtf16; + int16_t totalLen; + uint8 temp8; initStringInfo(&newUtf16); initStringInfo(&oldUtf16); @@ -2125,13 +2245,13 @@ TdsSendEnvChange(int envid, const char *new_val, const char *old_val) TdsUTF8toUTF16StringInfo(&newUtf16, new_val, strlen(new_val)); if (old_val) TdsUTF8toUTF16StringInfo(&oldUtf16, old_val, strlen(old_val)); - totalLen = 1 /* envid */ - + 1 /* new len */ - + newUtf16.len - + 1 /* old len */ - + oldUtf16.len; + totalLen = 1 /* envid */ + + 1 /* new len */ + + newUtf16.len + + 1 /* old len */ + + oldUtf16.len; - TDS_DEBUG(TDS_DEBUG2, "TdsSendEnvChange: token=0x%02x", TDS_TOKEN_ENVCHANGE); + TDS_DEBUG(TDS_DEBUG2, "TdsSendEnvChange: token=0x%02x", TDS_TOKEN_ENVCHANGE); temp8 = TDS_TOKEN_ENVCHANGE; TdsPutbytes(&temp8, sizeof(temp8)); @@ -2168,20 +2288,20 @@ TdsSendEnvChange(int envid, const char *new_val, const char *old_val) void TdsSendEnvChangeBinary(int envid, void *new, int newNbytes, - void *old, int oldNbytes) + void *old, int oldNbytes) { int16_t totalLen; uint8 temp8; SendPendingDone(true); - totalLen = 1 /* envid */ - + 1 /* new len */ - + newNbytes - + 1 /* old len */ - + oldNbytes; + totalLen = 1 /* envid */ + + 1 /* new len */ + + newNbytes + + 1 /* old len */ + + oldNbytes; - TDS_DEBUG(TDS_DEBUG2, "TdsSendEnvChangeBinary: token=0x%02x", TDS_TOKEN_ENVCHANGE); + TDS_DEBUG(TDS_DEBUG2, "TdsSendEnvChangeBinary: token=0x%02x", TDS_TOKEN_ENVCHANGE); temp8 = TDS_TOKEN_ENVCHANGE; TdsPutbytes(&temp8, sizeof(temp8)); @@ -2200,18 +2320,18 @@ TdsSendEnvChangeBinary(int envid, void *new, int newNbytes, void TdsSendInfo(int number, int state, int class, - char *message, int lineNo) + char *message, int lineNo) { TdsSendInfoOrError(TDS_TOKEN_INFO, number, state, class, - message, - "BABELFISH", /* TODO: where to get this? */ - "", /* TODO: where to get this? */ - lineNo); + message, + "BABELFISH", /* TODO: where to get this? */ + "", /* TODO: where to get this? */ + lineNo); } void TdsSendError(int number, int state, int class, - char *message, int lineNo) + char *message, int lineNo) { /* * If not already in RESPONSE mode, switch the TDS protocol to RESPONSE @@ -2227,19 +2347,19 @@ TdsSendError(int number, int state, int class, PG_TRY(); { TdsSendInfoOrError(TDS_TOKEN_ERROR, number, state, class, - message, - "BABELFISH", - "", - lineNo); + message, + "BABELFISH", + "", + lineNo); } PG_CATCH(); { /* Send message to client that internal error occurred */ TdsSendInfoOrError(TDS_TOKEN_ERROR, ERRCODE_PLTSQL_ERROR_NOT_MAPPED, 1, 16, - "internal error occurred", - "BABELFISH", - "", - lineNo); + "internal error occurred", + "BABELFISH", + "", + lineNo); PG_RE_THROW(); } PG_END_TRY(); @@ -2249,26 +2369,26 @@ TdsSendError(int number, int state, int class, void TdsSendInfoOrError(int token, int number, int state, int class, - char *message, char *serverName, char *procName, - int lineNo) + char *message, char *serverName, char *procName, + int lineNo) { - StringInfoData messageUtf16; - StringInfoData serverNameUtf16; - StringInfoData procNameUtf16; - int lineNoLen; - int messageLen = strlen(message); - int serverNameLen = strlen(serverName); - int procNameLen = strlen(procName); + StringInfoData messageUtf16; + StringInfoData serverNameUtf16; + StringInfoData procNameUtf16; + int lineNoLen; + int messageLen = strlen(message); + int serverNameLen = strlen(serverName); + int procNameLen = strlen(procName); int16_t messageLen_16 = pg_mbstrlen(message); - int32_t number_32 = (int32_t)number; - int32_t lineNo_32 = (int32_t)lineNo; + int32_t number_32 = (int32_t) number; + int32_t lineNo_32 = (int32_t) lineNo; int16_t totalLen; uint8 temp8; - uint32_t tdsVersion = GetClientTDSVersion(); + uint32_t tdsVersion = GetClientTDSVersion(); /* - * For Client TDS Version less than or equal to 7.1 Line Number is of 2 bytes - * and for TDS versions higher than 7.1 it is of 4 bytes. + * For Client TDS Version less than or equal to 7.1 Line Number is of 2 + * bytes and for TDS versions higher than 7.1 it is of 4 bytes. */ if (tdsVersion <= TDS_VERSION_7_1_1) lineNoLen = sizeof(int16_t); @@ -2285,19 +2405,19 @@ TdsSendInfoOrError(int token, int number, int state, int class, SendPendingDone(true); - totalLen = sizeof(number_32) /* error number */ - + 1 /* state */ - + 1 /* class */ - + sizeof(messageLen_16) /* message len */ - + messageUtf16.len /* message */ - + 1 /* server_name_len */ - + serverNameUtf16.len /* server_name */ - + 1 /* proc_name_len */ - + procNameUtf16.len /* proc_name */ - + lineNoLen; /* line_no */ - - /* Send Info or Error Token. */ - TDS_DEBUG(TDS_DEBUG2, "TdsSendInfoOrError: token=0x%02x", token); + totalLen = sizeof(number_32) /* error number */ + + 1 /* state */ + + 1 /* class */ + + sizeof(messageLen_16) /* message len */ + + messageUtf16.len /* message */ + + 1 /* server_name_len */ + + serverNameUtf16.len /* server_name */ + + 1 /* proc_name_len */ + + procNameUtf16.len /* proc_name */ + + lineNoLen; /* line_no */ + + /* Send Info or Error Token. */ + TDS_DEBUG(TDS_DEBUG2, "TdsSendInfoOrError: token=0x%02x", token); temp8 = token; TdsPutbytes(&temp8, sizeof(temp8)); TdsPutbytes(&totalLen, sizeof(totalLen)); @@ -2323,6 +2443,7 @@ TdsSendInfoOrError(int token, int number, int state, int class, if (tdsVersion <= TDS_VERSION_7_1_1) { int16_t lineNo_16; + if (lineNo > PG_INT16_MAX) ereport(FATAL, (errmsg("Line Number execeeds INT16_MAX"))); else @@ -2339,9 +2460,9 @@ TdsSendInfoOrError(int token, int number, int state, int class, void TdsSendRowDescription(TupleDesc typeinfo, - List *targetlist, int16 *formats) + List *targetlist, int16 *formats) { - TDSRequest request = TdsRequestCtrl->request; + TDSRequest request = TdsRequestCtrl->request; /* If we reach here, typeinfo should not be null. */ Assert(typeinfo != NULL); @@ -2351,19 +2472,22 @@ TdsSendRowDescription(TupleDesc typeinfo, /* * If fNoMetadata flags is set in RPC header flag, the server doesn't need - * to send the metadata again for COLMETADATA token. In that case the, the - * server sends only NoMetaData (0xFFFF) field in COLMETADATA token. + * to send the metadata again for COLMETADATA token. In that case the, + * the server sends only NoMetaData (0xFFFF) field in COLMETADATA token. */ if (request->reqType == TDS_REQUEST_SP_NUMBER) { - TDSRequestSP req = (TDSRequestSP) request; + TDSRequestSP req = (TDSRequestSP) request; - /* Send Column Metadata for SP_PREPARE, SP_PREPEXEC, SP_EXECUTE and SP_EXECUTESQL even if - * the FLAG is set to true, since TSQL does the same. */ + /* + * Send Column Metadata for SP_PREPARE, SP_PREPEXEC, SP_EXECUTE and + * SP_EXECUTESQL even if the FLAG is set to true, since TSQL does the + * same. + */ if ((req->spFlags & SP_FLAGS_NOMETADATA) && (req->spType != SP_PREPARE) && (req->spType != SP_PREPEXEC) && (req->spType != SP_EXECUTE) && (req->spType != SP_EXECUTESQL)) { - TDS_DEBUG(TDS_DEBUG2, "SendColumnMetadataToken: token=0x%02x", TDS_TOKEN_COLMETADATA); + TDS_DEBUG(TDS_DEBUG2, "SendColumnMetadataToken: token=0x%02x", TDS_TOKEN_COLMETADATA); TdsPutInt8(TDS_TOKEN_COLMETADATA); TdsPutInt8(0xFF); TdsPutInt8(0xFF); @@ -2377,23 +2501,23 @@ TdsSendRowDescription(TupleDesc typeinfo, bool TdsPrintTup(TupleTableSlot *slot, DestReceiver *self) { - TupleDesc typeinfo = slot->tts_tupleDescriptor; - DR_printtup *myState = (DR_printtup *) self; - MemoryContext oldContext; - int natts = typeinfo->natts; - int attno; - uint8_t rowToken; - TDSRequest request = TdsRequestCtrl->request; - bool sendRowStat = false; - int nullMapSize = 0; - int simpleRowSize = 0; - uint32_t tdsVersion = GetClientTDSVersion(); - uint8_t *nullMap = NULL; + TupleDesc typeinfo = slot->tts_tupleDescriptor; + DR_printtup *myState = (DR_printtup *) self; + MemoryContext oldContext; + int natts = typeinfo->natts; + int attno; + uint8_t rowToken; + TDSRequest request = TdsRequestCtrl->request; + bool sendRowStat = false; + int nullMapSize = 0; + int simpleRowSize = 0; + uint32_t tdsVersion = GetClientTDSVersion(); + uint8_t *nullMap = NULL; TdsErrorContext->err_text = "Writing the Tds response to the socket"; if (request->reqType == TDS_REQUEST_SP_NUMBER) { - TDSRequestSP req = (TDSRequestSP) request; + TDSRequestSP req = (TDSRequestSP) request; /* ROWSTAT token is sent for sp_cursorfetch */ if (req->spType == SP_CURSORFETCH) @@ -2413,10 +2537,10 @@ TdsPrintTup(TupleTableSlot *slot, DestReceiver *self) if (tdsVersion >= TDS_VERSION_7_3_B) { /* - * NBCROW token was introduced in TDS version 7.3B. - * Determine the row type we send. For rows that don't contain any - * NULL values in variable size columns (like NVARCHAR) we can send - * the simple ROW (0xD1) format. Rows that do (specifically + * NBCROW token was introduced in TDS version 7.3B. Determine the row + * type we send. For rows that don't contain any NULL values in + * variable size columns (like NVARCHAR) we can send the simple ROW + * (0xD1) format. Rows that do (specifically * NVARCHAR/VARCHAR/CHAR/NCHAR/BINARY datatypes) need to be sent as * NBCROW (0xD2). Count the number of nullable columns and build the * null bitmap just in case while we are at it. @@ -2426,7 +2550,7 @@ TdsPrintTup(TupleTableSlot *slot, DestReceiver *self) MemSet(nullMap, 0, nullMapSize * sizeof(int8_t)); for (attno = 0; attno < natts; attno++) { - TdsColumnMetaData *col = &colMetaData[attno]; + TdsColumnMetaData *col = &colMetaData[attno]; if (col->metaEntry.type1.flags & TDS_COLMETA_NULLABLE) { @@ -2438,39 +2562,64 @@ TdsPrintTup(TupleTableSlot *slot, DestReceiver *self) case TDS_TYPE_VARCHAR: case TDS_TYPE_NVARCHAR: if (col->metaEntry.type2.maxSize == 0xffff) - /* - * To send NULL for VARCHAR(max) or NVARCHAR(max), - * we have to indicate it using 0xffffffffffffffff (PLP_NULL) + + /* + * To send NULL for VARCHAR(max) or + * NVARCHAR(max), we have to indicate it using + * 0xffffffffffffffff (PLP_NULL) */ simpleRowSize += 8; else - /* - * For regular case of VARCHAR/NVARCHAR, - * we have to send 0xffff (CHARBIN_NULL) to indicate NULL + + /* + * For regular case of VARCHAR/NVARCHAR, we + * have to send 0xffff (CHARBIN_NULL) to + * indicate NULL */ simpleRowSize += 2; break; case TDS_TYPE_VARBINARY: if (col->metaEntry.type7.maxSize == 0xffff) - /* To send NULL for VARBINARY(max),we have to indicate it using 0xffffffffffffffff (PLP_NULL) */ + + /* + * To send NULL for VARBINARY(max),we have to + * indicate it using 0xffffffffffffffff + * (PLP_NULL) + */ simpleRowSize += 8; else - /* For regular case of VARBINARY,we have to send 0xffff (CHARBIN_NULL) to indicate NULL */ + + /* + * For regular case of VARBINARY,we have to + * send 0xffff (CHARBIN_NULL) to indicate NULL + */ simpleRowSize += 2; break; case TDS_TYPE_CHAR: case TDS_TYPE_NCHAR: case TDS_TYPE_XML: case TDS_TYPE_BINARY: - /* For these datatypes, we need to send 0xffff (CHARBIN_NULL) to indicate NULL */ + + /* + * For these datatypes, we need to send 0xffff + * (CHARBIN_NULL) to indicate NULL + */ simpleRowSize += 2; break; case TDS_TYPE_SQLVARIANT: - /* For sql_variant, we need to send 0x00000000 to indicate NULL */ + + /* + * For sql_variant, we need to send 0x00000000 to + * indicate NULL + */ simpleRowSize += 4; break; default: - /* for other datatypes, we need to send 0x00 (1 byte) only */ + + /* + * for other datatypes, we need to send 0x00 (1 + * byte) only + */ simpleRowSize += 1; break; } @@ -2488,7 +2637,11 @@ TdsPrintTup(TupleTableSlot *slot, DestReceiver *self) } } else - /* ROW is only token to send data for TDS version lower or equal to 7.3A. */ + + /* + * ROW is only token to send data for TDS version lower or equal to + * 7.3A. + */ rowToken = TDS_TOKEN_ROW; /* Send the row token and the NULL bitmap if it is NBCROW */ TDS_DEBUG(TDS_DEBUG2, "rowToken = 0x%02x", rowToken); @@ -2506,15 +2659,16 @@ TdsPrintTup(TupleTableSlot *slot, DestReceiver *self) /* And finally send the actual column values */ for (attno = 0; attno < natts; attno++) { - PrinttupAttrInfo *thisState; - Datum attr; - TdsColumnMetaData *col = &colMetaData[attno]; + PrinttupAttrInfo *thisState; + Datum attr; + TdsColumnMetaData *col = &colMetaData[attno]; if (slot->tts_isnull[attno]) { /* Handle NULL values */ - /* when NBCROW token is used, all NULL values are - * sent using NULL bitmap only + /* + * when NBCROW token is used, all NULL values are sent using NULL + * bitmap only */ if (rowToken == TDS_TOKEN_ROW) { @@ -2523,39 +2677,62 @@ TdsPrintTup(TupleTableSlot *slot, DestReceiver *self) case TDS_TYPE_VARCHAR: case TDS_TYPE_NVARCHAR: if (col->metaEntry.type2.maxSize == 0xffff) - /* + + /* * To send NULL for VARCHAR(max) or NVARCHAR(max), - * we have to indicate it using 0xffffffffffffffff (PLP_NULL) + * we have to indicate it using 0xffffffffffffffff + * (PLP_NULL) */ TdsPutUInt64LE(0xffffffffffffffff); else - /* - * For regular case of VARCHAR/NVARCHAR, - * we have to send 0xffff (CHARBIN_NULL) to indicate NULL + + /* + * For regular case of VARCHAR/NVARCHAR, we have + * to send 0xffff (CHARBIN_NULL) to indicate NULL */ TdsPutInt16LE(0xffff); break; case TDS_TYPE_VARBINARY: if (col->metaEntry.type7.maxSize == 0xffff) - /* To send NULL for VARBINARY(max),we have to indicate it using 0xffffffffffffffff (PLP_NULL) */ + + /* + * To send NULL for VARBINARY(max),we have to + * indicate it using 0xffffffffffffffff (PLP_NULL) + */ TdsPutUInt64LE(0xffffffffffffffff); else - /* For regular case of VARBINARY,we have to send 0xffff (CHARBIN_NULL) to indicate NULL */ + + /* + * For regular case of VARBINARY,we have to send + * 0xffff (CHARBIN_NULL) to indicate NULL + */ TdsPutInt16LE(0xffff); break; case TDS_TYPE_CHAR: case TDS_TYPE_NCHAR: case TDS_TYPE_XML: case TDS_TYPE_BINARY: - /* In case of TDS version lower than or equal to 7.3A, we need to send 0xffff (CHARBIN_NULL)*/ + + /* + * In case of TDS version lower than or equal to 7.3A, + * we need to send 0xffff (CHARBIN_NULL) + */ TdsPutInt16LE(0xffff); break; case TDS_TYPE_SQLVARIANT: - /* For sql_variant, we need to send 0x00000000 to indicate NULL */ + + /* + * For sql_variant, we need to send 0x00000000 to + * indicate NULL + */ TdsPutInt32LE(0); break; default: - /* for these datatypes, we need to send 0x00 (1 byte) only */ + + /* + * for these datatypes, we need to send 0x00 (1 byte) + * only + */ TdsPutUInt8(0); break; } @@ -2578,7 +2755,7 @@ TdsPrintTup(TupleTableSlot *slot, DestReceiver *self) VARSIZE_ANY(attr)); /* Call the type specific output function */ - (col->sendFunc)(&thisState->finfo, attr, (void *)col); + (col->sendFunc) (&thisState->finfo, attr, (void *) col); } /* @@ -2587,13 +2764,13 @@ TdsPrintTup(TupleTableSlot *slot, DestReceiver *self) * Since, we've reached here, we are definitely returning a tuple. So, we * should set the flag as succeeded. * - * XXX: We need to figure out a way to set the flag SP_CURSOR_FETCH_MISSING - * when we can't fetch the underlying tuple. It's only possible in case of - * sensitive cursors when the underlying tuple may have been deleted. In that - * case, the tds protocol prepares a dummy row with the missing data (nullable - * fields set to null, fixed length fields set to 0, blank, or the default for - * that column, as appropriate) followed by SP_CURSOR_FETCH_MISSING as the - * value of ROWSTAT column. + * XXX: We need to figure out a way to set the flag + * SP_CURSOR_FETCH_MISSING when we can't fetch the underlying tuple. It's + * only possible in case of sensitive cursors when the underlying tuple + * may have been deleted. In that case, the tds protocol prepares a dummy + * row with the missing data (nullable fields set to null, fixed length + * fields set to 0, blank, or the default for that column, as appropriate) + * followed by SP_CURSOR_FETCH_MISSING as the value of ROWSTAT column. */ if (sendRowStat) (void) TdsPutInt32LE(SP_CURSOR_FETCH_SUCCEEDED); @@ -2619,13 +2796,13 @@ TdsPrintTupShutdown(void) void TdsSendReturnStatus(int status) { - uint8 temp8; - int32_t tmp; + uint8 temp8; + int32_t tmp; TdsErrorContext->err_text = "Writing Return Status Token"; SendPendingDone(true); - TDS_DEBUG(TDS_DEBUG2, "TdsSendReturnStatus: token=0x%02x", TDS_TOKEN_RETURNSTATUS); + TDS_DEBUG(TDS_DEBUG2, "TdsSendReturnStatus: token=0x%02x", TDS_TOKEN_RETURNSTATUS); temp8 = TDS_TOKEN_RETURNSTATUS; TdsPutbytes(&temp8, sizeof(temp8)); @@ -2645,7 +2822,7 @@ TdsSendReturnStatus(int status) void TdsSendDone(int token, int status, int curcmd, uint64_t nprocessed) { - bool gucNocount = false; + bool gucNocount = false; TdsErrorContext->err_text = "Writing Done Token"; @@ -2661,10 +2838,11 @@ TdsSendDone(int token, int status, int curcmd, uint64_t nprocessed) TDS_DEBUG(TDS_DEBUG2, "TdsSendDone: token=0x%02x, status=%d, curcmd=%d, " "nprocessed=%lu nocount=%d", token, status, curcmd, nprocessed, gucNocount); + /* - * If we have a pending DONE token and encounter another one then - * the pending DONE is not the final one. Add the DONE_MORE flag - * and add it to the output buffer. + * If we have a pending DONE token and encounter another one then the + * pending DONE is not the final one. Add the DONE_MORE flag and add it to + * the output buffer. */ SendPendingDone(true); @@ -2691,8 +2869,8 @@ TdsFlush(void) markErrorFlag = false; /* - * The current execution stack must be zero. Otherwise, - * some of our execution assumtion may have gone wrong. + * The current execution stack must be zero. Otherwise, some of our + * execution assumtion may have gone wrong. */ Assert(!tds_estate || tds_estate->current_stack == 0); @@ -2706,7 +2884,7 @@ TdsFlush(void) void TDSStatementBeginCallback(PLtsql_execstate *estate, PLtsql_stmt *stmt) { - if(tds_estate == NULL) + if (tds_estate == NULL) return; TDS_DEBUG(TDS_DEBUG3, "begin %d", tds_estate->current_stack); @@ -2720,23 +2898,23 @@ TDSStatementBeginCallback(PLtsql_execstate *estate, PLtsql_stmt *stmt) /* * TODO: It's possible that for some statements, we've to send a done toke - * when we start the command and another done token when we end the command. - * TRY..CATCH is one such example. We can use this function to send - * the done token at the beginning of the command. + * when we start the command and another done token when we end the + * command. TRY..CATCH is one such example. We can use this function to + * send the done token at the beginning of the command. */ } static void StatementEnd_Internal(PLtsql_execstate *estate, PLtsql_stmt *stmt, bool error) { - int token_type = TDS_TOKEN_DONEPROC; - int command_type = TDS_CMD_UNKNOWN; - int flags = 0; - uint64_t nprocessed = 0; - bool toplevel = false; - bool is_proc = false; - bool skip_done = false; - bool row_count_valid = false; + int token_type = TDS_TOKEN_DONEPROC; + int command_type = TDS_CMD_UNKNOWN; + int flags = 0; + uint64_t nprocessed = 0; + bool toplevel = false; + bool is_proc = false; + bool skip_done = false; + bool row_count_valid = false; tds_estate->current_stack--; TDS_DEBUG(TDS_DEBUG3, "end %d", tds_estate->current_stack); @@ -2744,8 +2922,8 @@ StatementEnd_Internal(PLtsql_execstate *estate, PLtsql_stmt *stmt, bool error) /* - * If we're ending a statement, that means we've already handled the error. - * In that case, just clear the error offset. + * If we're ending a statement, that means we've already handled the + * error. In that case, just clear the error offset. */ tds_estate->error_stack_offset = 0; @@ -2760,13 +2938,13 @@ StatementEnd_Internal(PLtsql_execstate *estate, PLtsql_stmt *stmt, bool error) return; /* TODO: handle all the cases */ - switch(stmt->cmd_type) + switch (stmt->cmd_type) { case PLTSQL_STMT_GOTO: case PLTSQL_STMT_RETURN: - /* Used in inline table valued functions */ + /* Used in inline table valued functions */ case PLTSQL_STMT_RETURN_QUERY: - /* Used in multi-statement table valued functions */ + /* Used in multi-statement table valued functions */ case PLTSQL_STMT_DECL_TABLE: case PLTSQL_STMT_RETURN_TABLE: { @@ -2802,15 +2980,16 @@ StatementEnd_Internal(PLtsql_execstate *estate, PLtsql_stmt *stmt, bool error) if (plansource->commandTag == CMDTAG_INSERT) { command_type = TDS_CMD_INSERT; + /* - * row_count should be invalid if the INSERT is - * inside the procedure of an INSERT-EXEC, or if - * the INSERT itself is an INSERT-EXEC and it - * just returned error. + * row_count should be invalid if the INSERT + * is inside the procedure of an INSERT-EXEC, + * or if the INSERT itself is an INSERT-EXEC + * and it just returned error. */ row_count_valid = !estate->insert_exec && !(markErrorFlag && - ((PLtsql_stmt_execsql *)stmt)->insert_exec); + ((PLtsql_stmt_execsql *) stmt)->insert_exec); } else if (plansource->commandTag == CMDTAG_UPDATE) { @@ -2822,9 +3001,10 @@ StatementEnd_Internal(PLtsql_execstate *estate, PLtsql_stmt *stmt, bool error) command_type = TDS_CMD_DELETE; row_count_valid = !estate->insert_exec; } + /* - * [BABEL-2090] SELECT statement should show - * 'rows affected' count + * [BABEL-2090] SELECT statement should show 'rows + * affected' count */ else if (plansource->commandTag == CMDTAG_SELECT) { @@ -2860,12 +3040,13 @@ StatementEnd_Internal(PLtsql_execstate *estate, PLtsql_stmt *stmt, bool error) /* * XXX: For SP_CUSTOMTYPE, if we're done executing the top level stored - * procedure, we need to send the return status and OUT parameters - * before the DONEPROC token. + * procedure, we need to send the return status and OUT parameters before + * the DONEPROC token. */ if (toplevel && is_proc) { - TDSRequest request = TdsRequestCtrl->request; + TDSRequest request = TdsRequestCtrl->request; + if (request->reqType == TDS_REQUEST_SP_NUMBER) { TDSRequestSP req = (TDSRequestSP) request; @@ -2876,10 +3057,10 @@ StatementEnd_Internal(PLtsql_execstate *estate, PLtsql_stmt *stmt, bool error) } /* - * Send return status token if executed a procedure at top-level - * N.B. It's possible that the EXEC statement itself throws an error. In - * that case, this token will follow an error token. We should not send - * a return status in that case. + * Send return status token if executed a procedure at top-level N.B. It's + * possible that the EXEC statement itself throws an error. In that case, + * this token will follow an error token. We should not send a return + * status in that case. */ if (!markErrorFlag && toplevel && is_proc) { @@ -2913,8 +3094,8 @@ StatementEnd_Internal(PLtsql_execstate *estate, PLtsql_stmt *stmt, bool error) } /* - * If we shouldn't send a done token for the current command, we can return - * from here. + * If we shouldn't send a done token for the current command, we can + * return from here. */ if (skip_done) return; @@ -2947,7 +3128,7 @@ StatementEnd_Internal(PLtsql_execstate *estate, PLtsql_stmt *stmt, bool error) void TDSStatementEndCallback(PLtsql_execstate *estate, PLtsql_stmt *stmt) { - if(tds_estate == NULL) + if (tds_estate == NULL) return; StatementEnd_Internal(estate, stmt, false); @@ -2956,7 +3137,7 @@ TDSStatementEndCallback(PLtsql_execstate *estate, PLtsql_stmt *stmt) void TDSStatementExceptionCallback(PLtsql_execstate *estate, PLtsql_stmt *stmt, bool terminate_batch) { - if(tds_estate == NULL) + if (tds_estate == NULL) return; TDS_DEBUG(TDS_DEBUG3, "exception %d", tds_estate->current_stack); @@ -2965,8 +3146,8 @@ TDSStatementExceptionCallback(PLtsql_execstate *estate, PLtsql_stmt *stmt, bool /* * If we're terminating the batch, then we should not send any done token - * from this level. The done token will be sent from a higher level - * where the error got handled. + * from this level. The done token will be sent from a higher level where + * the error got handled. */ if (terminate_batch) { @@ -2986,9 +3167,9 @@ TDSStatementExceptionCallback(PLtsql_execstate *estate, PLtsql_stmt *stmt, bool /* * TODO: We should add the current command in a queue. In the current * state, we don't know whether there is a TRY..CATCH in the upper level - * that catches this error. In that case, we don't have to mark the - * error flag in the done token. Once we have that information, we'll - * send done tokens for each entry in this queue and empty the queue. + * that catches this error. In that case, we don't have to mark the error + * flag in the done token. Once we have that information, we'll send done + * tokens for each entry in this queue and empty the queue. */ } @@ -3009,8 +3190,10 @@ SendColumnMetadata(TupleDesc typeinfo, List *targetlist, int16 *formats) static void SetTdsEstateErrorData(void) { - int number, severity, state; - + int number, + severity, + state; + if (GetTdsEstateErrorData(&number, &severity, &state)) { tds_estate->cur_error_number = number; @@ -3049,7 +3232,8 @@ GetTdsEstateErrorData(int *number, int *severity, int *state) *state = tds_estate->cur_error_state; return true; } - /* + + /* * If tds_estate doesn't have valid error data, try to find it in * exec_state_call_stack */ @@ -3062,7 +3246,7 @@ GetTdsEstateErrorData(int *number, int *severity, int *state) static void SetAttributesForColmetada(TdsColumnMetaData *col) { - HeapTuple tp; + HeapTuple tp; Form_pg_attribute att_tup; /* Initialise to false if no valid heap tuple is found. */ @@ -3071,17 +3255,17 @@ SetAttributesForColmetada(TdsColumnMetaData *col) col->attgenerated = false; /* - * Send the right column-metadata only for FMTONLY Statements. - * FIXME: We need to find a generic solution where we do not rely - * on the catalog for constraint information. + * Send the right column-metadata only for FMTONLY Statements. FIXME: We + * need to find a generic solution where we do not rely on the catalog for + * constraint information. */ if (pltsql_plugin_handler_ptr && - !(*pltsql_plugin_handler_ptr->pltsql_is_fmtonly_stmt)) + !(*pltsql_plugin_handler_ptr->pltsql_is_fmtonly_stmt)) return; - tp = SearchSysCache2(ATTNUM, - ObjectIdGetDatum(col->relOid), - Int16GetDatum(col->attrNum)); + tp = SearchSysCache2(ATTNUM, + ObjectIdGetDatum(col->relOid), + Int16GetDatum(col->attrNum)); if (HeapTupleIsValid(tp)) { diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdsrpc.c b/contrib/babelfishpg_tds/src/backend/tds/tdsrpc.c index b881d043ef..123714d08f 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tdsrpc.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tdsrpc.c @@ -87,9 +87,12 @@ do \ #define SP_CURSOR_SCROLLOPT_FAST_FORWARD_ACCEPTABLE 0x100000 #define SP_CURSOR_CCOPT_READ_ONLY 0x0001 -#define SP_CURSOR_CCOPT_SCROLL_LOCKS 0x0002 /* previously known as LOCKCC */ -#define SP_CURSOR_CCOPT_OPTIMISTIC1 0x0004 /* previously known as OPTCC */ -#define SP_CURSOR_CCOPT_OPTIMISTIC2 0x0008 /* previously known as OPTCCVAL */ +#define SP_CURSOR_CCOPT_SCROLL_LOCKS 0x0002 /* previously known as + * LOCKCC */ +#define SP_CURSOR_CCOPT_OPTIMISTIC1 0x0004 /* previously known as + * OPTCC */ +#define SP_CURSOR_CCOPT_OPTIMISTIC2 0x0008 /* previously known as + * OPTCCVAL */ #define SP_CURSOR_CCOPT_ALLOW_DIRECT 0x2000 #define SP_CURSOR_CCOPT_UPDT_IN_PLACE 0x4000 #define SP_CURSOR_CCOPT_CHECK_ACCEPTED_OPTS 0x8000 @@ -128,18 +131,18 @@ static void GetSPCursorHandleParameter(TDSRequestSP request); static inline void FillStoredProcedureCallFromParameterToken(TDSRequestSP req, StringInfo inBuf); static inline void FillQueryFromParameterToken(TDSRequestSP req, - StringInfo inBuf); + StringInfo inBuf); static inline void InitializeDataParamTokenIndex(TDSRequestSP req); static void InitialiseParameterToken(TDSRequestSP request); static inline Portal GetPortalFromCursorHandle(const int portalHandle, bool missingOk); static void SendCursorResponse(TDSRequestSP req); static inline void FetchCursorOptions(TDSRequestSP req); -static int SetCursorOption(TDSRequestSP req); +static int SetCursorOption(TDSRequestSP req); static void HandleSPCursorOpenCommon(TDSRequestSP req); static void HandleSPCursorCloseRequest(TDSRequestSP req); static void HandleSPCursorUnprepareRequest(TDSRequestSP req); static void GenerateBindParamsData(TDSRequestSP req); -static int ReadParameters(TDSRequestSP request, uint64_t offset, StringInfo message, int *parameterCount); +static int ReadParameters(TDSRequestSP request, uint64_t offset, StringInfo message, int *parameterCount); static void SPExecuteSQL(TDSRequestSP req); static void SPPrepare(TDSRequestSP req); static void SPExecute(TDSRequestSP req); @@ -147,14 +150,14 @@ static void SPPrepExec(TDSRequestSP req); static void SPCustomType(TDSRequestSP req); static void SPUnprepare(TDSRequestSP req); static void TDSLogStatementCursorHandler(TDSRequestSP req, char *stmt, int option); -static InlineCodeBlockArgs* DeclareVariables(TDSRequestSP req, FunctionCallInfo *fcinfo, unsigned long options); -List *tvp_lookup_list = NIL; -bool lockForFaultInjection = false; +static InlineCodeBlockArgs *DeclareVariables(TDSRequestSP req, FunctionCallInfo *fcinfo, unsigned long options); +List *tvp_lookup_list = NIL; +bool lockForFaultInjection = false; -static InlineCodeBlockArgs* +static InlineCodeBlockArgs * CreateArgs(int nargs) { - InlineCodeBlockArgs *args; + InlineCodeBlockArgs *args; args = (InlineCodeBlockArgs *) palloc0(sizeof(InlineCodeBlockArgs)); args->numargs = nargs; @@ -175,15 +178,16 @@ CreateArgs(int nargs) * If fcinfo is NULL, then don't call the pltsql API - just get the args and set * up TVP lookup. */ -static InlineCodeBlockArgs* +static InlineCodeBlockArgs * DeclareVariables(TDSRequestSP req, FunctionCallInfo *fcinfo, unsigned long options) { - InlineCodeBlockArgs *args = NULL; - ParameterToken token = NULL; - int i = 0, index = 0; - bool resolveParamNames = false; - char *tmp = NULL, - *fToken = NULL; + InlineCodeBlockArgs *args = NULL; + ParameterToken token = NULL; + int i = 0, + index = 0; + bool resolveParamNames = false; + char *tmp = NULL, + *fToken = NULL; args = (InlineCodeBlockArgs *) palloc0(sizeof(InlineCodeBlockArgs)); args->numargs = req->nTotalParams; @@ -205,12 +209,12 @@ DeclareVariables(TDSRequestSP req, FunctionCallInfo *fcinfo, unsigned long optio args->argtypmods = (int32 *) palloc(sizeof(int32) * args->numargs); args->argnames = (char **) palloc(sizeof(char *) * args->numargs); args->argmodes = (char *) palloc(sizeof(char) * args->numargs); + /* - * We have the assumption that either all parameters will have names - * or none of them will have. - * So, check the parameter name for the first token and set the flag. - * If above assumption is invalid, then we will raise the error in - * below for loop. + * We have the assumption that either all parameters will have names or + * none of them will have. So, check the parameter name for the first + * token and set the flag. If above assumption is invalid, then we will + * raise the error in below for loop. */ if (req->dataParameter->paramMeta.colName.len == 0) { @@ -221,18 +225,17 @@ DeclareVariables(TDSRequestSP req, FunctionCallInfo *fcinfo, unsigned long optio req->metaDataParameterValue->len); /* - * XXX: Ugly hack - When the client driver doesn't specify the parameter names - * along with each parameter token, it can be of the either of the following - * two formats: + * XXX: Ugly hack - When the client driver doesn't specify the + * parameter names along with each parameter token, it can be of + * the either of the following two formats: * - * @P0 , @P1 , ..... - * or - * @P1 , @P2 , ..... + * @P0 , @P1 , ..... or @P1 , @P2 + * , ..... * - * So, we just check the first parameter name whether it starts with "0" or - * "1" and auto-generate the parameter names. + * So, we just check the first parameter name whether it starts + * with "0" or "1" and auto-generate the parameter names. */ - fToken = strtok (tmp, " "); + fToken = strtok(tmp, " "); if (strcmp(fToken, "@P0") == 0) i = 0; else if (strcmp(fToken, "@P1") == 0) @@ -249,13 +252,13 @@ DeclareVariables(TDSRequestSP req, FunctionCallInfo *fcinfo, unsigned long optio } /* - * For each token, we need to call pltsql_declare_var_block_handler API - * to declare the corresponding variable. + * For each token, we need to call pltsql_declare_var_block_handler API to + * declare the corresponding variable. */ for (token = req->dataParameter, index = 0; token != NULL; token = token->next, index++) { - char *paramName; - StringInfo name; + char *paramName; + StringInfo name; Datum pval; bool isNull; TdsIoFunctionInfo tempFuncInfo; @@ -264,17 +267,16 @@ DeclareVariables(TDSRequestSP req, FunctionCallInfo *fcinfo, unsigned long optio /* * TODO: Can we directly give the intermediate token (@P0 int, @P1 - * varchar))to the pltsql ? - * Also, maybe we can use the raw_parser() directly for getting the parameter - * names + * varchar))to the pltsql ? Also, maybe we can use the raw_parser() + * directly for getting the parameter names */ if (resolveParamNames && (name->len)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("not all Parameters have names"))); - else if(resolveParamNames) + else if (resolveParamNames) { - char buf[10]; + char buf[10]; snprintf(buf, sizeof(buf), "@p%d", i); paramName = pnstrdup(buf, strlen(buf));; @@ -292,25 +294,27 @@ DeclareVariables(TDSRequestSP req, FunctionCallInfo *fcinfo, unsigned long optio pval = (Datum) 0; if (fcinfo) - pltsql_plugin_handler_ptr->pltsql_declare_var_callback ( - token->paramMeta.pgTypeOid, /* oid */ - GetTypModForToken(token), /* typmod */ - paramName, /* name */ - (token->flags == 0) ? - PROARGMODE_IN : PROARGMODE_INOUT, /* mode */ - pval, /* datum */ - isNull, /* null */ - index, - &args, - fcinfo); + pltsql_plugin_handler_ptr->pltsql_declare_var_callback( + token->paramMeta.pgTypeOid, /* oid */ + GetTypModForToken(token), /* typmod */ + paramName, /* name */ + (token->flags == 0) ? + PROARGMODE_IN : PROARGMODE_INOUT, /* mode */ + pval, /* datum */ + isNull, /* null */ + index, + &args, + fcinfo); else { MemoryContext xactContext; MemoryContext oldContext = CurrentMemoryContext; + StartTransactionCommand(); if (get_typtype(token->paramMeta.pgTypeOid) == TYPTYPE_COMPOSITE) { TvpLookupItem *item; + xactContext = MemoryContextSwitchTo(oldContext); item = (TvpLookupItem *) palloc(sizeof(TvpLookupItem)); item->name = paramName; @@ -339,9 +343,10 @@ DeclareVariables(TDSRequestSP req, FunctionCallInfo *fcinfo, unsigned long optio static void SetVariables(TDSRequestSP req, FunctionCallInfo *fcinfo) { - InlineCodeBlockArgs *codeblock_args; - ParameterToken token = NULL; - int i = 0, index = 0; + InlineCodeBlockArgs *codeblock_args; + ParameterToken token = NULL; + int i = 0, + index = 0; /* should be only called for sp_execute */ Assert(req->spType == SP_EXECUTE); @@ -349,14 +354,14 @@ SetVariables(TDSRequestSP req, FunctionCallInfo *fcinfo) codeblock_args = (InlineCodeBlockArgs *) palloc0(sizeof(InlineCodeBlockArgs)); codeblock_args->handle = (int) req->handle; codeblock_args->options = (BATCH_OPTION_EXEC_CACHED_PLAN | - BATCH_OPTION_NO_FREE); + BATCH_OPTION_NO_FREE); /* Set variable if any. */ if (req->nTotalParams > 0) { /* - * For each token, we need to call pltsql_declare_var_block_handler API - * to declare the corresponding variable. + * For each token, we need to call pltsql_declare_var_block_handler + * API to declare the corresponding variable. */ for (token = req->dataParameter, index = 0; token != NULL; token = token->next, index++) { @@ -374,15 +379,15 @@ SetVariables(TDSRequestSP req, FunctionCallInfo *fcinfo) pval = (Datum) 0; pltsql_plugin_handler_ptr->pltsql_declare_var_callback(token->paramMeta.pgTypeOid, /* oid */ - GetTypModForToken(token), /* typmod */ - NULL, /* name */ - (token->flags == 0) ? - PROARGMODE_IN : PROARGMODE_INOUT, /* mode */ - pval, /* datum */ - isNull, /* null */ - index, - NULL, - fcinfo); + GetTypModForToken(token), /* typmod */ + NULL, /* name */ + (token->flags == 0) ? + PROARGMODE_IN : PROARGMODE_INOUT, /* mode */ + pval, /* datum */ + isNull, /* null */ + index, + NULL, + fcinfo); i++; } @@ -404,6 +409,7 @@ static int errdetail_params(int nTotalParams) { ParamListInfo params; + params = (ParamListInfo) palloc(offsetof(ParamListInfoData, params) + nTotalParams * sizeof(ParamExternData)); @@ -482,19 +488,19 @@ SPExecuteSQL(TDSRequestSP req) InlineCodeBlock *codeblock; FunctionCallInfo fcinfo; - int paramno; - Datum retval; - Datum *values; - bool *nulls; - char *activity; + int paramno; + Datum retval; + Datum *values; + bool *nulls; + char *activity; TdsErrorContext->err_text = "Processing SP_EXECUTESQL Request"; if ((req->nTotalParams) > PREPARE_STMT_MAX_ARGS) - ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " - "Too many parameters were provided in this RPC request. The maximum is %d", - PREPARE_STMT_MAX_ARGS))); + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " + "Too many parameters were provided in this RPC request. The maximum is %d", + PREPARE_STMT_MAX_ARGS))); TDSInstrumentation(INSTR_TDS_SP_EXECUTESQL); @@ -507,7 +513,7 @@ SPExecuteSQL(TDSRequestSP req) codeblock = makeNode(InlineCodeBlock); codeblock->source_text = s.data; - codeblock->langOid = 0; /* TODO does it matter */ + codeblock->langOid = 0; /* TODO does it matter */ codeblock->langIsTrusted = true; codeblock->atomic = false; @@ -526,14 +532,17 @@ SPExecuteSQL(TDSRequestSP req) PG_TRY(); { /* Now, execute the same and retrieve the composite datum */ - retval = pltsql_plugin_handler_ptr->sp_executesql_callback (fcinfo); + retval = pltsql_plugin_handler_ptr->sp_executesql_callback(fcinfo); MemoryContextSwitchTo(MessageContext); /* If pltsql_inline_handler does not end normally */ if (fcinfo->isnull) elog(ERROR, "pltsql_inline_handler failed"); - /* Read out params and nulls after checking the retrived Datum for NULL */ + /* + * Read out params and nulls after checking the retrived Datum for + * NULL + */ if (retval) pltsql_plugin_handler_ptr->pltsql_read_out_param_callback(retval, &values, &nulls); else if (req->nOutParams > 0) @@ -572,6 +581,7 @@ SPExecuteSQL(TDSRequestSP req) { ErrorContextCallback *plerrcontext = error_context_stack; + error_context_stack = plerrcontext->previous; ereport(LOG, @@ -596,10 +606,10 @@ SPPrepare(TDSRequestSP req) StringInfoData s; FunctionCallInfo fcinfo; - Datum retval; - Datum *values; - bool *nulls; - char *activity; + Datum retval; + Datum *values; + bool *nulls; + char *activity; TdsErrorContext->err_text = "Processing SP_PREPARE Request"; TDSInstrumentation(INSTR_TDS_SP_PREPARE); @@ -607,10 +617,10 @@ SPPrepare(TDSRequestSP req) tvp_lookup_list = NIL; if (req->nTotalParams > 1) - ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " - "Too many parameters were provided in this RPC request"))); + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " + "Too many parameters were provided in this RPC request"))); initStringInfo(&s); FillQueryFromParameterToken(req, &s); @@ -639,14 +649,17 @@ SPPrepare(TDSRequestSP req) PG_TRY(); { /* Now, call the prepare handler and retrieve the handle */ - retval = pltsql_plugin_handler_ptr->sp_prepare_callback (fcinfo); + retval = pltsql_plugin_handler_ptr->sp_prepare_callback(fcinfo); MemoryContextSwitchTo(MessageContext); /* If sp_prepare_handler does not end normally */ if (fcinfo->isnull) elog(ERROR, "sp_prepare_handler failed"); - /* Read out params and nulls after checking the retrived Datum for NULL */ + /* + * Read out params and nulls after checking the retrived Datum for + * NULL + */ if (retval) pltsql_plugin_handler_ptr->pltsql_read_out_param_callback(retval, &values, &nulls); else if (req->nOutParams > 0) @@ -681,12 +694,13 @@ SPExecute(TDSRequestSP req) InlineCodeBlock *codeblock; FunctionCallInfo fcinfo; - int paramno; - Datum retval; - Datum *values; - bool *nulls; + int paramno; + Datum retval; + Datum *values; + bool *nulls; + + char *activity = psprintf("SP_EXECUTE Handle: %d", req->handle); - char *activity = psprintf("SP_EXECUTE Handle: %d", req->handle); TdsErrorContext->err_text = "Processing SP_EXECUTE Request"; pgstat_report_activity(STATE_RUNNING, activity); pfree(activity); @@ -695,15 +709,15 @@ SPExecute(TDSRequestSP req) tvp_lookup_list = NIL; if ((req->nTotalParams) > PREPARE_STMT_MAX_ARGS) - ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " - "Too many parameters were provided in this RPC request. The maximum is %d", - PREPARE_STMT_MAX_ARGS))); + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " + "Too many parameters were provided in this RPC request. The maximum is %d", + PREPARE_STMT_MAX_ARGS))); codeblock = makeNode(InlineCodeBlock); codeblock->source_text = NULL; - codeblock->langOid = 0; /* TODO does it matter */ + codeblock->langOid = 0; /* TODO does it matter */ codeblock->langIsTrusted = true; codeblock->atomic = false; @@ -720,7 +734,7 @@ SPExecute(TDSRequestSP req) PG_TRY(); { /* Now, call the execute handler and retrieve the composite datum. */ - retval = pltsql_plugin_handler_ptr->sp_execute_callback (fcinfo); + retval = pltsql_plugin_handler_ptr->sp_execute_callback(fcinfo); MemoryContextSwitchTo(MessageContext); /* If sp_execute_handler does not end normally. */ @@ -766,6 +780,7 @@ SPExecute(TDSRequestSP req) if (pltsql_plugin_handler_ptr->stmt_needs_logging || TDS_DEBUG_ENABLED(TDS_DEBUG2)) { ErrorContextCallback *plerrcontext = error_context_stack; + error_context_stack = plerrcontext->previous; ereport(LOG, @@ -790,24 +805,24 @@ SPPrepExec(TDSRequestSP req) { StringInfoData s; InlineCodeBlock *codeblock; - InlineCodeBlockArgs* codeblock_args; + InlineCodeBlockArgs *codeblock_args; FunctionCallInfo fcinfo; - int paramno; - Datum retval; - Datum *values; - bool *nulls; - char *activity; + int paramno; + Datum retval; + Datum *values; + bool *nulls; + char *activity; tvp_lookup_list = NIL; TdsErrorContext->err_text = "Processing SP_PREPEXEC Request"; if ((req->nTotalParams) > PREPARE_STMT_MAX_ARGS) - ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " - "Too many parameters were provided in this RPC request. The maximum is %d", - PREPARE_STMT_MAX_ARGS))); + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " + "Too many parameters were provided in this RPC request. The maximum is %d", + PREPARE_STMT_MAX_ARGS))); TDSInstrumentation(INSTR_TDS_SP_PREPEXEC); @@ -820,7 +835,7 @@ SPPrepExec(TDSRequestSP req) codeblock = makeNode(InlineCodeBlock); codeblock->source_text = s.data; - codeblock->langOid = 0; /* TODO does it matter */ + codeblock->langOid = 0; /* TODO does it matter */ codeblock->langIsTrusted = true; codeblock->atomic = false; @@ -831,21 +846,24 @@ SPPrepExec(TDSRequestSP req) fcinfo->args[0].isnull = false; codeblock_args = DeclareVariables(req, &fcinfo, - (BATCH_OPTION_CACHE_PLAN | BATCH_OPTION_NO_FREE)); + (BATCH_OPTION_CACHE_PLAN | BATCH_OPTION_NO_FREE)); TDSStatementBeginCallback(NULL, NULL); PG_TRY(); { /* Now, call the execute handler and retrieve the composite datum. */ - retval = pltsql_plugin_handler_ptr->sp_prepexec_callback (fcinfo); + retval = pltsql_plugin_handler_ptr->sp_prepexec_callback(fcinfo); MemoryContextSwitchTo(MessageContext); /* If sp_prepexec_handler does not end normally. */ if (fcinfo->isnull) elog(ERROR, "sp_prepexec_handler failed"); - /* Read out params and nulls after checking the retrived Datum for NULL */ + /* + * Read out params and nulls after checking the retrived Datum for + * NULL + */ if (retval) pltsql_plugin_handler_ptr->pltsql_read_out_param_callback(retval, &values, &nulls); else if (req->nOutParams > 0) @@ -856,7 +874,7 @@ SPPrepExec(TDSRequestSP req) if (TDS_DEBUG_ENABLED(TDS_DEBUG2)) ereport(LOG, (errmsg("sp_prepexec handle: %d, " - "statement: %s", req->handle, s.data), + "statement: %s", req->handle, s.data), errhidestmt(true), errdetail_params(req->nTotalParams))); @@ -916,20 +934,20 @@ SPPrepExec(TDSRequestSP req) static ParameterToken DeclareSPVariables(TDSRequestSP req, FunctionCallInfo *fcinfo) { - InlineCodeBlockArgs *args = NULL; - ParameterToken token = NULL; - int index = 0; - ParameterToken returnToken; - Oid atttypid; - Oid atttypmod; - int attcollation; + InlineCodeBlockArgs *args = NULL; + ParameterToken token = NULL; + int index = 0; + ParameterToken returnToken; + Oid atttypid; + Oid atttypmod; + int attcollation; /* * The return type is not sent by the client. So, we first look up the * function/procedure name from the catalog using a builtin system - * function. Then, we check the type of the function. If it's a procedure - * the return type will be always an integer in case of babel, and if - * it's a UDF, we just fetch the return type from catalog. + * function. Then, we check the type of the function. If it's a + * procedure the return type will be always an integer in case of babel, + * and if it's a UDF, we just fetch the return type from catalog. */ pltsql_plugin_handler_ptr->pltsql_read_procedure_info( &req->name, @@ -946,32 +964,32 @@ DeclareSPVariables(TDSRequestSP req, FunctionCallInfo *fcinfo) (*fcinfo)->nargs++; /* - * Once we know the return type, we've to prepare a parameter token, so that - * we can send the return value of as OUT parameter if required. + * Once we know the return type, we've to prepare a parameter token, so + * that we can send the return value of as OUT parameter if required. */ returnToken = MakeEmptyParameterToken("", atttypid, atttypmod, attcollation); returnToken->paramOrdinal = 0; - pltsql_plugin_handler_ptr->pltsql_declare_var_callback ( - returnToken->paramMeta.pgTypeOid, /* oid */ - GetTypModForToken(returnToken), /* typmod */ - "@p0", /* name */ - PROARGMODE_INOUT, /* mode */ - (Datum) 0, /* datum */ - true, /* null */ - index, - &args, - fcinfo); + pltsql_plugin_handler_ptr->pltsql_declare_var_callback( + returnToken->paramMeta.pgTypeOid, /* oid */ + GetTypModForToken(returnToken), /* typmod */ + "@p0", /* name */ + PROARGMODE_INOUT, /* mode */ + (Datum) 0, /* datum */ + true, /* null */ + index, + &args, + fcinfo); index++; /* - * For each token, we need to call pltsql_declare_var_block_handler API - * to declare the corresponding variable. + * For each token, we need to call pltsql_declare_var_block_handler API to + * declare the corresponding variable. */ for (token = req->dataParameter; token != NULL; token = token->next, index++) { - char *paramName; - StringInfo name; + char *paramName; + StringInfo name; Datum pval; bool isNull; TdsIoFunctionInfo tempFuncInfo; @@ -980,7 +998,7 @@ DeclareSPVariables(TDSRequestSP req, FunctionCallInfo *fcinfo) if (name->len == 0) { - char buf[10]; + char buf[10]; snprintf(buf, sizeof(buf), "@p%d", index); paramName = pnstrdup(buf, strlen(buf));; @@ -997,17 +1015,17 @@ DeclareSPVariables(TDSRequestSP req, FunctionCallInfo *fcinfo) else pval = (Datum) 0; - pltsql_plugin_handler_ptr->pltsql_declare_var_callback ( - token->paramMeta.pgTypeOid, /* oid */ - GetTypModForToken(token), /* typmod */ - paramName, /* name */ - (token->flags == 0) ? - PROARGMODE_IN : PROARGMODE_INOUT, /* mode */ - pval, /* datum */ - isNull, /* null */ - index, - &args, - fcinfo); + pltsql_plugin_handler_ptr->pltsql_declare_var_callback( + token->paramMeta.pgTypeOid, /* oid */ + GetTypModForToken(token), /* typmod */ + paramName, /* name */ + (token->flags == 0) ? + PROARGMODE_IN : PROARGMODE_INOUT, /* mode */ + pval, /* datum */ + isNull, /* null */ + index, + &args, + fcinfo); } return returnToken; @@ -1021,20 +1039,20 @@ SPCustomType(TDSRequestSP req) FunctionCallInfo fcinfo; ParameterToken returnParamToken = NULL; - int paramno; - Datum retval; - Datum *values; - bool *nulls; - char *activity; + int paramno; + Datum retval; + Datum *values; + bool *nulls; + char *activity; tvp_lookup_list = NIL; TdsErrorContext->err_text = "Processing SP_CUSTOMTYPE Request"; if ((req->nTotalParams) > PREPARE_STMT_MAX_ARGS) - ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " - "Too many parameters were provided in this RPC request. The maximum is %d", - PREPARE_STMT_MAX_ARGS))); + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " + "Too many parameters were provided in this RPC request. The maximum is %d", + PREPARE_STMT_MAX_ARGS))); TDSInstrumentation(INSTR_TDS_USER_CUSTOM_SP); @@ -1047,7 +1065,7 @@ SPCustomType(TDSRequestSP req) codeblock = makeNode(InlineCodeBlock); codeblock->source_text = s.data; - codeblock->langOid = 0; /* TODO does it matter */ + codeblock->langOid = 0; /* TODO does it matter */ codeblock->langIsTrusted = true; codeblock->atomic = false; @@ -1063,14 +1081,17 @@ SPCustomType(TDSRequestSP req) returnParamToken = DeclareSPVariables(req, &fcinfo); /* Now, execute the same and retrieve the composite datum */ - retval = pltsql_plugin_handler_ptr->sp_executesql_callback (fcinfo); + retval = pltsql_plugin_handler_ptr->sp_executesql_callback(fcinfo); MemoryContextSwitchTo(MessageContext); /* If pltsql_inline_handler does not end normally */ if (fcinfo->isnull) elog(ERROR, "pltsql_inline_handler failed"); - /* Read out params and nulls after checking the retrived Datum for NULL */ + /* + * Read out params and nulls after checking the retrived Datum for + * NULL + */ if (retval) pltsql_plugin_handler_ptr->pltsql_read_out_param_callback(retval, &values, &nulls); else if (req->nOutParams > 0) @@ -1121,6 +1142,7 @@ SPCustomType(TDSRequestSP req) if (pltsql_plugin_handler_ptr->stmt_needs_logging || TDS_DEBUG_ENABLED(TDS_DEBUG2)) { ErrorContextCallback *plerrcontext = error_context_stack; + error_context_stack = plerrcontext->previous; ereport(LOG, (errmsg("stored procedure: %s", req->name.data), @@ -1144,7 +1166,8 @@ SPUnprepare(TDSRequestSP req) /* SP_UNPREPARE takes only one argument. */ LOCAL_FCINFO(fcinfo, 1); - char *activity = psprintf("SP_UNPREPARE Handle: %d", req->handle); + char *activity = psprintf("SP_UNPREPARE Handle: %d", req->handle); + TdsErrorContext->err_text = "Processing SP_UNPREPARE Request"; pgstat_report_activity(STATE_RUNNING, activity); pfree(activity); @@ -1162,7 +1185,7 @@ SPUnprepare(TDSRequestSP req) PG_TRY(); { /* Now, execute the unprepare handler and retrieve the composite datum */ - pltsql_plugin_handler_ptr->sp_unprepare_callback (fcinfo); + pltsql_plugin_handler_ptr->sp_unprepare_callback(fcinfo); MemoryContextSwitchTo(MessageContext); /* If sp_unprepare_handler does not end normally. */ @@ -1188,18 +1211,18 @@ SPUnprepare(TDSRequestSP req) static int GetSetColMetadataForCharType(ParameterToken temp, StringInfo message, uint8_t tdsType, - uint64_t *mainOffset) + uint64_t *mainOffset) { - uint32_t collation; - uint8_t sortId; - uint64_t offset = *mainOffset; - uint16_t tempLen; - pg_enc enc; + uint32_t collation; + uint8_t sortId; + uint64_t offset = *mainOffset; + uint16_t tempLen; + pg_enc enc; if ((offset + sizeof(tempLen) + - sizeof(collation) + - sizeof(sortId)) > + sizeof(collation) + + sizeof(sortId)) > message->len) return STATUS_ERROR; @@ -1211,7 +1234,10 @@ GetSetColMetadataForCharType(ParameterToken temp, StringInfo message, uint8_t td sortId = message->data[offset]; offset += sizeof(sortId); - /* If we recieve 0 value for LCID then we should treat it as a default LCID.*/ + /* + * If we recieve 0 value for LCID then we should treat it as a default + * LCID. + */ enc = TdsGetEncoding(collation); /* @@ -1219,13 +1245,13 @@ GetSetColMetadataForCharType(ParameterToken temp, StringInfo message, uint8_t td */ if (enc == -1) ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Babelfish does not support %d Locale with %d collate flags and %d SortId", collation & 0xFFFFF, (collation & 0xFFF00000) >> 20, sortId))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Babelfish does not support %d Locale with %d collate flags and %d SortId", collation & 0xFFFFF, (collation & 0xFFF00000) >> 20, sortId))); SetColMetadataForCharType(&temp->paramMeta, tdsType, - collation & 0xFFFFF, enc, - (collation & 0xFFF00000) >> 20, - sortId, tempLen); + collation & 0xFFFFF, enc, + (collation & 0xFFF00000) >> 20, + sortId, tempLen); *mainOffset = offset; return STATUS_OK; @@ -1233,17 +1259,17 @@ GetSetColMetadataForCharType(ParameterToken temp, StringInfo message, uint8_t td static int GetSetColMetadataForTextType(ParameterToken temp, StringInfo message, uint8_t tdsType, - uint64_t *mainOffset) + uint64_t *mainOffset) { - uint32_t collation; - uint8_t sortId; - uint64_t offset = *mainOffset; - pg_enc enc; + uint32_t collation; + uint8_t sortId; + uint64_t offset = *mainOffset; + pg_enc enc; if ((offset + sizeof(temp->maxLen) + - sizeof(collation) + - sizeof(sortId)) > message->len) + sizeof(collation) + + sizeof(sortId)) > message->len) return STATUS_ERROR; memcpy(&temp->maxLen, &message->data[offset], sizeof(temp->maxLen)); @@ -1253,7 +1279,10 @@ GetSetColMetadataForTextType(ParameterToken temp, StringInfo message, uint8_t td sortId = message->data[offset]; offset += sizeof(sortId); - /* If we recieve 0 value for LCID then we should treat it as a default LCID.*/ + /* + * If we recieve 0 value for LCID then we should treat it as a default + * LCID. + */ enc = TdsGetEncoding(collation); /* @@ -1261,13 +1290,13 @@ GetSetColMetadataForTextType(ParameterToken temp, StringInfo message, uint8_t td */ if (enc == -1) ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Babelfish does not support %d Locale with %d collate flags and %d SortId", collation & 0xFFFFF, (collation & 0xFFF00000) >> 20, sortId))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Babelfish does not support %d Locale with %d collate flags and %d SortId", collation & 0xFFFFF, (collation & 0xFFF00000) >> 20, sortId))); SetColMetadataForTextType(&temp->paramMeta, tdsType, - collation & 0xFFFFF, enc, - (collation & 0xFFF00000) >> 20, - sortId, temp->maxLen); + collation & 0xFFFFF, enc, + (collation & 0xFFF00000) >> 20, + sortId, temp->maxLen); *mainOffset = offset; return STATUS_OK; @@ -1277,12 +1306,13 @@ int ReadPlp(ParameterToken temp, StringInfo message, uint64_t *mainOffset) { - uint64_t plpTok; - Plp plpTemp, plpPrev = NULL; + uint64_t plpTok; + Plp plpTemp, + plpPrev = NULL; unsigned long lenCheck = 0; - uint64_t offset = *mainOffset; + uint64_t offset = *mainOffset; - memcpy(&plpTok , &message->data[offset], sizeof(plpTok)); + memcpy(&plpTok, &message->data[offset], sizeof(plpTok)); offset += sizeof(plpTok); temp->plp = NULL; @@ -1296,11 +1326,11 @@ ReadPlp(ParameterToken temp, StringInfo message, uint64_t *mainOffset) while (true) { - uint32_t tempLen; + uint32_t tempLen; if (offset + sizeof(tempLen) > message->len) return STATUS_ERROR; - memcpy(&tempLen , &message->data[offset], sizeof(tempLen)); + memcpy(&tempLen, &message->data[offset], sizeof(tempLen)); offset += sizeof(tempLen); /* PLP Terminator */ @@ -1344,7 +1374,7 @@ InitialiseParameterToken(TDSRequestSP request) /* Initialize */ request->handleParameter = NULL; request->cursorHandleParameter = NULL; - request->cursorPreparedHandleParameter = NULL; + request->cursorPreparedHandleParameter = NULL; request->queryParameter = NULL; request->cursorExtraArg1 = NULL; request->cursorExtraArg2 = NULL; @@ -1355,28 +1385,32 @@ InitialiseParameterToken(TDSRequestSP request) static int ReadParameters(TDSRequestSP request, uint64_t offset, StringInfo message, int *parameterCount) { - ParameterToken temp, prev = NULL; - int len = 0; + ParameterToken temp, + prev = NULL; + int len = 0; TdsIoFunctionInfo tempFuncInfo; - uint16 paramOrdinal = 0; - int retStatus; + uint16 paramOrdinal = 0; + int retStatus; - while(offset < message->len) + while (offset < message->len) { - uint8_t tdsType; + uint8_t tdsType; /* - * If next byte after a parameter is a BatchFlag - * we store the following parameters for the next RPC packet in the Batch. - * BatchFlag is '0xFF' For TDS versions more than or equal to 7.2 - * and '0x80' for Versions lower than or equal to TDS 7.1 + * If next byte after a parameter is a BatchFlag we store the + * following parameters for the next RPC packet in the Batch. + * BatchFlag is '0xFF' For TDS versions more than or equal to 7.2 and + * '0x80' for Versions lower than or equal to TDS 7.1 */ - if((uint8_t) message->data[offset] == GetRpcBatchSeparator(GetClientTDSVersion())) + if ((uint8_t) message->data[offset] == GetRpcBatchSeparator(GetClientTDSVersion())) { /* Increment offset by 1 to ignore the batch-separator. */ request->batchSeparatorOffset = offset + 1; - /* Need to save the lenght of the message, since only messageData field is set for TdsRequestCtrl. */ + /* + * Need to save the lenght of the message, since only messageData + * field is set for TdsRequestCtrl. + */ request->messageLen = message->len; return STATUS_OK; } @@ -1385,8 +1419,8 @@ ReadParameters(TDSRequestSP request, uint64_t offset, StringInfo message, int *p len = message->data[offset++]; /* - * Call initStringInfo for every parameter name even if len is 0 - * so that the processing logic can check the length field from + * Call initStringInfo for every parameter name even if len is 0 so + * that the processing logic can check the length field from * temp->name->len */ initStringInfo(&(temp->paramMeta.colName)); @@ -1394,7 +1428,8 @@ ReadParameters(TDSRequestSP request, uint64_t offset, StringInfo message, int *p if (len > 0) { /* - * FIXME: parameter name is in UTF-16 format. Fix this separately. + * FIXME: parameter name is in UTF-16 format. Fix this + * separately. */ TdsUTF16toUTF8StringInfo(&(temp->paramMeta.colName), &(message->data[offset]), 2 * len); offset += 2 * len; @@ -1405,20 +1440,22 @@ ReadParameters(TDSRequestSP request, uint64_t offset, StringInfo message, int *p offset += sizeof(temp->flags); #ifdef FAULT_INJECTOR - /* - * We need to have a lock since we are injecting pre-parsing - * fault while parsing ReadParameters. - */ - if (!lockForFaultInjection) - { - TdsMessageWrapper wrapper; - lockForFaultInjection = true; - wrapper.message = message; - wrapper.messageType = TDS_RPC; - wrapper.offset = offset; - FAULT_INJECT(ParseRpcType, &wrapper); - lockForFaultInjection = false; - } + + /* + * We need to have a lock since we are injecting pre-parsing fault + * while parsing ReadParameters. + */ + if (!lockForFaultInjection) + { + TdsMessageWrapper wrapper; + + lockForFaultInjection = true; + wrapper.message = message; + wrapper.messageType = TDS_RPC; + wrapper.offset = offset; + FAULT_INJECT(ParseRpcType, &wrapper); + lockForFaultInjection = false; + } #endif tdsType = message->data[offset++]; @@ -1430,329 +1467,340 @@ ReadParameters(TDSRequestSP request, uint64_t offset, StringInfo message, int *p { case TDS_TYPE_TEXT: case TDS_TYPE_NTEXT: - { - /* Type TEXT and NTEXT are deprecated large objects */ - if(temp->flags & SP_FLAGS_BYREFVALUE) - ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("Invalid parameter %d (\"%s\"): Data type 0x%02X is a deprecated large object, or LOB, but is marked as output parameter. " - "Deprecated types are not supported as output parameters. Use current large object types instead.", - paramOrdinal, temp->paramMeta.colName.data, tdsType))); - retStatus = GetSetColMetadataForTextType(temp, message, tdsType, &offset); - if (retStatus != STATUS_OK) - return retStatus; + { + /* Type TEXT and NTEXT are deprecated large objects */ + if (temp->flags & SP_FLAGS_BYREFVALUE) + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("Invalid parameter %d (\"%s\"): Data type 0x%02X is a deprecated large object, or LOB, but is marked as output parameter. " + "Deprecated types are not supported as output parameters. Use current large object types instead.", + paramOrdinal, temp->paramMeta.colName.data, tdsType))); + retStatus = GetSetColMetadataForTextType(temp, message, tdsType, &offset); + if (retStatus != STATUS_OK) + return retStatus; - memcpy(&temp->len, &message->data[offset], sizeof(temp->len)); + memcpy(&temp->len, &message->data[offset], sizeof(temp->len)); - /* for Null values, Len field is set to -1(0xFFFFFFFF) */ - if (temp->len == 0xFFFFFFFF) - { - temp->len = 0; - temp->isNull = true; - } + /* for Null values, Len field is set to -1(0xFFFFFFFF) */ + if (temp->len == 0xFFFFFFFF) + { + temp->len = 0; + temp->isNull = true; + } - CheckForInvalidLength(temp); + CheckForInvalidLength(temp); - offset += sizeof(temp->len); - temp->dataOffset = offset; - offset += temp->len; - } - break; + offset += sizeof(temp->len); + temp->dataOffset = offset; + offset += temp->len; + } + break; case TDS_TYPE_IMAGE: case TDS_TYPE_SQLVARIANT: - { - /* Type IMAGE is a deprecated large object*/ - if((temp->flags & SP_FLAGS_BYREFVALUE) && tdsType == TDS_TYPE_IMAGE) - ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("Invalid parameter %d (\"%s\"): Data type 0x%02X is a deprecated large object, or LOB, but is marked as output parameter. " - "Deprecated types are not supported as output parameters. Use current large object types instead.", - paramOrdinal, temp->paramMeta.colName.data, tdsType))); - SetColMetadataForImageType(&temp->paramMeta, tdsType); - - memcpy(&temp->len, &message->data[offset], sizeof(temp->len)); - - /* for Null values, Len field is set to -1(0xFFFFFFFF) or 0 */ - if (temp->len == 0xFFFFFFFF || - (tdsType == TDS_TYPE_SQLVARIANT && temp->len == 0)) { - temp->len = 0; - temp->isNull = true; - } - - if (tdsType == TDS_TYPE_SQLVARIANT && temp->len > temp->paramMeta.metaEntry.type8.maxSize) - ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " - "Parameter %d (\"%s\"): Data type 0x%02X (sql_variant) has an invalid length for type-specific metadata.", - paramOrdinal, temp->paramMeta.colName.data, tdsType))); + /* Type IMAGE is a deprecated large object */ + if ((temp->flags & SP_FLAGS_BYREFVALUE) && tdsType == TDS_TYPE_IMAGE) + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("Invalid parameter %d (\"%s\"): Data type 0x%02X is a deprecated large object, or LOB, but is marked as output parameter. " + "Deprecated types are not supported as output parameters. Use current large object types instead.", + paramOrdinal, temp->paramMeta.colName.data, tdsType))); + SetColMetadataForImageType(&temp->paramMeta, tdsType); - /* - * Skipping two sequence of 4 Bytes, each sequence containing - * actual image file length - */ - offset += 2 * sizeof(temp->len); - - temp->dataOffset = offset; - offset += temp->len; - } - break; - case TDS_TYPE_CHAR: - case TDS_TYPE_NCHAR: - case TDS_TYPE_VARCHAR: - case TDS_TYPE_NVARCHAR: - { - retStatus = GetSetColMetadataForCharType(temp, message, tdsType, &offset); - if (retStatus != STATUS_OK) - return retStatus; + memcpy(&temp->len, &message->data[offset], sizeof(temp->len)); - /* - * If varchar/Nvchar is created with max keyword, then - * data will come in PLP chuncks - */ - if (temp->maxLen == 0xFFFF) - { - retStatus = ReadPlp(temp, message, &offset); - CheckPLPStatusNotOK(temp, retStatus); - } - else - { /* - * Nvarchar datatype have length field of 2 byte + * for Null values, Len field is set to -1(0xFFFFFFFF) or + * 0 */ - uint16_t tempLen; + if (temp->len == 0xFFFFFFFF || + (tdsType == TDS_TYPE_SQLVARIANT && temp->len == 0)) + { + temp->len = 0; + temp->isNull = true; + } - if (offset + sizeof(tempLen) > message->len) + if (tdsType == TDS_TYPE_SQLVARIANT && temp->len > temp->paramMeta.metaEntry.type8.maxSize) ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " - "Parameter %d (\"%s\"): The supplied length is not valid for data type CHAR/NCHAR/VARCHAR/NVARCHAR. " - "Check the source data for invalid lengths. An example of an invalid length is data of nchar type with an odd length in bytes.", - paramOrdinal, temp->paramMeta.colName.data))); + "Parameter %d (\"%s\"): Data type 0x%02X (sql_variant) has an invalid length for type-specific metadata.", + paramOrdinal, temp->paramMeta.colName.data, tdsType))); + + /* + * Skipping two sequence of 4 Bytes, each sequence + * containing actual image file length + */ + offset += 2 * sizeof(temp->len); - memcpy(&tempLen , &message->data[offset], sizeof(tempLen)); - temp->len = tempLen; - offset += sizeof(tempLen); temp->dataOffset = offset; + offset += temp->len; + } + break; + case TDS_TYPE_CHAR: + case TDS_TYPE_NCHAR: + case TDS_TYPE_VARCHAR: + case TDS_TYPE_NVARCHAR: + { + retStatus = GetSetColMetadataForCharType(temp, message, tdsType, &offset); + if (retStatus != STATUS_OK) + return retStatus; /* - * For Null values, Len field is set to 65535(0xffff) + * If varchar/Nvchar is created with max keyword, then + * data will come in PLP chuncks */ - if (temp->len == 0xffff) + if (temp->maxLen == 0xFFFF) { - temp->len = 0; - temp->isNull = true; + retStatus = ReadPlp(temp, message, &offset); + CheckPLPStatusNotOK(temp, retStatus); } + else + { + /* + * Nvarchar datatype have length field of 2 byte + */ + uint16_t tempLen; - if (offset + temp->len > message->len) - ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " - "Parameter %d (\"%s\"): Data type 0x%02X has an invalid data length or metadata length.", - paramOrdinal, temp->paramMeta.colName.data, tdsType))); + if (offset + sizeof(tempLen) > message->len) + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " + "Parameter %d (\"%s\"): The supplied length is not valid for data type CHAR/NCHAR/VARCHAR/NVARCHAR. " + "Check the source data for invalid lengths. An example of an invalid length is data of nchar type with an odd length in bytes.", + paramOrdinal, temp->paramMeta.colName.data))); + + memcpy(&tempLen, &message->data[offset], sizeof(tempLen)); + temp->len = tempLen; + offset += sizeof(tempLen); + temp->dataOffset = offset; + + /* + * For Null values, Len field is set to 65535(0xffff) + */ + if (temp->len == 0xffff) + { + temp->len = 0; + temp->isNull = true; + } - offset += temp->len; + if (offset + temp->len > message->len) + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " + "Parameter %d (\"%s\"): Data type 0x%02X has an invalid data length or metadata length.", + paramOrdinal, temp->paramMeta.colName.data, tdsType))); + + offset += temp->len; + } } - } - break; + break; case TDS_TYPE_BIT: case TDS_TYPE_INTEGER: case TDS_TYPE_FLOAT: case TDS_TYPE_MONEYN: case TDS_TYPE_DATETIMEN: case TDS_TYPE_UNIQUEIDENTIFIER: - { - if ((offset + 2) > message->len) - return STATUS_ERROR; - temp->maxLen = message->data[offset++]; - /* - * Fixed-length datatypes have length field of 1 byte - */ - temp->len = message->data[offset++]; + { + if ((offset + 2) > message->len) + return STATUS_ERROR; + temp->maxLen = message->data[offset++]; - if (temp->len == 0) - temp->isNull = true; + /* + * Fixed-length datatypes have length field of 1 byte + */ + temp->len = message->data[offset++]; - CheckForInvalidLength(temp); + if (temp->len == 0) + temp->isNull = true; - temp->dataOffset = offset; - if (offset + temp->len > message->len) - return STATUS_ERROR; - offset += temp->len; + CheckForInvalidLength(temp); - SetColMetadataForFixedType(&temp->paramMeta, tdsType, temp->maxLen); - } - break; + temp->dataOffset = offset; + if (offset + temp->len > message->len) + return STATUS_ERROR; + offset += temp->len; + + SetColMetadataForFixedType(&temp->paramMeta, tdsType, temp->maxLen); + } + break; case TDS_TYPE_TABLE: - { - temp->tvpInfo = palloc0(sizeof(TvpData)); + { + temp->tvpInfo = palloc0(sizeof(TvpData)); - /* Sets the col metadata and also the corresponding row data. */ - SetColMetadataForTvp(temp, message, &offset); - } - break; + /* + * Sets the col metadata and also the corresponding row + * data. + */ + SetColMetadataForTvp(temp, message, &offset); + } + break; case TDS_TYPE_BINARY: case TDS_TYPE_VARBINARY: - { - uint16 len; - - memcpy(&len, &message->data[offset], sizeof(len)); - offset += sizeof(len); - temp->maxLen = len; - - - SetColMetadataForBinaryType(&temp->paramMeta, tdsType, temp->maxLen); - - /* - * If varbinary is created with max keyword, - * data will come in PLP chuncks - */ - if (temp->maxLen == 0xffff) - { - retStatus = ReadPlp(temp, message, &offset); - CheckPLPStatusNotOK(temp, retStatus); - } - else { + uint16 len; + memcpy(&len, &message->data[offset], sizeof(len)); offset += sizeof(len); - temp->len = len; + temp->maxLen = len; + + + SetColMetadataForBinaryType(&temp->paramMeta, tdsType, temp->maxLen); + /* - * Binary, varbinary datatypes have length field of 2 bytes - * For NULL value, Len field is set to 65535(0xffff) - */ - if (temp->len == 0xffff) + * If varbinary is created with max keyword, data will + * come in PLP chuncks + */ + if (temp->maxLen == 0xffff) { - temp->len = 0; - temp->isNull = true; + retStatus = ReadPlp(temp, message, &offset); + CheckPLPStatusNotOK(temp, retStatus); } + else + { + memcpy(&len, &message->data[offset], sizeof(len)); + offset += sizeof(len); + temp->len = len; + + /* + * Binary, varbinary datatypes have length field of 2 + * bytes For NULL value, Len field is set to + * 65535(0xffff) + */ + if (temp->len == 0xffff) + { + temp->len = 0; + temp->isNull = true; + } - CheckForInvalidLength(temp); + CheckForInvalidLength(temp); - temp->dataOffset = offset; - if (offset + temp->len > message->len) - return STATUS_ERROR; - offset += temp->len; + temp->dataOffset = offset; + if (offset + temp->len > message->len) + return STATUS_ERROR; + offset += temp->len; + } } - } - break; + break; case TDS_TYPE_DATE: - { - if ((offset + 1) > message->len) - return STATUS_ERROR; + { + if ((offset + 1) > message->len) + return STATUS_ERROR; - temp->len = message->data[offset++]; - temp->maxLen = 3; + temp->len = message->data[offset++]; + temp->maxLen = 3; - if (temp->len == 0) - temp->isNull = true; + if (temp->len == 0) + temp->isNull = true; - CheckForInvalidLength(temp); + CheckForInvalidLength(temp); - temp->dataOffset = offset; - if (offset + temp->len > message->len) - return STATUS_ERROR; - offset += temp->len; + temp->dataOffset = offset; + if (offset + temp->len > message->len) + return STATUS_ERROR; + offset += temp->len; - SetColMetadataForDateType(&temp->paramMeta, tdsType); - } - break; + SetColMetadataForDateType(&temp->paramMeta, tdsType); + } + break; case TDS_TYPE_TIME: case TDS_TYPE_DATETIME2: case TDS_TYPE_DATETIMEOFFSET: - { - uint8_t scale = message->data[offset++]; - temp->len = message->data[offset++]; + { + uint8_t scale = message->data[offset++]; - if (temp->len == 0) - temp->isNull = true; + temp->len = message->data[offset++]; - if (tdsType == TDS_TYPE_TIME) - temp->maxLen = 5; - else if (tdsType == TDS_TYPE_DATETIME2) - temp->maxLen = 8; - else if (tdsType == TDS_TYPE_DATETIMEOFFSET) - temp->maxLen = 10; + if (temp->len == 0) + temp->isNull = true; - CheckForInvalidLength(temp); + if (tdsType == TDS_TYPE_TIME) + temp->maxLen = 5; + else if (tdsType == TDS_TYPE_DATETIME2) + temp->maxLen = 8; + else if (tdsType == TDS_TYPE_DATETIMEOFFSET) + temp->maxLen = 10; - temp->dataOffset = offset; - if ((offset + temp->len) > message->len) - return STATUS_ERROR; - offset += temp->len; + CheckForInvalidLength(temp); - SetColMetadataForTimeType(&temp->paramMeta, tdsType, scale); - } - break; + temp->dataOffset = offset; + if ((offset + temp->len) > message->len) + return STATUS_ERROR; + offset += temp->len; + + SetColMetadataForTimeType(&temp->paramMeta, tdsType, scale); + } + break; case TDS_TYPE_DECIMALN: case TDS_TYPE_NUMERICN: - { - uint8_t scale; - uint8_t precision; + { + uint8_t scale; + uint8_t precision; - temp->maxLen = message->data[offset++]; + temp->maxLen = message->data[offset++]; - precision = message->data[offset++]; - scale = message->data[offset++]; + precision = message->data[offset++]; + scale = message->data[offset++]; - if (scale > precision) - ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " + if (scale > precision) + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " "Parameter %d (\"%s\"): The supplied value is not a valid instance of data type Numeric/Decimal. Check the source data for invalid values. " "An example of an invalid value is data of numeric type with scale greater than precision", - paramOrdinal, temp->paramMeta.colName.data))); + paramOrdinal, temp->paramMeta.colName.data))); - temp->len = message->data[offset++]; - if (temp->len > TDS_MAXLEN_NUMERIC) - ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " - "Parameter %d (\"%s\"): Data type 0x%02X has an invalid data length or metadata length.", - paramOrdinal, temp->paramMeta.colName.data, tdsType))); + temp->len = message->data[offset++]; + if (temp->len > TDS_MAXLEN_NUMERIC) + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " + "Parameter %d (\"%s\"): Data type 0x%02X has an invalid data length or metadata length.", + paramOrdinal, temp->paramMeta.colName.data, tdsType))); - if (temp->len == 0) - temp->isNull = true; + if (temp->len == 0) + temp->isNull = true; - CheckForInvalidLength(temp); + CheckForInvalidLength(temp); - temp->dataOffset = offset; + temp->dataOffset = offset; - if ((offset + temp->len) > message->len) - return STATUS_ERROR; + if ((offset + temp->len) > message->len) + return STATUS_ERROR; - /* - * XXX: We do not support DECIMAL so internally we store - * DECIMAL as NUMERIC. - */ - temp->type = TDS_TYPE_NUMERICN; - tdsType = TDS_TYPE_NUMERICN; + /* + * XXX: We do not support DECIMAL so internally we store + * DECIMAL as NUMERIC. + */ + temp->type = TDS_TYPE_NUMERICN; + tdsType = TDS_TYPE_NUMERICN; - SetColMetadataForNumericType(&temp->paramMeta, TDS_TYPE_NUMERICN, temp->maxLen, - precision, scale); - offset += temp->len; - } - break; + SetColMetadataForNumericType(&temp->paramMeta, TDS_TYPE_NUMERICN, temp->maxLen, + precision, scale); + offset += temp->len; + } + break; case TDS_TYPE_XML: - { - temp->maxLen = message->data[offset++]; - retStatus = ReadPlp(temp, message, &offset); - CheckPLPStatusNotOK(temp, retStatus); - } - break; + { + temp->maxLen = message->data[offset++]; + retStatus = ReadPlp(temp, message, &offset); + CheckPLPStatusNotOK(temp, retStatus); + } + break; default: - ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " - "Parameter %d (\"%s\"): Data type 0x%02X is unknown.", - paramOrdinal, temp->paramMeta.colName.data, tdsType))); + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " + "Parameter %d (\"%s\"): Data type 0x%02X is unknown.", + paramOrdinal, temp->paramMeta.colName.data, tdsType))); } tempFuncInfo = TdsLookupTypeFunctionsByTdsId(tdsType, temp->maxLen); /* - * We save the recvFunc address here, so that during the bind we can directly - * use the recv function and save one extra lookup. We also store the sender - * sendFunc address here which can be used to send back OUT parameters. + * We save the recvFunc address here, so that during the bind we can + * directly use the recv function and save one extra lookup. We also + * store the sender sendFunc address here which can be used to send + * back OUT parameters. */ SetParamMetadataCommonInfo(&(temp->paramMeta), tempFuncInfo); @@ -1769,11 +1817,12 @@ ReadParameters(TDSRequestSP request, uint64_t offset, StringInfo message, int *p prev->next = temp; prev = temp; } - *parameterCount += 1; + *parameterCount += 1; } + /* - * We set the flag for offset as an invalid value so as to - * to execute the Flush phase in TdsSocketBackend. + * We set the flag for offset as an invalid value so as to to execute the + * Flush phase in TdsSocketBackend. */ request->batchSeparatorOffset = message->len; return STATUS_OK; @@ -1786,7 +1835,7 @@ ReadParameters(TDSRequestSP request, uint64_t offset, StringInfo message, int *p static void GetSPCursorHandleParameter(TDSRequestSP request) { - switch(request->spType) + switch (request->spType) { case SP_CURSORPREPEXEC: case SP_CURSOREXEC: @@ -1813,8 +1862,8 @@ GetSPCursorHandleParameter(TDSRequestSP request) /* the handle must be valid */ if (request->cursorHandle == SP_CURSOR_HANDLE_INVALID) ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("cursor %d doesn't exist", request->cursorHandle))); + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("cursor %d doesn't exist", request->cursorHandle))); } break; @@ -1841,7 +1890,7 @@ GetSPCursorHandleParameter(TDSRequestSP request) static void GetSPCursorPreparedHandleParameter(TDSRequestSP request) { - switch(request->spType) + switch (request->spType) { case SP_CURSORPREPEXEC: case SP_CURSOROPEN: @@ -1893,7 +1942,7 @@ GetSPCursorPreparedHandleParameter(TDSRequestSP request) static void GetSPHandleParameter(TDSRequestSP request) { - switch(request->spType) + switch (request->spType) { case SP_CURSORPREPARE: case SP_CURSORPREPEXEC: @@ -1956,8 +2005,8 @@ FillStoredProcedureCallFromParameterToken(TDSRequestSP req, StringInfo inBuf) { int paramno; int numParams; - ParameterToken token = NULL; - StringInfo name; + ParameterToken token = NULL; + StringInfo name; Assert(req->queryParameter == NULL); @@ -1980,7 +2029,7 @@ FillStoredProcedureCallFromParameterToken(TDSRequestSP req, StringInfo inBuf) else appendStringInfo(inBuf, "%s = %s", name->data, name->data); /* If this is an OUT parameter, mark it */ - if(token->flags & SP_FLAGS_BYREFVALUE) + if (token->flags & SP_FLAGS_BYREFVALUE) appendStringInfo(inBuf, " OUT"); token = token->next; paramno++; @@ -1995,7 +2044,7 @@ FillStoredProcedureCallFromParameterToken(TDSRequestSP req, StringInfo inBuf) else appendStringInfo(inBuf, ", %s = %s", name->data, name->data); /* If this is an OUT parameter, mark it */ - if(token->flags & SP_FLAGS_BYREFVALUE) + if (token->flags & SP_FLAGS_BYREFVALUE) appendStringInfo(inBuf, " OUT"); paramno++; } @@ -2022,9 +2071,9 @@ FillQueryFromParameterToken(TDSRequestSP req, StringInfo inBuf) static inline void InitializeDataParamTokenIndex(TDSRequestSP request) { - ParameterToken token; - uint16 idOutParam = 0; - int32 paramCount = 0; + ParameterToken token; + uint16 idOutParam = 0; + int32 paramCount = 0; request->nOutParams = 0; request->idxOutParams = NULL; @@ -2033,7 +2082,7 @@ InitializeDataParamTokenIndex(TDSRequestSP request) { request->nTotalParams++; - if ((token->flags & 0x01) == 1) + if ((token->flags & 0x01) == 1) request->nOutParams++; } @@ -2048,7 +2097,7 @@ InitializeDataParamTokenIndex(TDSRequestSP request) for (token = request->dataParameter; token != NULL; token = token->next) { - if ((token->flags & 0x01) == 1) + if ((token->flags & 0x01) == 1) request->idxOutParams[idOutParam++] = token; paramCount++; } @@ -2059,7 +2108,7 @@ InitializeDataParamTokenIndex(TDSRequestSP request) static inline void FillOidsFromParameterToken(TDSRequestSP req, StringInfo inBuf) { - ParameterToken token; + ParameterToken token; /* store num of data params amd their oids */ enlargeStringInfo(inBuf, sizeof(uint16) @@ -2069,7 +2118,8 @@ FillOidsFromParameterToken(TDSRequestSP req, StringInfo inBuf) for (token = req->dataParameter; token != NULL; token = token->next) { - uint32 paramType = (uint32) token->paramMeta.pgTypeOid; + uint32 paramType = (uint32) token->paramMeta.pgTypeOid; + pq_writeint32(inBuf, paramType); } } @@ -2139,16 +2189,16 @@ static int SetCursorOption(TDSRequestSP req) { - int curoptions = 0; + int curoptions = 0; /* we're always going to fetch in binary format */ curoptions = CURSOR_OPT_BINARY; /* - * XXX: For now, map STATIC cursor to WITH HOLD cursor option. It materializes - * the result in a temp file when the transaction is closed. But, a STATIC - * cursor should also return the number of tuples in the result set. We've - * not implemented that yet. + * XXX: For now, map STATIC cursor to WITH HOLD cursor option. It + * materializes the result in a temp file when the transaction is closed. + * But, a STATIC cursor should also return the number of tuples in the + * result set. We've not implemented that yet. */ if (req->scrollopt & SP_CURSOR_SCROLLOPT_STATIC) curoptions |= CURSOR_OPT_HOLD; @@ -2175,21 +2225,21 @@ SetCursorOption(TDSRequestSP req) static void SendCursorResponse(TDSRequestSP req) { - int cmd_type = TDS_CMD_UNKNOWN; - Portal portal; + int cmd_type = TDS_CMD_UNKNOWN; + Portal portal; /* fetch the portal */ portal = GetPortalFromCursorHandle(req->cursorHandle, false); /* * If we are in aborted transaction state, we can't run - * PrepareRowDescription(), because that needs catalog accesses. - * Hence, refuse to Describe portals that return data. + * PrepareRowDescription(), because that needs catalog accesses. Hence, + * refuse to Describe portals that return data. */ if (IsAbortedTransactionBlockState() && portal->tupDesc) elog(ERROR, "current transaction is aborted, " - "commands ignored until end of transaction block"); + "commands ignored until end of transaction block"); if (portal->commandTag && portal->commandTag == CMDTAG_SELECT) { @@ -2209,26 +2259,27 @@ SendCursorResponse(TDSRequestSP req) * and keyset cursors (XXX: these cursors are not yet implemented). */ PrepareRowDescription(portal->tupDesc, FetchPortalTargetList(portal), - portal->formats, true, - (req->scrollopt & (SP_CURSOR_SCROLLOPT_DYNAMIC | SP_CURSOR_SCROLLOPT_KEYSET))); + portal->formats, true, + (req->scrollopt & (SP_CURSOR_SCROLLOPT_DYNAMIC | SP_CURSOR_SCROLLOPT_KEYSET))); /* Send COLMETADATA token, TABNAME token and COLINFO token */ - SendColumnMetadataToken(portal->tupDesc->natts, true /* send ROWSTAT column */); + SendColumnMetadataToken(portal->tupDesc->natts, true /* send ROWSTAT column */ ); SendTabNameToken(); - SendColInfoToken(portal->tupDesc->natts, true /* send ROWSTAT column */); + SendColInfoToken(portal->tupDesc->natts, true /* send ROWSTAT column */ ); TdsSendDone(TDS_TOKEN_DONEINPROC, TDS_DONE_MORE, cmd_type, 0); /* * return codes - procedure executed successfully (0) * - * XXX: How to implement other return codes related to different error scenarios? + * XXX: How to implement other return codes related to different error + * scenarios? */ TdsSendReturnStatus(0); /* - * Send the handle for the PrePared Plan only for the - * sp_cursorprepexec request + * Send the handle for the PrePared Plan only for the sp_cursorprepexec + * request * */ if (req->spType == SP_CURSORPREPEXEC) @@ -2240,35 +2291,36 @@ SendCursorResponse(TDSRequestSP req) UInt32GetDatum(req->cursorHandle), false, false); /* - * If the scrollopt value is not appropriate for the cursor w.r.t the sql statement, - * the engine can override the scrollopt value. - * TODO: Implement this feature in the engine. Currently, PG engine doesn't have - * a way to modify the input value. For now, just return the input value. + * If the scrollopt value is not appropriate for the cursor w.r.t the sql + * statement, the engine can override the scrollopt value. TODO: Implement + * this feature in the engine. Currently, PG engine doesn't have a way to + * modify the input value. For now, just return the input value. */ if (req->cursorExtraArg1 && (req->cursorExtraArg1->flags & 0x01) == 1) SendReturnValueTokenInternal(req->cursorExtraArg1, 0x01, NULL, UInt32GetDatum((int) req->scrollopt), false, false); /* - * If the ccopt value is not appropriate for the cursor w.r.t the sql statement, - * the engine can override the ccopt value. - * TODO: Implement this feature in the engine. Currently, PG engine doesn't have - * a way to modify the input value. For now, just return the input value. + * If the ccopt value is not appropriate for the cursor w.r.t the sql + * statement, the engine can override the ccopt value. TODO: Implement + * this feature in the engine. Currently, PG engine doesn't have a way to + * modify the input value. For now, just return the input value. */ if (req->cursorExtraArg2 && (req->cursorExtraArg2->flags & 0x01) == 1) SendReturnValueTokenInternal(req->cursorExtraArg2, 0x01, NULL, UInt32GetDatum((int) req->ccopt), false, false); /* - * If the cursor is populated as part of sp_cursoropen request packet (STATIC, - * INSENSITIVE cursors), then we should return the actual number of rows in - * the result set. For dynamic cursors, we should return -1. Ideally, we should - * fetch the correct value from @@CURSOR_ROWS global variable. + * If the cursor is populated as part of sp_cursoropen request packet + * (STATIC, INSENSITIVE cursors), then we should return the actual number + * of rows in the result set. For dynamic cursors, we should return -1. + * Ideally, we should fetch the correct value from @@CURSOR_ROWS global + * variable. * - * TODO: Implement @@CURSOR_ROWS global variable. As part of that implementation, - * we should check how to get the correct number of rows without fetching anything - * from the cursor. For now, always send -1 and hope the client driver doesn't - * complain. + * TODO: Implement @@CURSOR_ROWS global variable. As part of that + * implementation, we should check how to get the correct number of rows + * without fetching anything from the cursor. For now, always send -1 and + * hope the client driver doesn't complain. */ if (req->cursorExtraArg3 && (req->cursorExtraArg3->flags & 0x01) == 1) SendReturnValueTokenInternal(req->cursorExtraArg3, 0x01, NULL, @@ -2283,8 +2335,8 @@ SendCursorResponse(TDSRequestSP req) static void HandleSPCursorOpenCommon(TDSRequestSP req) { - int curoptions = 0; - int ret; + int curoptions = 0; + int ret; StringInfoData buf; TdsErrorContext->err_text = "Processing SP_CURSOROPEN Common Request"; @@ -2299,49 +2351,51 @@ HandleSPCursorOpenCommon(TDSRequestSP req) { if (req->spType == SP_CURSOREXEC) { - char *activity = psprintf("SP_CURSOREXEC Handle: %d", (int)req->cursorPreparedHandle); + char *activity = psprintf("SP_CURSOREXEC Handle: %d", (int) req->cursorPreparedHandle); + pgstat_report_activity(STATE_RUNNING, activity); pfree(activity); - ret = pltsql_plugin_handler_ptr->sp_cursorexecute_callback((int)req->cursorPreparedHandle, (int *)&req->cursorHandle, &req->scrollopt, &req->ccopt, - NULL /* TODO row_count */, req->nTotalParams, req->boundParamsData, req->boundParamsNullList); + ret = pltsql_plugin_handler_ptr->sp_cursorexecute_callback((int) req->cursorPreparedHandle, (int *) &req->cursorHandle, &req->scrollopt, &req->ccopt, + NULL /* TODO row_count */ , req->nTotalParams, req->boundParamsData, req->boundParamsNullList); } else { - char *activity; + char *activity; + initStringInfo(&buf); /* fetch the query */ FillQueryFromParameterToken(req, &buf); switch (req->spType) { - case SP_CURSOROPEN: - activity = psprintf("SP_CURSOROPEN: %s", buf.data); - pgstat_report_activity(STATE_RUNNING, activity); - pfree(activity); + case SP_CURSOROPEN: + activity = psprintf("SP_CURSOROPEN: %s", buf.data); + pgstat_report_activity(STATE_RUNNING, activity); + pfree(activity); - ret = pltsql_plugin_handler_ptr->sp_cursoropen_callback((int *)&req->cursorHandle, buf.data, &req->scrollopt, &req->ccopt, - NULL /* TODO row_count */, req->nTotalParams, req->boundParamsData, req->boundParamsNullList); - break; - case SP_CURSORPREPARE: - activity = psprintf("SP_CURSORPREPARE: %s", buf.data); - pgstat_report_activity(STATE_RUNNING, activity); - pfree(activity); + ret = pltsql_plugin_handler_ptr->sp_cursoropen_callback((int *) &req->cursorHandle, buf.data, &req->scrollopt, &req->ccopt, + NULL /* TODO row_count */ , req->nTotalParams, req->boundParamsData, req->boundParamsNullList); + break; + case SP_CURSORPREPARE: + activity = psprintf("SP_CURSORPREPARE: %s", buf.data); + pgstat_report_activity(STATE_RUNNING, activity); + pfree(activity); - ret = pltsql_plugin_handler_ptr->sp_cursorprepare_callback((int *)&req->cursorPreparedHandle, buf.data, curoptions, &req->scrollopt, &req->ccopt, - (int)req->nTotalBindParams, req->boundParamsOidList); - break; - case SP_CURSORPREPEXEC: - activity = psprintf("SP_CURSORPREPEXEC: %s", buf.data); - pgstat_report_activity(STATE_RUNNING, activity); - pfree(activity); + ret = pltsql_plugin_handler_ptr->sp_cursorprepare_callback((int *) &req->cursorPreparedHandle, buf.data, curoptions, &req->scrollopt, &req->ccopt, + (int) req->nTotalBindParams, req->boundParamsOidList); + break; + case SP_CURSORPREPEXEC: + activity = psprintf("SP_CURSORPREPEXEC: %s", buf.data); + pgstat_report_activity(STATE_RUNNING, activity); + pfree(activity); - ret = pltsql_plugin_handler_ptr->sp_cursorprepexec_callback((int *)&req->cursorPreparedHandle, (int *)&req->cursorHandle, buf.data, curoptions, &req->scrollopt, &req->ccopt, - NULL /* TODO row_count */, req->nTotalParams, (int)req->nTotalBindParams, req->boundParamsOidList, req->boundParamsData, req->boundParamsNullList); - break; - default: - Assert(0); + ret = pltsql_plugin_handler_ptr->sp_cursorprepexec_callback((int *) &req->cursorPreparedHandle, (int *) &req->cursorHandle, buf.data, curoptions, &req->scrollopt, &req->ccopt, + NULL /* TODO row_count */ , req->nTotalParams, (int) req->nTotalBindParams, req->boundParamsOidList, req->boundParamsData, req->boundParamsNullList); + break; + default: + Assert(0); } if (ret > 0) @@ -2376,7 +2430,7 @@ HandleSPCursorOpenCommon(TDSRequestSP req) static void GenerateBindParamsData(TDSRequestSP req) { - uint16_t count = 0; + uint16_t count = 0; ParameterToken tempBindParam; bool isNull; TdsIoFunctionInfo tempFuncInfo; @@ -2413,7 +2467,7 @@ GenerateBindParamsData(TDSRequestSP req) { tempFuncInfo = TdsLookupTypeFunctionsByTdsId(tempBindParam->type, - tempBindParam->maxLen); + tempBindParam->maxLen); isNull = tempBindParam->isNull; ptype = tempBindParam->paramMeta.pgTypeOid; @@ -2436,7 +2490,7 @@ static void FetchAndValidateCursorFetchOptions(TDSRequestSP req, int *fetchType, int *rownum, int *howMany) { - ParameterToken token; + ParameterToken token; token = req->cursorExtraArg1; Assert(token); @@ -2447,7 +2501,7 @@ FetchAndValidateCursorFetchOptions(TDSRequestSP req, int *fetchType, memcpy(fetchType, &req->messageData[token->dataOffset], sizeof(uint32)); - switch(*fetchType) + switch (*fetchType) { case SP_CURSOR_FETCH_FIRST: case SP_CURSOR_FETCH_NEXT: @@ -2455,24 +2509,26 @@ FetchAndValidateCursorFetchOptions(TDSRequestSP req, int *fetchType, case SP_CURSOR_FETCH_LAST: case SP_CURSOR_FETCH_ABSOLUTE: break; - /* - * The following cursor options are not supported in postgres. Although - * postgres supports the relative cursor fetch option, but the behaviour - * in TDS protocol is very different from postgres. - */ + + /* + * The following cursor options are not supported in postgres. + * Although postgres supports the relative cursor fetch option, + * but the behaviour in TDS protocol is very different from + * postgres. + */ case SP_CURSOR_FETCH_RELATIVE: case SP_CURSOR_FETCH_REFRESH: case SP_CURSOR_FETCH_INFO: case SP_CURSOR_FETCH_PREV_NOADJUST: case SP_CURSOR_FETCH_SKIP_UPDT_CNCY: ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cursor fetch type %X not supported", *fetchType))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cursor fetch type %X not supported", *fetchType))); break; default: ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid cursor fetch type %X", *fetchType))); + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid cursor fetch type %X", *fetchType))); } token = req->cursorExtraArg2; @@ -2486,9 +2542,9 @@ FetchAndValidateCursorFetchOptions(TDSRequestSP req, int *fetchType, memcpy(rownum, &req->messageData[token->dataOffset], sizeof(uint32)); /* - * Rownum is used to specify the row position for the ABSOLUTE and INFO - * fetchtype. And, it serves as the row offset for the fetchtype bit - * value RELATIVE. It is ignored for all other values. + * Rownum is used to specify the row position for the ABSOLUTE and + * INFO fetchtype. And, it serves as the row offset for the fetchtype + * bit value RELATIVE. It is ignored for all other values. */ if (*fetchType != SP_CURSOR_FETCH_ABSOLUTE && *fetchType != SP_CURSOR_FETCH_RELATIVE && @@ -2535,11 +2591,11 @@ FetchAndValidateCursorFetchOptions(TDSRequestSP req, int *fetchType, static void HandleSPCursorFetchRequest(TDSRequestSP req) { - int ret; - int fetchType; - int rownum; - int nrows; - char *activity = psprintf("SP_CURSORFETCH Handle: %d", (int)req->cursorHandle); + int ret; + int fetchType; + int rownum; + int nrows; + char *activity = psprintf("SP_CURSORFETCH Handle: %d", (int) req->cursorHandle); TdsErrorContext->err_text = "Processing SP_CURSORFETCH Request"; pgstat_report_activity(STATE_RUNNING, activity); @@ -2551,7 +2607,7 @@ HandleSPCursorFetchRequest(TDSRequestSP req) PG_TRY(); { - ret = pltsql_plugin_handler_ptr->sp_cursorfetch_callback((int)req->cursorHandle, &fetchType, &rownum, &nrows); + ret = pltsql_plugin_handler_ptr->sp_cursorfetch_callback((int) req->cursorHandle, &fetchType, &rownum, &nrows); MemoryContextSwitchTo(MessageContext); if (ret > 0) @@ -2584,8 +2640,8 @@ HandleSPCursorFetchRequest(TDSRequestSP req) static void HandleSPCursorCloseRequest(TDSRequestSP req) { - int ret; - char *activity = psprintf("SP_CURSORCLOSE Handle: %d", (int)req->cursorHandle); + int ret; + char *activity = psprintf("SP_CURSORCLOSE Handle: %d", (int) req->cursorHandle); TdsErrorContext->err_text = "Processing SP_CURSORCLOSE Request"; pgstat_report_activity(STATE_RUNNING, activity); @@ -2595,7 +2651,7 @@ HandleSPCursorCloseRequest(TDSRequestSP req) /* close the cursor */ PG_TRY(); { - ret = pltsql_plugin_handler_ptr->sp_cursorclose_callback((int)req->cursorHandle); + ret = pltsql_plugin_handler_ptr->sp_cursorclose_callback((int) req->cursorHandle); MemoryContextSwitchTo(MessageContext); if (ret > 0) @@ -2626,8 +2682,8 @@ HandleSPCursorCloseRequest(TDSRequestSP req) static void HandleSPCursorUnprepareRequest(TDSRequestSP req) { - int ret; - char *activity = psprintf("SP_CURSORUNPREPARE Handle: %d", (int)req->cursorPreparedHandle); + int ret; + char *activity = psprintf("SP_CURSORUNPREPARE Handle: %d", (int) req->cursorPreparedHandle); TdsErrorContext->err_text = "Processing SP_CURSORUNPREPARE Request"; pgstat_report_activity(STATE_RUNNING, activity); @@ -2637,7 +2693,7 @@ HandleSPCursorUnprepareRequest(TDSRequestSP req) /* close the cursor */ PG_TRY(); { - ret = pltsql_plugin_handler_ptr->sp_cursorunprepare_callback((int)req->cursorPreparedHandle); + ret = pltsql_plugin_handler_ptr->sp_cursorunprepare_callback((int) req->cursorPreparedHandle); MemoryContextSwitchTo(MessageContext); if (ret > 0) @@ -2660,7 +2716,7 @@ HandleSPCursorUnprepareRequest(TDSRequestSP req) /* command type - execute (0xe0) */ TdsSendDone(TDS_TOKEN_DONEPROC, TDS_DONE_FINAL, 0xe0, 0); - + /* Log immediately if dictated by log_statement and log_duration */ TDSLogStatementCursorHandler(req, req->messageData, PRINT_CURSOR_HANDLE); } @@ -2668,12 +2724,13 @@ HandleSPCursorUnprepareRequest(TDSRequestSP req) static void HandleSPCursorOptionRequest(TDSRequestSP req) { - int ret; + int ret; ParameterToken token; - int code; - int value; + int code; + int value; + + char *activity = psprintf("SP_CURSOROPTION Handle: %d", (int) req->cursorHandle); - char *activity = psprintf("SP_CURSOROPTION Handle: %d", (int)req->cursorHandle); pgstat_report_activity(STATE_RUNNING, activity); pfree(activity); @@ -2703,7 +2760,7 @@ HandleSPCursorOptionRequest(TDSRequestSP req) PG_TRY(); { - ret = pltsql_plugin_handler_ptr->sp_cursoroption_callback((int)req->cursorHandle, code, value); + ret = pltsql_plugin_handler_ptr->sp_cursoroption_callback((int) req->cursorHandle, code, value); MemoryContextSwitchTo(MessageContext); if (ret > 0) @@ -2734,12 +2791,12 @@ HandleSPCursorOptionRequest(TDSRequestSP req) static void HandleSPCursorRequest(TDSRequestSP req) { - int ret; - List *values = NIL; - int i; + int ret; + List *values = NIL; + int i; ParameterToken token; - int optype; - int rownum; + int optype; + int rownum; pgstat_report_activity(STATE_RUNNING, "SP_CURSOR"); for (i = 0; i < req->nTotalBindParams; i++) @@ -2771,13 +2828,13 @@ HandleSPCursorRequest(TDSRequestSP req) PG_TRY(); { - StringInfo buf = makeStringInfo(); + StringInfo buf = makeStringInfo(); ParameterToken token = req->cursorExtraArg3; TdsReadUnicodeDataFromTokenCommon(req->messageData, token, buf); appendStringInfoCharMacro(buf, '\0'); - ret = pltsql_plugin_handler_ptr->sp_cursor_callback((int)req->cursorHandle, optype, rownum, buf->data, values); + ret = pltsql_plugin_handler_ptr->sp_cursor_callback((int) req->cursorHandle, optype, rownum, buf->data, values); MemoryContextSwitchTo(MessageContext); if (ret > 0) @@ -2808,29 +2865,31 @@ HandleSPCursorRequest(TDSRequestSP req) TDSRequest GetRPCRequest(StringInfo message) { - TDSRequestSP request; - uint64_t offset = 0; - uint16_t len = 0; - int messageLen = 0; - int parameterCount = 0; - uint32_t tdsVersion = GetClientTDSVersion(); + TDSRequestSP request; + uint64_t offset = 0; + uint16_t len = 0; + int messageLen = 0; + int parameterCount = 0; + uint32_t tdsVersion = GetClientTDSVersion(); TdsErrorContext->err_text = "Fetching RPC Request"; + /* - * In the ALL_HEADERS rule, the Query Notifications header and the Transaction - * Descriptor header were introduced in TDS 7.2. We need to to Process them only - * for TDS versions more than or equal to 7.2, otherwise we do not increment the offset. + * In the ALL_HEADERS rule, the Query Notifications header and the + * Transaction Descriptor header were introduced in TDS 7.2. We need to to + * Process them only for TDS versions more than or equal to 7.2, otherwise + * we do not increment the offset. */ if (tdsVersion > TDS_VERSION_7_1_1) offset = ProcessStreamHeaders(message); /* Build return structure */ - if(TdsRequestCtrl->request != NULL && RPCBatchExists(TdsRequestCtrl->request->sp)) + if (TdsRequestCtrl->request != NULL && RPCBatchExists(TdsRequestCtrl->request->sp)) { /* - * If previously an RPC batch separator was found and if another RPC is left to process - * then we set the offset to the first byte of the next RPC packet - * and use the existing request after initialising. + * If previously an RPC batch separator was found and if another RPC + * is left to process then we set the offset to the first byte of the + * next RPC packet and use the existing request after initialising. */ offset = TdsRequestCtrl->request->sp.batchSeparatorOffset; messageLen = TdsRequestCtrl->request->sp.messageLen; @@ -2843,18 +2902,17 @@ GetRPCRequest(StringInfo message) request->reqType = TDS_REQUEST_SP_NUMBER; memcpy(&len, &(message->data[offset]), sizeof(len)); + /* - * initStringInfo even if len is 0, so that - * the processing logic can check the length field from - * request.name->len + * initStringInfo even if len is 0, so that the processing logic can check + * the length field from request.name->len */ initStringInfo(&request->name); - offset += sizeof(len); /* Procedure name len */ + offset += sizeof(len); /* Procedure name len */ /* - * The RPC packet will contain the SP name - * (dotnet SP) or will contain the TDS spec - * defined SPType (prep-exec, Java SP) + * The RPC packet will contain the SP name (dotnet SP) or will contain the + * TDS spec defined SPType (prep-exec, Java SP) */ if (len != 0xffff) { @@ -2875,15 +2933,15 @@ GetRPCRequest(StringInfo message) offset += sizeof(request->spFlags); /* - * Store the address of message data, so that - * the Process step can fetch it + * Store the address of message data, so that the Process step can fetch + * it */ request->messageData = message->data; if (ReadParameters(request, offset, message, ¶meterCount) != STATUS_OK) elog(FATAL, "corrupted TDS_RPC message - " - "offset beyond the message length"); - /*Initialise*/ + "offset beyond the message length"); + /* Initialise */ InitialiseParameterToken(request); /* TODO: SP might need special handling, this is only for prep-exec */ @@ -2893,39 +2951,38 @@ GetRPCRequest(StringInfo message) { TdsErrorContext->spType = "SP_CURSOROPEN"; TDSInstrumentation(INSTR_TDS_SP_CURSOR_OPEN); + /* * - * The order of the parameter is cursor handle, cursor statement, - * scrollopt, ccopt, rowcount and boundparams. Cursor handle - * and statement are mandatory, the rest are optional parameters. - * If one optional parameter exists, all previous optional parameter - * must be there in the packet. + * The order of the parameter is cursor handle, cursor + * statement, scrollopt, ccopt, rowcount and boundparams. + * Cursor handle and statement are mandatory, the rest are + * optional parameters. If one optional parameter exists, all + * previous optional parameter must be there in the packet. */ if (unlikely(parameterCount < 2)) ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The minimum number of parameters should be %d", 2))); + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The minimum number of parameters should be %d", 2))); if (unlikely(FetchDataTypeNameFromParameter(request->parameter) != TDS_TYPE_INTEGER)) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "Cursor handle", "integer"))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "Cursor handle", "integer"))); request->cursorHandleParameter = request->parameter; if (unlikely(!request->parameter->next)) ereport(ERROR, - (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("%s parameter should not be null", "Query"))); + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("%s parameter should not be null", "Query"))); if (unlikely(FetchDataTypeNameFromParameter(request->parameter->next) != TDS_TYPE_NVARCHAR && - FetchDataTypeNameFromParameter(request->parameter->next) != TDS_TYPE_NTEXT)) + FetchDataTypeNameFromParameter(request->parameter->next) != TDS_TYPE_NTEXT)) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "Query", "NVARCHAR or NTEXT"))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "Query", "NVARCHAR or NTEXT"))); request->queryParameter = request->parameter->next; /* - * ExtraArg1 = scrollopt - * ExtraArg2 = ccopt - * ExtraArg3 = Rowcount - * dataParameter = boundparams + * ExtraArg1 = scrollopt ExtraArg2 = ccopt ExtraArg3 = + * Rowcount dataParameter = boundparams */ request->cursorExtraArg1 = request->queryParameter->next; @@ -2940,8 +2997,8 @@ GetRPCRequest(StringInfo message) if (request->cursorExtraArg3->next != NULL) { TdsReadUnicodeDataFromTokenCommon(message->data, - request->cursorExtraArg3->next, - request->metaDataParameterValue); + request->cursorExtraArg3->next, + request->metaDataParameterValue); request->dataParameter = request->cursorExtraArg3->next->next; } } @@ -2955,29 +3012,28 @@ GetRPCRequest(StringInfo message) TDSInstrumentation(INSTR_TDS_SP_CURSOR_EXEC); if (unlikely(parameterCount < 2)) ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The minimum number of parameters should be %d", 2))); + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The minimum number of parameters should be %d", 2))); + /* - * 1. Cursor prepared Handle parameter (mandatory) - * 2. Cursor parameter (mandatory) - * 3. ExtraArg1 = scrollopt - * 4. ExtraArg2 = ccopt - * 5. ExtraArg3 = Rowcount - * 6. dataParameter = boundparams + * 1. Cursor prepared Handle parameter (mandatory) 2. Cursor + * parameter (mandatory) 3. ExtraArg1 = scrollopt 4. + * ExtraArg2 = ccopt 5. ExtraArg3 = Rowcount 6. dataParameter + * = boundparams */ if (unlikely(FetchDataTypeNameFromParameter(request->parameter) != TDS_TYPE_INTEGER)) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "Cursor prepared handle", "integer"))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "Cursor prepared handle", "integer"))); request->cursorPreparedHandleParameter = request->parameter; if (unlikely(!request->cursorPreparedHandleParameter->next)) ereport(ERROR, - (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("%s parameter should not be null", "Cursor handle"))); + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("%s parameter should not be null", "Cursor handle"))); if (unlikely(FetchDataTypeNameFromParameter(request->cursorPreparedHandleParameter->next) != TDS_TYPE_INTEGER)) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "Cursor handle", "integer"))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "Cursor handle", "integer"))); request->cursorHandleParameter = request->cursorPreparedHandleParameter->next; if (request->cursorHandleParameter) @@ -3006,53 +3062,52 @@ GetRPCRequest(StringInfo message) TdsErrorContext->spType = "SP_CURSORPREPEXEC"; TDSInstrumentation(INSTR_TDS_SP_CURSOR_PREPEXEC); - if (unlikely(parameterCount < 3)) + if (unlikely(parameterCount < 3)) ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The minimum number of parameters should be %d", 3))); + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The minimum number of parameters should be %d", 3))); + /* - * 1. Cursor prepared Handle parameter (mandatory) - * 2. Cursor parameter (mandatory) - * 3. query parameter (mandatory) - * 4. ExtraArg1 = scrollopt - * 5. ExtraArg2 = ccopt - * 6. ExtraArg3 = Rowcount - * 7. dataParameter = boundparams + * 1. Cursor prepared Handle parameter (mandatory) 2. Cursor + * parameter (mandatory) 3. query parameter (mandatory) 4. + * ExtraArg1 = scrollopt 5. ExtraArg2 = ccopt 6. ExtraArg3 = + * Rowcount 7. dataParameter = boundparams */ if (unlikely(FetchDataTypeNameFromParameter(request->parameter) != TDS_TYPE_INTEGER)) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "Cursor prepared handle", "integer"))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "Cursor prepared handle", "integer"))); request->cursorPreparedHandleParameter = request->parameter; if (unlikely(!request->cursorPreparedHandleParameter->next)) ereport(ERROR, - (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("%s parameter should not be null", "Cursor handle"))); + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("%s parameter should not be null", "Cursor handle"))); if (unlikely(FetchDataTypeNameFromParameter(request->cursorPreparedHandleParameter->next) != TDS_TYPE_INTEGER)) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "Cursor handle", "integer"))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "Cursor handle", "integer"))); request->cursorHandleParameter = request->cursorPreparedHandleParameter->next; /* - * We haven't seen the case where dataParameter is absent in case of cursorprepexec - * So, indirectly, metaData (For ex. @P1 int, @P2 int etc) will always be there. + * We haven't seen the case where dataParameter is absent in + * case of cursorprepexec So, indirectly, metaData (For ex. + * @P1 int, @P2 int etc) will always be there. */ TdsReadUnicodeDataFromTokenCommon(message->data, - request->cursorHandleParameter->next, - request->metaDataParameterValue); + request->cursorHandleParameter->next, + request->metaDataParameterValue); if (unlikely(!request->cursorHandleParameter->next->next)) ereport(ERROR, - (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("%s parameter should not be null", "Query"))); + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("%s parameter should not be null", "Query"))); if (unlikely(FetchDataTypeNameFromParameter(request->cursorHandleParameter->next->next) != TDS_TYPE_NVARCHAR && - FetchDataTypeNameFromParameter(request->cursorHandleParameter->next->next) != TDS_TYPE_NTEXT)) + FetchDataTypeNameFromParameter(request->cursorHandleParameter->next->next) != TDS_TYPE_NTEXT)) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "Query", "NVARCHAR or NTEXT"))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "Query", "NVARCHAR or NTEXT"))); request->queryParameter = request->cursorHandleParameter->next->next; if (request->queryParameter) @@ -3086,22 +3141,20 @@ GetRPCRequest(StringInfo message) /* * - * The order of the parameter is cursor handle, fetch - * type, rownum and nrows. Only Cursor handle is mandatory, - * the rest are optional parameters. If one optional - * parameter exists, all previous optional parameter - * must be there in the packet. + * The order of the parameter is cursor handle, fetch type, + * rownum and nrows. Only Cursor handle is mandatory, the + * rest are optional parameters. If one optional parameter + * exists, all previous optional parameter must be there in + * the packet. */ if (unlikely(FetchDataTypeNameFromParameter(request->parameter) != TDS_TYPE_INTEGER)) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "Cursor handle", "integer"))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "Cursor handle", "integer"))); request->cursorHandleParameter = request->parameter; /* - * ExtraArg1 = fetch type - * ExtraArg2 = rownum - * ExtraArg3 = nrows + * ExtraArg1 = fetch type ExtraArg2 = rownum ExtraArg3 = nrows */ request->cursorExtraArg1 = request->cursorHandleParameter->next; @@ -3121,13 +3174,13 @@ GetRPCRequest(StringInfo message) TDSInstrumentation(INSTR_TDS_SP_CURSOR_CLOSE); if (unlikely(parameterCount < 1)) ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The minimum number of parameters should be %d", 1))); + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The minimum number of parameters should be %d", 1))); if (unlikely(FetchDataTypeNameFromParameter(request->parameter) != TDS_TYPE_INTEGER)) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "Cursor handle", "integer"))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "Cursor handle", "integer"))); request->cursorHandleParameter = request->parameter; TDS_DEBUG(TDS_DEBUG1, "message_type: Remote Procedure Call (3) rpc_packet_type: sp_cursorclose"); } @@ -3139,12 +3192,12 @@ GetRPCRequest(StringInfo message) if (unlikely(parameterCount < 1)) ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The minimum number of parameters should be %d", 1))); + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The minimum number of parameters should be %d", 1))); if (unlikely(FetchDataTypeNameFromParameter(request->parameter) != TDS_TYPE_INTEGER)) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "Cursor prepared handle", "integer"))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "Cursor prepared handle", "integer"))); request->cursorPreparedHandleParameter = request->parameter; TDS_DEBUG(TDS_DEBUG1, "message_type: Remote Procedure Call (3) rpc_packet_type: sp_cursorunprepare"); } @@ -3152,62 +3205,60 @@ GetRPCRequest(StringInfo message) case SP_CURSOR: { /* - * 1. Cursor parameter (mandatory) - * 2. ExtraArg1 = optype (mandatory) - * 3. ExtraArg2 = rownum (mandatory) - * 4. ExtraArg3 = table (mandatory) - * 5. dataParameter = value + * 1. Cursor parameter (mandatory) 2. ExtraArg1 = optype + * (mandatory) 3. ExtraArg2 = rownum (mandatory) 4. ExtraArg3 + * = table (mandatory) 5. dataParameter = value */ TdsErrorContext->spType = "SP_CURSOR"; TDSInstrumentation(INSTR_UNSUPPORTED_TDS_SP_CURSOR); - if (unlikely(parameterCount < 4)) + if (unlikely(parameterCount < 4)) ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The minimum number of parameters should be %d", 4))); + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The minimum number of parameters should be %d", 4))); - if (unlikely(FetchDataTypeNameFromParameter(request->parameter) != TDS_TYPE_INTEGER)) + if (unlikely(FetchDataTypeNameFromParameter(request->parameter) != TDS_TYPE_INTEGER)) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "Cursor handle", "integer"))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "Cursor handle", "integer"))); request->cursorHandleParameter = request->parameter; request->cursorExtraArg1 = request->cursorHandleParameter->next; if (unlikely(FetchDataTypeNameFromParameter(request->cursorExtraArg1) != TDS_TYPE_INTEGER)) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "optype", "integer"))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "optype", "integer"))); request->cursorExtraArg2 = request->cursorExtraArg1->next; if (unlikely(FetchDataTypeNameFromParameter(request->cursorExtraArg2) != TDS_TYPE_INTEGER)) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "rownum", "integer"))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "rownum", "integer"))); /* table should be of string datatype */ request->cursorExtraArg3 = request->cursorExtraArg2->next; if (unlikely(FetchDataTypeNameFromParameter(request->cursorExtraArg3) != TDS_TYPE_NVARCHAR && - FetchDataTypeNameFromParameter(request->cursorExtraArg3) != TDS_TYPE_VARCHAR && - FetchDataTypeNameFromParameter(request->cursorExtraArg3) != TDS_TYPE_NCHAR && - FetchDataTypeNameFromParameter(request->cursorExtraArg3) != TDS_TYPE_CHAR && - FetchDataTypeNameFromParameter(request->cursorExtraArg3) != TDS_TYPE_NTEXT && - FetchDataTypeNameFromParameter(request->cursorExtraArg3) != TDS_TYPE_TEXT)) + FetchDataTypeNameFromParameter(request->cursorExtraArg3) != TDS_TYPE_VARCHAR && + FetchDataTypeNameFromParameter(request->cursorExtraArg3) != TDS_TYPE_NCHAR && + FetchDataTypeNameFromParameter(request->cursorExtraArg3) != TDS_TYPE_CHAR && + FetchDataTypeNameFromParameter(request->cursorExtraArg3) != TDS_TYPE_NTEXT && + FetchDataTypeNameFromParameter(request->cursorExtraArg3) != TDS_TYPE_TEXT)) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "table", "string"))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "table", "string"))); if (request->cursorExtraArg3->next) { /* value should be of string datatype */ request->dataParameter = request->cursorExtraArg3->next; if (unlikely(FetchDataTypeNameFromParameter(request->cursorExtraArg3) != TDS_TYPE_NVARCHAR && - FetchDataTypeNameFromParameter(request->cursorExtraArg3) != TDS_TYPE_VARCHAR && - FetchDataTypeNameFromParameter(request->cursorExtraArg3) != TDS_TYPE_NCHAR && - FetchDataTypeNameFromParameter(request->cursorExtraArg3) != TDS_TYPE_CHAR && - FetchDataTypeNameFromParameter(request->cursorExtraArg3) != TDS_TYPE_NTEXT && - FetchDataTypeNameFromParameter(request->cursorExtraArg3) != TDS_TYPE_TEXT)) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "value", "string"))); + FetchDataTypeNameFromParameter(request->cursorExtraArg3) != TDS_TYPE_VARCHAR && + FetchDataTypeNameFromParameter(request->cursorExtraArg3) != TDS_TYPE_NCHAR && + FetchDataTypeNameFromParameter(request->cursorExtraArg3) != TDS_TYPE_CHAR && + FetchDataTypeNameFromParameter(request->cursorExtraArg3) != TDS_TYPE_NTEXT && + FetchDataTypeNameFromParameter(request->cursorExtraArg3) != TDS_TYPE_TEXT)) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "value", "string"))); } TDS_DEBUG(TDS_DEBUG1, "message_type: Remote Procedure Call (3) rpc_packet_type: sp_cursor"); } @@ -3215,99 +3266,97 @@ GetRPCRequest(StringInfo message) case SP_CURSOROPTION: { /* - * 1. Cursor parameter (mandatory) - * 2. ExtraArg1 = code (mandatory) - * 3. ExtraArg2 = value (mandatory) + * 1. Cursor parameter (mandatory) 2. ExtraArg1 = code + * (mandatory) 3. ExtraArg2 = value (mandatory) */ TdsErrorContext->spType = "SP_CURSOROPTION"; TDSInstrumentation(INSTR_UNSUPPORTED_TDS_SP_CURSOROPTION); - if (unlikely(parameterCount < 3)) + if (unlikely(parameterCount < 3)) ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The minimum number of parameters should be %d", 3))); + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The minimum number of parameters should be %d", 3))); - if (unlikely(FetchDataTypeNameFromParameter(request->parameter) != TDS_TYPE_INTEGER)) + if (unlikely(FetchDataTypeNameFromParameter(request->parameter) != TDS_TYPE_INTEGER)) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "Cursor handle", "integer"))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "Cursor handle", "integer"))); request->cursorHandleParameter = request->parameter; request->cursorExtraArg1 = request->cursorHandleParameter->next; if (unlikely(FetchDataTypeNameFromParameter(request->cursorExtraArg1) != TDS_TYPE_INTEGER)) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "code", "integer"))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "code", "integer"))); request->cursorExtraArg2 = request->cursorExtraArg1->next; if (unlikely(FetchDataTypeNameFromParameter(request->cursorExtraArg2) != TDS_TYPE_INTEGER)) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "value", "integer"))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "value", "integer"))); TDS_DEBUG(TDS_DEBUG1, "message_type: Remote Procedure Call (3) rpc_packet_type: sp_cursoroption"); } break; case SP_CURSORPREPARE: { - /* - * 1. Cursor prepared Handle parameter (mandatory) - * 2. query parameter (mandatory) - * 3. ExtraArg1 = scrollopt - * 4. ExtraArg2 = ccopt - */ - TDSInstrumentation(INSTR_UNSUPPORTED_TDS_SP_CURSORPREPARE); - if (unlikely(parameterCount < 4)) - ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The minimum number of parameters should be %d", 4))); - - if (unlikely(FetchDataTypeNameFromParameter(request->parameter) != TDS_TYPE_INTEGER)) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "Cursor prepared handle", "integer"))); - request->cursorPreparedHandleParameter = request->parameter; + /* + * 1. Cursor prepared Handle parameter (mandatory) 2. query + * parameter (mandatory) 3. ExtraArg1 = scrollopt 4. ExtraArg2 + * = ccopt + */ + TDSInstrumentation(INSTR_UNSUPPORTED_TDS_SP_CURSORPREPARE); + if (unlikely(parameterCount < 4)) + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The minimum number of parameters should be %d", 4))); - TdsReadUnicodeDataFromTokenCommon(message->data, - request->cursorPreparedHandleParameter->next, - request->metaDataParameterValue); + if (unlikely(FetchDataTypeNameFromParameter(request->parameter) != TDS_TYPE_INTEGER)) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "Cursor prepared handle", "integer"))); + request->cursorPreparedHandleParameter = request->parameter; - if (unlikely(!request->cursorPreparedHandleParameter->next->next)) + TdsReadUnicodeDataFromTokenCommon(message->data, + request->cursorPreparedHandleParameter->next, + request->metaDataParameterValue); + + if (unlikely(!request->cursorPreparedHandleParameter->next->next)) ereport(ERROR, - (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("%s parameter should not be null", "Query"))); - if (unlikely(FetchDataTypeNameFromParameter(request->cursorPreparedHandleParameter->next->next) != TDS_TYPE_NVARCHAR && - FetchDataTypeNameFromParameter(request->cursorPreparedHandleParameter->next->next) != TDS_TYPE_NTEXT)) + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("%s parameter should not be null", "Query"))); + if (unlikely(FetchDataTypeNameFromParameter(request->cursorPreparedHandleParameter->next->next) != TDS_TYPE_NVARCHAR && + FetchDataTypeNameFromParameter(request->cursorPreparedHandleParameter->next->next) != TDS_TYPE_NTEXT)) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "Query", "NVARCHAR or NTEXT"))); - request->queryParameter = request->cursorPreparedHandleParameter->next->next; + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "Query", "NVARCHAR or NTEXT"))); + request->queryParameter = request->cursorPreparedHandleParameter->next->next; - if (unlikely(FetchDataTypeNameFromParameter(request->queryParameter) != TDS_TYPE_NVARCHAR && - FetchDataTypeNameFromParameter(request->parameter) != TDS_TYPE_NCHAR && - FetchDataTypeNameFromParameter(request->parameter) != TDS_TYPE_NTEXT)) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "Query", "NVARCHAR or NTEXT"))); + if (unlikely(FetchDataTypeNameFromParameter(request->queryParameter) != TDS_TYPE_NVARCHAR && + FetchDataTypeNameFromParameter(request->parameter) != TDS_TYPE_NCHAR && + FetchDataTypeNameFromParameter(request->parameter) != TDS_TYPE_NTEXT)) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "Query", "NVARCHAR or NTEXT"))); - request->cursorExtraArg1 = request->queryParameter->next; - if (unlikely(FetchDataTypeNameFromParameter(request->cursorExtraArg1) != TDS_TYPE_INTEGER)) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "options", "integer"))); + request->cursorExtraArg1 = request->queryParameter->next; + if (unlikely(FetchDataTypeNameFromParameter(request->cursorExtraArg1) != TDS_TYPE_INTEGER)) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "options", "integer"))); - request->cursorExtraArg2 = request->queryParameter->next; - if (unlikely(FetchDataTypeNameFromParameter(request->cursorExtraArg2) != TDS_TYPE_INTEGER)) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "scrollopt", "integer"))); + request->cursorExtraArg2 = request->queryParameter->next; + if (unlikely(FetchDataTypeNameFromParameter(request->cursorExtraArg2) != TDS_TYPE_INTEGER)) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "scrollopt", "integer"))); - request->cursorExtraArg3 = request->queryParameter->next; - if (unlikely(FetchDataTypeNameFromParameter(request->cursorExtraArg3) != TDS_TYPE_INTEGER)) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "ccopt", "integer"))); + request->cursorExtraArg3 = request->queryParameter->next; + if (unlikely(FetchDataTypeNameFromParameter(request->cursorExtraArg3) != TDS_TYPE_INTEGER)) ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("\n Tds %s not supported yet", "SP_CURSORPREPARE"))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "ccopt", "integer"))); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("\n Tds %s not supported yet", "SP_CURSORPREPARE"))); } break; case SP_EXECUTESQL: @@ -3315,21 +3364,21 @@ GetRPCRequest(StringInfo message) TdsErrorContext->spType = "SP_EXECUTESQL"; if (unlikely(parameterCount < 1)) ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The minimum number of parameters should be %d", 1))); + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The minimum number of parameters should be %d", 1))); if (unlikely(FetchDataTypeNameFromParameter(request->parameter) != TDS_TYPE_NVARCHAR && - FetchDataTypeNameFromParameter(request->parameter) != TDS_TYPE_NTEXT)) + FetchDataTypeNameFromParameter(request->parameter) != TDS_TYPE_NTEXT)) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "Query", "NVARCHAR or NTEXT"))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "Query", "NVARCHAR or NTEXT"))); request->queryParameter = request->parameter; if (request->queryParameter->next && request->queryParameter->next->next) { TdsReadUnicodeDataFromTokenCommon(message->data, - request->queryParameter->next, - request->metaDataParameterValue); + request->queryParameter->next, + request->metaDataParameterValue); request->dataParameter = request->queryParameter->next->next; } @@ -3341,44 +3390,43 @@ GetRPCRequest(StringInfo message) TdsErrorContext->spType = "SP_PREPARE"; if (unlikely(parameterCount < 2)) ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The minimum number of parameters should be %d", 2))); + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The minimum number of parameters should be %d", 2))); if (unlikely(FetchDataTypeNameFromParameter(request->parameter) != TDS_TYPE_INTEGER)) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "Handle", "integer"))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "Handle", "integer"))); request->handleParameter = request->parameter; /* - * In case, IN/OUT parameters are absent - * then the intermediate parameter will - * (@P0 int, ...) will be absent, and - * next parameter after the handle parameter - * should be the actual query + * In case, IN/OUT parameters are absent then the intermediate + * parameter will (@P0 int, ...) will be absent, and next + * parameter after the handle parameter should be the actual + * query */ if (request->parameter->next && request->parameter->next->next) { if (request->handleParameter) { TdsReadUnicodeDataFromTokenCommon(message->data, - request->handleParameter->next, - request->metaDataParameterValue); + request->handleParameter->next, + request->metaDataParameterValue); } if (unlikely(FetchDataTypeNameFromParameter(request->parameter->next->next) != TDS_TYPE_NVARCHAR && - FetchDataTypeNameFromParameter(request->parameter->next->next) != TDS_TYPE_NTEXT)) + FetchDataTypeNameFromParameter(request->parameter->next->next) != TDS_TYPE_NTEXT)) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "Query", "NVARCHAR or NTEXT"))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "Query", "NVARCHAR or NTEXT"))); request->queryParameter = request->parameter->next->next; } else { if (unlikely(FetchDataTypeNameFromParameter(request->parameter->next) != TDS_TYPE_NVARCHAR && - FetchDataTypeNameFromParameter(request->parameter->next) != TDS_TYPE_NTEXT)) + FetchDataTypeNameFromParameter(request->parameter->next) != TDS_TYPE_NTEXT)) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "Query", "NVARCHAR or NTEXT"))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "Query", "NVARCHAR or NTEXT"))); request->queryParameter = request->parameter->next; } if (request->queryParameter->next) @@ -3392,12 +3440,12 @@ GetRPCRequest(StringInfo message) TdsErrorContext->spType = "SP_EXECUTE"; if (unlikely(parameterCount < 1)) ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The minimum number of parameters should be %d", 1))); + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The minimum number of parameters should be %d", 1))); if (unlikely(FetchDataTypeNameFromParameter(request->parameter) != TDS_TYPE_INTEGER)) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "Handle", "INT"))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "Handle", "INT"))); request->handleParameter = request->parameter; @@ -3411,20 +3459,19 @@ GetRPCRequest(StringInfo message) TdsErrorContext->spType = "SP_PREPEXEC"; if (unlikely(parameterCount < 2)) ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The minimum number of parameters should be %d", 2))); + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The minimum number of parameters should be %d", 2))); if (unlikely(FetchDataTypeNameFromParameter(request->parameter) != TDS_TYPE_INTEGER)) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "Handle", "INT"))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "Handle", "INT"))); request->handleParameter = request->parameter; /* - * In case, IN/OUT parameters are absent - * then the intermediate parameter will - * (@P0 int, ...) will be absent, and - * next parameter after the handle parameter - * should be the actual query + * In case, IN/OUT parameters are absent then the intermediate + * parameter will (@P0 int, ...) will be absent, and next + * parameter after the handle parameter should be the actual + * query */ if (request->parameter->next && request->parameter->next->next) @@ -3432,24 +3479,24 @@ GetRPCRequest(StringInfo message) if (request->handleParameter) { TdsReadUnicodeDataFromTokenCommon(message->data, - request->handleParameter->next, - request->metaDataParameterValue); + request->handleParameter->next, + request->metaDataParameterValue); } if (unlikely(FetchDataTypeNameFromParameter(request->parameter->next->next) != TDS_TYPE_NVARCHAR && - FetchDataTypeNameFromParameter(request->parameter->next->next) != TDS_TYPE_NTEXT)) + FetchDataTypeNameFromParameter(request->parameter->next->next) != TDS_TYPE_NTEXT)) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "Query", "NVARCHAR or NTEXT"))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "Query", "NVARCHAR or NTEXT"))); request->queryParameter = request->parameter->next->next; } else { if (unlikely(FetchDataTypeNameFromParameter(request->parameter->next) != TDS_TYPE_NVARCHAR && - FetchDataTypeNameFromParameter(request->parameter->next) != TDS_TYPE_NTEXT)) + FetchDataTypeNameFromParameter(request->parameter->next) != TDS_TYPE_NTEXT)) ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("%s parameter should be of %s type", "Query", "NVARCHAR or NTEXT"))); + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("%s parameter should be of %s type", "Query", "NVARCHAR or NTEXT"))); request->queryParameter = request->parameter->next; } if (request->queryParameter->next) @@ -3462,8 +3509,8 @@ GetRPCRequest(StringInfo message) TdsErrorContext->spType = "SP_PREPEXECRPC"; /* Not supported yet */ ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("SP_PREPEXECRPC not supported yet"))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("SP_PREPEXECRPC not supported yet"))); } break; case SP_UNPREPARE: @@ -3471,8 +3518,8 @@ GetRPCRequest(StringInfo message) TdsErrorContext->spType = "SP_UNPREPARE"; if (unlikely(parameterCount < 1)) ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The minimum number of parameters should be %d", 1))); + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The minimum number of parameters should be %d", 1))); request->handleParameter = request->parameter; TDS_DEBUG(TDS_DEBUG1, "message_type: Remote Procedure Call (3) rpc_packet_type: sp_unprepare"); } @@ -3485,9 +3532,9 @@ GetRPCRequest(StringInfo message) } break; default: - ereport(ERROR, + ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. The RPC name is invalid."))); + errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. The RPC name is invalid."))); } /* initialize the IN/OUT parameter index array */ @@ -3502,7 +3549,7 @@ GetRPCRequest(StringInfo message) /* get the SP cursor Prepared handle */ GetSPCursorPreparedHandleParameter(request); - return (TDSRequest)request; + return (TDSRequest) request; } void @@ -3513,7 +3560,8 @@ RestoreRPCBatch(StringInfo message, uint8_t *status, uint8_t *messageType) Assert(RPCBatchExists(TdsRequestCtrl->request->sp)); message->data = TdsRequestCtrl->request->sp.messageData; message->len = TdsRequestCtrl->request->sp.messageLen; - *messageType = TDS_RPC; /* Hardcoded the type since we do an assert at the start. */ + *messageType = TDS_RPC; /* Hardcoded the type since we do an assert at + * the start. */ *status = TdsRequestCtrl->status; } @@ -3524,7 +3572,7 @@ ProcessRPCRequest(TDSRequest request) req = (TDSRequestSP) request; - switch(req->spType) + switch (req->spType) { case SP_CURSOR: GenerateBindParamsData(req); @@ -3580,6 +3628,7 @@ bool TdsIsSPPrepare() { TDSRequestSP req; + req = (TDSRequestSP) TdsRequestCtrl->request; if (req->spType == SP_PREPARE) return true; @@ -3600,8 +3649,8 @@ TdsIsSPPrepare() void TdsFetchInParamValues(ParamListInfo params) { - ParameterToken token; - TDSRequest request = TdsRequestCtrl->request; + ParameterToken token; + TDSRequest request = TdsRequestCtrl->request; TDSRequestSP req; int paramno = 0; @@ -3678,21 +3727,24 @@ TdsGetAndSetParamIndex(const char *name) } req = (TDSRequestSP) TdsRequestCtrl->request; + /* - * We need to use the intermediate Parameter - * For ex: (@P0 int, @P1 int etc) when available. + * We need to use the intermediate Parameter For ex: (@P0 int, @P1 int + * etc) when available. */ if (req->metaDataParameterValue->len > 0) { - int i = 0, temp = 0; - const char *source = req->metaDataParameterValue->data; - char *pos; + int i = 0, + temp = 0; + const char *source = req->metaDataParameterValue->data; + char *pos; int ptr; - int qlen = strlen(source); + int qlen = strlen(source); int nlen = strlen(name); + while (temp < qlen) { - int j; + int j; /* * If param names are not given by the application, then driver @@ -3711,17 +3763,19 @@ TdsGetAndSetParamIndex(const char *name) for (j = ptr; j < ptr + nlen && j < qlen; j++) { /* - * Parameter names comparison seems to be dependent on collation - * (case sensitive vs insensitive). So here, we will have to do the - * comparision depending on collation. For now, convert everything - * into lower case and compare since by default collation in TSQL - * is case insensitive (SQL_Latin1_General_CP1_CI_AS) + * Parameter names comparison seems to be dependent on + * collation (case sensitive vs insensitive). So here, we will + * have to do the comparision depending on collation. For now, + * convert everything into lower case and compare since by + * default collation in TSQL is case insensitive + * (SQL_Latin1_General_CP1_CI_AS) */ if (tolower(source[j]) != tolower(name[j - ptr])) { break; } } + /* * If no characters match, then return 0 */ @@ -3743,16 +3797,16 @@ TdsGetAndSetParamIndex(const char *name) /* * We shouldn't reach here other than SP_[CURSOR]EXEC SP request. * - * Assumption: In case of SP_[CURSOR]EXEC SP request, - * this function will be called only once during exec_bind_message. + * Assumption: In case of SP_[CURSOR]EXEC SP request, this function will + * be called only once during exec_bind_message. * * If in future we encounter a case, where above assumption doesn't work, - * then only option is to parse the complete query text to get the param index. - * This is kind of an optimization to save us from the complete query - * parsing based on above assumptions. + * then only option is to parse the complete query text to get the param + * index. This is kind of an optimization to save us from the complete + * query parsing based on above assumptions. */ Assert(req->spType == SP_EXECUTE || - req->spType == SP_CURSOREXEC); + req->spType == SP_CURSOREXEC); return ++(req->paramIndex); } @@ -3767,9 +3821,9 @@ TdsGetAndSetParamIndex(const char *name) bool TdsGetParamNames(List **pnames) { - TDSRequest request; - TDSRequestSP req; - ParameterToken token; + TDSRequest request; + TDSRequestSP req; + ParameterToken token; if ((TdsRequestCtrl == NULL) || (TdsRequestCtrl->request == NULL) || (TdsRequestCtrl->request->reqType != TDS_REQUEST_SP_NUMBER)) @@ -3792,17 +3846,16 @@ TdsGetParamNames(List **pnames) for (token = req->dataParameter; token != NULL; token = token->next) { - StringInfo name; + StringInfo name; TdsParamName item = palloc(sizeof(TdsParamNameData)); name = &(token->paramMeta.colName); /* - * When parameter names aren't given by the client driver, then - * simply return true. - * We make an assumption that all parameters will either have a name - * or not. There won't be a case where some parameters in a packet have name, - * while others don't. + * When parameter names aren't given by the client driver, then simply + * return true. We make an assumption that all parameters will either + * have a name or not. There won't be a case where some parameters in + * a packet have name, while others don't. */ if (name->len == 0) return true; @@ -3822,17 +3875,17 @@ TdsGetParamNames(List **pnames) void TDSLogDuration(char *query) { - char msec_str[32]; + char msec_str[32]; switch (check_log_duration(msec_str, false)) { case 1: ereport(LOG, (errmsg("Query duration: %s ms", msec_str), - errhidestmt(true))); + errhidestmt(true))); break; case 2: ereport(LOG, (errmsg("Query: %s duration: %s ms", - query, msec_str), errhidestmt(true))); + query, msec_str), errhidestmt(true))); break; default: break; @@ -3849,30 +3902,31 @@ TDSLogStatementCursorHandler(TDSRequestSP req, char *stmt, int option) if (pltsql_plugin_handler_ptr->stmt_needs_logging || TDS_DEBUG_ENABLED(TDS_DEBUG2)) { ErrorContextCallback *plerrcontext = error_context_stack; + error_context_stack = plerrcontext->previous; - + switch (option) { case PRINT_CURSOR_HANDLE: ereport(LOG, - (errmsg("sp_cursor handle: %d; statement: %s", - req->cursorHandle, stmt), - errhidestmt(true), - errdetail_params(req->nTotalParams))); + (errmsg("sp_cursor handle: %d; statement: %s", + req->cursorHandle, stmt), + errhidestmt(true), + errdetail_params(req->nTotalParams))); break; case PRINT_PREPARED_CURSOR_HANDLE: ereport(LOG, - (errmsg("sp_cursor prepared handle: %d; statement: %s", - req->cursorPreparedHandle, stmt), - errhidestmt(true), - errdetail_params(req->nTotalParams))); + (errmsg("sp_cursor prepared handle: %d; statement: %s", + req->cursorPreparedHandle, stmt), + errhidestmt(true), + errdetail_params(req->nTotalParams))); break; case PRINT_BOTH_CURSOR_HANDLE: ereport(LOG, - (errmsg("sp_cursor handle: %d; sp_cursor prepared handle: %d; statement: %s", - req->cursorHandle, req->cursorPreparedHandle, stmt), - errhidestmt(true), - errdetail_params(req->nTotalParams))); + (errmsg("sp_cursor handle: %d; sp_cursor prepared handle: %d; statement: %s", + req->cursorHandle, req->cursorPreparedHandle, stmt), + errhidestmt(true), + errdetail_params(req->nTotalParams))); break; default: break; @@ -3881,7 +3935,7 @@ TDSLogStatementCursorHandler(TDSRequestSP req, char *stmt, int option) pltsql_plugin_handler_ptr->stmt_needs_logging = false; error_context_stack = plerrcontext; } - + /* Print TDS log duration, if log_duration is set */ TDSLogDuration(stmt); } diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdssecure.c b/contrib/babelfishpg_tds/src/backend/tds/tdssecure.c index ce9fa8cb7a..72f9371d62 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tdssecure.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tdssecure.c @@ -38,14 +38,14 @@ #include "src/include/tds_secure.h" #include "src/include/tds_int.h" -int tds_ssl_min_protocol_version; -int tds_ssl_max_protocol_version; +int tds_ssl_min_protocol_version; +int tds_ssl_max_protocol_version; #ifdef USE_SSL /* * SslRead - TDS secure read function, similar to my_sock_read */ static int -SslRead(BIO *h, char *buf, int size) +SslRead(BIO * h, char *buf, int size) { int res = 0; @@ -72,9 +72,9 @@ SslRead(BIO *h, char *buf, int size) * filling in the data in buf called from openssl library */ static int -SslHandShakeRead(BIO *h, char *buf, int size) +SslHandShakeRead(BIO * h, char *buf, int size) { - int res = 0; + int res = 0; if ((res = SslRead(h, buf, size)) <= 0) return res; @@ -85,32 +85,38 @@ SslHandShakeRead(BIO *h, char *buf, int size) if (res < TDS_PACKET_HEADER_SIZE) { - int remainingRead = TDS_PACKET_HEADER_SIZE - res; - char tempBuf[TDS_PACKET_HEADER_SIZE]; - res = 0; - - /* Read the complete remaining of the header and throw away the bytes */ - while(res < remainingRead) - { - int tmp_res = 0; - if ((tmp_res = SslRead(h, tempBuf, remainingRead - res)) <= 0) - { - return tmp_res; - } - res += tmp_res; - } - - /* - * Read the actual data and return the res of the actual data read - * Don't worry if complete read, Openssl library will take care - */ - if ((res = SslRead(h, buf, size)) <= 0) - return res; + int remainingRead = TDS_PACKET_HEADER_SIZE - res; + char tempBuf[TDS_PACKET_HEADER_SIZE]; + + res = 0; + + /* + * Read the complete remaining of the header and throw away the + * bytes + */ + while (res < remainingRead) + { + int tmp_res = 0; + + if ((tmp_res = SslRead(h, tempBuf, remainingRead - res)) <= 0) + { + return tmp_res; + } + res += tmp_res; + } + + /* + * Read the actual data and return the res of the actual data read + * Don't worry if complete read, Openssl library will take care + */ + if ((res = SslRead(h, buf, size)) <= 0) + return res; } else { - int tmp_res = 0; - int i = TDS_PACKET_HEADER_SIZE; + int tmp_res = 0; + int i = TDS_PACKET_HEADER_SIZE; + for (i = TDS_PACKET_HEADER_SIZE; i < res; i++) { buf[i - TDS_PACKET_HEADER_SIZE] = buf[i]; @@ -119,9 +125,9 @@ SslHandShakeRead(BIO *h, char *buf, int size) /* * Read remaining of the data. Even if the read is less than - * requested size due to whatever reasons, we are good, since - * we are returning the correct res value, so caller will take - * care of reading the remaining data + * requested size due to whatever reasons, we are good, since we + * are returning the correct res value, so caller will take care + * of reading the remaining data */ if ((tmp_res = SslRead(h, &buf[res], TDS_PACKET_HEADER_SIZE)) <= 0) return tmp_res; @@ -136,9 +142,9 @@ SslHandShakeRead(BIO *h, char *buf, int size) * SslWrite - Tds secure write function, similar to my_sock_write. */ static int -SslWrite(BIO *h, const char *buf, int size) +SslWrite(BIO * h, const char *buf, int size) { - int res = 0; + int res = 0; res = secure_raw_write(((Port *) BIO_get_data(h)), buf, size); BIO_clear_retry_flags(h); @@ -160,12 +166,12 @@ SslWrite(BIO *h, const char *buf, int size) * is sent to client */ static int -SslHandShakeWrite(BIO *h, const char *buf, int size) +SslHandShakeWrite(BIO * h, const char *buf, int size) { - StringInfoData str; - char tmp[2]; - uint16_t tsize; - int res = 0; + StringInfoData str; + char tmp[2]; + uint16_t tsize; + int res = 0; /* Nothing to write */ if (size < 0) @@ -175,7 +181,7 @@ SslHandShakeWrite(BIO *h, const char *buf, int size) appendStringInfoChar(&str, TDS_PRELOGIN); appendStringInfoChar(&str, TDS_PACKET_HEADER_STATUS_EOM); tsize = pg_hton16(size + TDS_PACKET_HEADER_SIZE); - memcpy(&tmp,(char *) &tsize, 2); + memcpy(&tmp, (char *) &tsize, 2); appendStringInfoChar(&str, tmp[0]); appendStringInfoChar(&str, tmp[1]); @@ -191,23 +197,25 @@ SslHandShakeWrite(BIO *h, const char *buf, int size) /* Write the complete data */ while (res < size) { - int tmp_res = 0; + int tmp_res = 0; + if ((tmp_res = SslWrite(h, &buf[res], size - res)) <= 0) return tmp_res; res += tmp_res; } /* - * Below assertion should not be failed in ideal case. If it gets failed then - * it means that we wrote TDS HEADER and buf on the wire without any error above - * but number of bytes written is still less than TDS_PACKET_HEADER_SIZE which is - * unexpected in any case. + * Below assertion should not be failed in ideal case. If it gets failed + * then it means that we wrote TDS HEADER and buf on the wire without any + * error above but number of bytes written is still less than + * TDS_PACKET_HEADER_SIZE which is unexpected in any case. */ Assert(res >= TDS_PACKET_HEADER_SIZE); /* - * We are returning (res - TDS_PACKET_HEADER_SIZE) here because we are asked to write "size" number of bytes - * and callee does not know anything about TDS packet header. + * We are returning (res - TDS_PACKET_HEADER_SIZE) here because we are + * asked to write "size" number of bytes and callee does not know anything + * about TDS packet header. */ return (res - TDS_PACKET_HEADER_SIZE); } @@ -218,7 +226,7 @@ SslHandShakeWrite(BIO *h, const char *buf, int size) * for the initial SSL handshake */ BIO_METHOD * -TdsBioSecureSocket(BIO_METHOD *my_bio_methods) +TdsBioSecureSocket(BIO_METHOD * my_bio_methods) { if (my_bio_methods == NULL) { @@ -269,8 +277,7 @@ TdsFreeSslStruct(Port *port) if (port->ssl) { /* - * Don't call the SSL_shutdown - - * since it shutdowns the connection + * Don't call the SSL_shutdown - since it shutdowns the connection */ SSL_free(port->ssl); port->ssl = NULL; diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdssqlbatch.c b/contrib/babelfishpg_tds/src/backend/tds/tdssqlbatch.c index 49f61da9a0..db10653445 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tdssqlbatch.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tdssqlbatch.c @@ -32,16 +32,18 @@ TDSRequest GetSQLBatchRequest(StringInfo message) { - TDSRequestSQLBatch request; - int query_offset = 0; - int query_len; - uint32_t tdsVersion = GetClientTDSVersion(); + TDSRequestSQLBatch request; + int query_offset = 0; + int query_len; + uint32_t tdsVersion = GetClientTDSVersion(); TdsErrorContext->err_text = "Fetching SQL Batch Request"; + /* - * In the ALL_HEADERS rule, the Query Notifications header and the Transaction - * Descriptor header were introduced in TDS 7.2. We need to to Process them only - * for TDS versions more than or equal to 7.2, otherwise we do not increment the offset. + * In the ALL_HEADERS rule, the Query Notifications header and the + * Transaction Descriptor header were introduced in TDS 7.2. We need to to + * Process them only for TDS versions more than or equal to 7.2, otherwise + * we do not increment the offset. */ if (tdsVersion > TDS_VERSION_7_1_1) query_offset = ProcessStreamHeaders(message); @@ -54,10 +56,10 @@ GetSQLBatchRequest(StringInfo message) initStringInfo(&(request->query)); TdsUTF16toUTF8StringInfo(&(request->query), - &(message->data[query_offset]), - query_len); + &(message->data[query_offset]), + query_len); - return (TDSRequest)request; + return (TDSRequest) request; } /* @@ -67,9 +69,9 @@ GetSQLBatchRequest(StringInfo message) void ExecuteSQLBatch(char *query) { - LOCAL_FCINFO(fcinfo,1); + LOCAL_FCINFO(fcinfo, 1); InlineCodeBlock *codeblock = makeNode(InlineCodeBlock); - char *activity = psprintf("SQL_BATCH: %s", query); + char *activity = psprintf("SQL_BATCH: %s", query); TdsErrorContext->err_text = "Processing SQL Batch Request"; pgstat_report_activity(STATE_RUNNING, activity); @@ -77,7 +79,7 @@ ExecuteSQLBatch(char *query) /* Only source text matters to handler */ codeblock->source_text = query; - codeblock->langOid = 0; /* TODO does it matter */ + codeblock->langOid = 0; /* TODO does it matter */ codeblock->langIsTrusted = true; codeblock->atomic = false; @@ -87,7 +89,7 @@ ExecuteSQLBatch(char *query) fcinfo->args[0].isnull = false; PG_TRY(); { - pltsql_plugin_handler_ptr->sql_batch_callback (fcinfo); + pltsql_plugin_handler_ptr->sql_batch_callback(fcinfo); } PG_CATCH(); { @@ -106,6 +108,7 @@ ExecuteSQLBatch(char *query) if (pltsql_plugin_handler_ptr->stmt_needs_logging || TDS_DEBUG_ENABLED(TDS_DEBUG2)) { ErrorContextCallback *plerrcontext = error_context_stack; + error_context_stack = plerrcontext->previous; ereport(LOG, (errmsg("sql_batch statement: %s", query), @@ -128,7 +131,7 @@ ExecuteSQLBatch(char *query) void ProcessSQLBatchRequest(TDSRequest request) { - TDSRequestSQLBatch req = (TDSRequestSQLBatch)request; + TDSRequestSQLBatch req = (TDSRequestSQLBatch) request; ExecuteSQLBatch(req->query.data); MemoryContextSwitchTo(MessageContext); diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdstimestamp.c b/contrib/babelfishpg_tds/src/backend/tds/tdstimestamp.c index aff439a469..df2002138c 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tdstimestamp.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tdstimestamp.c @@ -19,30 +19,32 @@ #include "src/include/tds_timestamp.h" -int DaycountInMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; +int DaycountInMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; static inline -int IsLeap(int y) -{ - if ((y%100 != 0 && y%4 == 0) || y %400 == 0) - return 1; +int +IsLeap(int y) +{ + if ((y % 100 != 0 && y % 4 == 0) || y % 400 == 0) + return 1; - return 0; + return 0; } - + void TdsCheckDateValidity(DateADT result) { /* Limit to the same range that date_in() accepts. */ if (DATE_NOT_FINITE(result) || (!IS_VALID_DATE(result))) ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("date out of range"))); + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("date out of range"))); } static inline int CountLeapYears(struct pg_tm *t) { - int years = t->tm_year; + int years = t->tm_year; + if (t->tm_mon <= 2) years--; @@ -52,8 +54,9 @@ CountLeapYears(struct pg_tm *t) static inline int GetDayDifference(struct pg_tm *t1, struct pg_tm *t2) { - long int n1, n2; - int i; + long int n1, + n2; + int i; n1 = t1->tm_year * 365 + t1->tm_mday; for (i = 0; i < t1->tm_mon - 1; i++) @@ -71,9 +74,13 @@ GetDayDifference(struct pg_tm *t1, struct pg_tm *t2) uint32 TdsGetDayDifferenceHelper(int day, int mon, int year, bool isDateType) { - uint32 numDays = 0; - struct pg_tm tj, ti, *tm = &ti, *tt = &tj; - tm->tm_mday = day, tm->tm_mon = mon, tm->tm_year = year; + uint32 numDays = 0; + struct pg_tm tj, + ti, + *tm = &ti, + *tt = &tj; + + tm->tm_mday = day, tm->tm_mon = mon, tm->tm_year = year; tt->tm_mday = 1, tt->tm_mon = 1; if (isDateType) tt->tm_year = 1; @@ -89,24 +96,24 @@ GetDateFromDatum(Datum date, struct pg_tm *tm) if (!DATE_NOT_FINITE(date)) { j2date(date + POSTGRES_EPOCH_JDATE, - &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday)); + &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday)); } else ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("date out of range"))); + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("date out of range"))); } static inline void GetDatetimeFromDatum(Datum value, fsec_t *fsec, struct pg_tm *tm) { - Timestamp timestamp = (Timestamp)value; + Timestamp timestamp = (Timestamp) value; if (TIMESTAMP_NOT_FINITE(timestamp) || timestamp2tm(timestamp, NULL, tm, fsec, NULL, NULL) != 0) ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("Datetime out of range"))); + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("Datetime out of range"))); } /* @@ -115,8 +122,11 @@ GetDatetimeFromDatum(Datum value, fsec_t *fsec, struct pg_tm *tm) uint32 TdsDayDifference(Datum value) { - uint32 numDays = 0; - struct pg_tm tj, ti, *tm = &ti, *tt = &tj; + uint32 numDays = 0; + struct pg_tm tj, + ti, + *tm = &ti, + *tt = &tj; GetDateFromDatum(value, tm); @@ -140,8 +150,8 @@ GetNumDaysHelper(struct pg_tm *tm) tm->tm_mon = tm->tm_mday = 1; } else if ((tm->tm_mday == DaycountInMonth[tm->tm_mon - 1] && tm->tm_mon != 2) || - (tm->tm_mon == 2 && tm->tm_mday == 29 && IsLeap(tm->tm_year)) || - (tm->tm_mon == 2 && tm->tm_mday == 28 && !IsLeap(tm->tm_year))) + (tm->tm_mon == 2 && tm->tm_mday == 29 && IsLeap(tm->tm_year)) || + (tm->tm_mon == 2 && tm->tm_mday == 28 && !IsLeap(tm->tm_year))) { tm->tm_mon++; tm->tm_mday = 1; @@ -155,16 +165,19 @@ GetNumDaysHelper(struct pg_tm *tm) * and 1-1-1900 */ void -TdsTimeDifferenceSmalldatetime(Datum value, uint16 *numDays, - uint16 *numMins) +TdsTimeDifferenceSmalldatetime(Datum value, uint16 *numDays, + uint16 *numMins) { - struct pg_tm tj, ti, *tm = &ti, *tt = &tj; - fsec_t fsec = 0; + struct pg_tm tj, + ti, + *tm = &ti, + *tt = &tj; + fsec_t fsec = 0; GetDatetimeFromDatum(value, &fsec, tm); tt->tm_mday = 1, tt->tm_mon = 1, tt->tm_year = 1900; - *numDays = (uint16)GetDayDifference(tt, tm); + *numDays = (uint16) GetDayDifference(tt, tm); if (tm->tm_hour == 23 && tm->tm_min == 59 && tm->tm_sec == 59) { @@ -172,11 +185,11 @@ TdsTimeDifferenceSmalldatetime(Datum value, uint16 *numDays, GetNumDaysHelper(tm); (*numDays)++; } - else if ((tm->tm_sec == 29 && (fsec/1000) > 998) || tm->tm_sec > 29) + else if ((tm->tm_sec == 29 && (fsec / 1000) > 998) || tm->tm_sec > 29) tm->tm_min++; tm->tm_sec = 0; - *numMins = (tm->tm_hour * 60) + tm->tm_min; + *numMins = (tm->tm_hour * 60) + tm->tm_min; } /* @@ -185,21 +198,27 @@ TdsTimeDifferenceSmalldatetime(Datum value, uint16 *numDays, */ void TdsTimeDifferenceDatetime(Datum value, uint32 *numDays, - uint32 *numTicks) + uint32 *numTicks) { - uint32 milliCount = 0; - struct pg_tm tj, ti, *tm = &ti, *tt = &tj; - fsec_t fsec; - int msec = 0, unit = 0, round_val = 0; + uint32 milliCount = 0; + struct pg_tm tj, + ti, + *tm = &ti, + *tt = &tj; + fsec_t fsec; + int msec = 0, + unit = 0, + round_val = 0; + /* - * 1 tick = 1/300 sec = 3.3333333 ms - * babelfish uses tick count to accommodate millisecound count in 4 bytes + * 1 tick = 1/300 sec = 3.3333333 ms babelfish uses tick count to + * accommodate millisecound count in 4 bytes */ - double tick = 3.3333333; + double tick = 3.3333333; GetDatetimeFromDatum(value, &fsec, tm); tt->tm_mday = 1, tt->tm_mon = 1, tt->tm_year = 1900; - + *numDays = GetDayDifference(tt, tm); if (tm->tm_hour == 23 && tm->tm_min == 59 && tm->tm_sec == 59 && @@ -211,11 +230,12 @@ TdsTimeDifferenceDatetime(Datum value, uint32 *numDays, } else { - msec = (fsec/1000); + msec = (fsec / 1000); unit = msec % 10; /* - * millisecond value rounded to increments of .000, .003, or .007 seconds + * millisecond value rounded to increments of .000, .003, or .007 + * seconds */ switch (unit) { @@ -227,7 +247,11 @@ TdsTimeDifferenceDatetime(Datum value, uint32 *numDays, case 3: case 4: round_val = 3; - /* slightly different from default tick value at 7th decimal place */ + + /* + * slightly different from default tick value at 7th decimal + * place + */ tick = 3.3333332; break; case 5: @@ -245,9 +269,9 @@ TdsTimeDifferenceDatetime(Datum value, uint32 *numDays, msec = msec - unit + round_val; } milliCount = ((tm->tm_hour * 60 + tm->tm_min) * 60 + - tm->tm_sec) * 1000 + msec; - - *numTicks = (int)(milliCount / tick); + tm->tm_sec) * 1000 + msec; + + *numTicks = (int) (milliCount / tick); } /* @@ -255,23 +279,24 @@ TdsTimeDifferenceDatetime(Datum value, uint32 *numDays, * day of the date found by adding offset #days to day1 */ static inline -void RevoffsetDays(int offset, int *y, int *d, int *m) +void +RevoffsetDays(int offset, int *y, int *d, int *m) { - int month[13] = { 0, 31, 28, 31, 30, 31, 30, - 31, 31, 30, 31, 30, 31 }; - int i; - - if (IsLeap(*y)) - month[2] = 29; - - for (i = 1; i <= 12; i++) + int month[13] = {0, 31, 28, 31, 30, 31, 30, + 31, 31, 30, 31, 30, 31}; + int i; + + if (IsLeap(*y)) + month[2] = 29; + + for (i = 1; i <= 12; i++) { - if (offset <= month[i]) - break; - offset = offset - month[i]; + if (offset <= month[i]) + break; + offset = offset - month[i]; } - *d = offset; - *m = i; + *d = offset; + *m = i; } /* @@ -279,34 +304,36 @@ void RevoffsetDays(int offset, int *y, int *d, int *m) * retrieve target client date */ static inline -void CalculateTargetDate(int y1, int *d2, int *m2, int *y2, int x) +void +CalculateTargetDate(int y1, int *d2, int *m2, int *y2, int x) { - int y2days = 0; - int offset1 = 1; - int remDays = IsLeap(y1)?(366-offset1):(365-offset1); + int y2days = 0; + int offset1 = 1; + int remDays = IsLeap(y1) ? (366 - offset1) : (365 - offset1); - int offset2; - if (x <= remDays) + int offset2; + + if (x <= remDays) { - *y2 = y1; - offset2 = offset1 + x; + *y2 = y1; + offset2 = offset1 + x; } else { - x -= remDays; - *y2 = y1 + 1; - y2days = IsLeap(*y2)?366:365; - while (x >= y2days) + x -= remDays; + *y2 = y1 + 1; + y2days = IsLeap(*y2) ? 366 : 365; + while (x >= y2days) { x -= y2days; (*y2)++; - y2days = IsLeap(*y2)?366:365; + y2days = IsLeap(*y2) ? 366 : 365; } - offset2 = x; + offset2 = x; } - RevoffsetDays(offset2, y2, d2, m2); -} + RevoffsetDays(offset2, y2, d2, m2); +} /* * Get date info(day, month, year) from numDays elapsed from @@ -315,10 +342,13 @@ void CalculateTargetDate(int y1, int *d2, int *m2, int *y2, int x) void TdsTimeGetDatumFromDays(uint32 numDays, uint64 *val) { - int y1 = 1; - int d2 = 0, m2 = 0, y2 = 0; - int res; - struct pg_tm ti, *tm = &ti; + int y1 = 1; + int d2 = 0, + m2 = 0, + y2 = 0; + int res; + struct pg_tm ti, + *tm = &ti; CalculateTargetDate(y1, &d2, &m2, &y2, numDays); tm->tm_mday = d2; @@ -327,7 +357,7 @@ TdsTimeGetDatumFromDays(uint32 numDays, uint64 *val) res = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday); res -= POSTGRES_EPOCH_JDATE; - *val = (uint64)res; + *val = (uint64) res; } /* @@ -337,23 +367,29 @@ TdsTimeGetDatumFromDays(uint32 numDays, uint64 *val) * elapsed. */ static inline -void GetDatetimeFromDaysTicks(uint32 numDays, uint32 numTicks, - struct pg_tm *tm, fsec_t *fsec) +void +GetDatetimeFromDaysTicks(uint32 numDays, uint32 numTicks, + struct pg_tm *tm, fsec_t *fsec) { - int y1 = 1900; - int d2 = 0, m2 = 0, y2 = 0; - int min, hour, sec, numMilli = 0; + int y1 = 1900; + int d2 = 0, + m2 = 0, + y2 = 0; + int min, + hour, + sec, + numMilli = 0; CalculateTargetDate(y1, &d2, &m2, &y2, numDays); - numMilli = 3.33333333 * numTicks; - *fsec = (numMilli % 1000) * 1000; + numMilli = 3.33333333 * numTicks; + *fsec = (numMilli % 1000) * 1000; numMilli /= 1000; - /* need explicit assignment for JDBC prep-exec query - * where time datatype is sent as datetime in case - * sendTimeAsDateTime parameter is not explicitly set - * to false + /* + * need explicit assignment for JDBC prep-exec query where time datatype + * is sent as datetime in case sendTimeAsDateTime parameter is not + * explicitly set to false */ if (*fsec == 999000) { @@ -385,23 +421,28 @@ void TdsTimeGetDatumFromDatetime(uint32 numDays, uint32 numTicks, Timestamp *timestamp) { - struct pg_tm ti, *tm = &ti; - fsec_t fsec; - + struct pg_tm ti, + *tm = &ti; + fsec_t fsec; + GetDatetimeFromDaysTicks(numDays, numTicks, tm, &fsec); if (tm2timestamp(tm, fsec, NULL, timestamp) != 0) - ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("timestamp out of range"))); + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); } static inline -void GetDatetimeFromDaysMins(uint16 numDays, uint16 numMins, +void +GetDatetimeFromDaysMins(uint16 numDays, uint16 numMins, struct pg_tm *tm, fsec_t *fsec) { - int y1 = 1900; - int d2 = 0, m2 = 0, y2 = 0; - int min, hour; + int y1 = 1900; + int d2 = 0, + m2 = 0, + y2 = 0; + int min, + hour; CalculateTargetDate(y1, &d2, &m2, &y2, numDays); @@ -421,65 +462,77 @@ void GetDatetimeFromDaysMins(uint16 numDays, uint16 numMins, */ void TdsTimeGetDatumFromSmalldatetime(uint16 numDays, uint16 numMins, - Timestamp *timestamp) + Timestamp *timestamp) { - struct pg_tm ti, *tm = &ti; - fsec_t fsec = 0; + struct pg_tm ti, + *tm = &ti; + fsec_t fsec = 0; GetDatetimeFromDaysMins(numDays, numMins, tm, &fsec); tm->tm_sec = 0; if (tm2timestamp(tm, fsec, NULL, timestamp) != 0) ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("timestamp out of range"))); + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); } void TdsGetDayTimeFromTimestamp(Timestamp value, uint32 *numDays, uint64 *numSec, - int scale) + int scale) { - struct pg_tm ti, tj, *tm = &ti, *tt = &tj; + struct pg_tm ti, + tj, + *tm = &ti, + *tt = &tj; fsec_t fsec = 0; double res = 0; - if (timestamp2tm((Timestamp)value, NULL, tm, &fsec, NULL, NULL) != 0) - ereport(ERROR,(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("timestamp out of range"))); + if (timestamp2tm((Timestamp) value, NULL, tm, &fsec, NULL, NULL) != 0) + ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); tt->tm_mday = 1, tt->tm_mon = 1, tt->tm_year = 1; - *numDays = (uint32)GetDayDifference(tt, tm); + *numDays = (uint32) GetDayDifference(tt, tm); - res = (double)(((tm->tm_hour * 60 + tm->tm_min) * 60 + tm->tm_sec) + - ((double)fsec/ 1000000)); + res = (double) (((tm->tm_hour * 60 + tm->tm_min) * 60 + tm->tm_sec) + + ((double) fsec / 1000000)); while (scale--) res *= 10; /* Round res to the nearest integer */ res += 0.5; - - *numSec = (uint64_t)res; + + *numSec = (uint64_t) res; } -void TdsGetTimestampFromDayTime(uint32 numDays, uint64 numMicro, int tz, - Timestamp *timestamp, int scale) +void +TdsGetTimestampFromDayTime(uint32 numDays, uint64 numMicro, int tz, + Timestamp *timestamp, int scale) { - struct pg_tm ti, *tm = &ti; + struct pg_tm ti, + *tm = &ti; fsec_t fsec; - int y1 = 1; - int d2 = 0, m2 = 0, y2 = 0, min, hour, sec; + int y1 = 1; + int d2 = 0, + m2 = 0, + y2 = 0, + min, + hour, + sec; double result; CalculateTargetDate(y1, &d2, &m2, &y2, numDays); - result = (double)numMicro; + result = (double) numMicro; while (scale--) result /= 10; result *= 1000000; - + /* - * Casting result to unint64_t will always round it down to the nearest integer (similar - * to what floor() does). Instead, we should round it to the nearest integer. + * Casting result to unint64_t will always round it down to the nearest + * integer (similar to what floor() does). Instead, we should round it to + * the nearest integer. */ - numMicro = (result - (uint64_t)result <= 0.5) ? (uint64_t)result : (uint64_t)result + 1; + numMicro = (result - (uint64_t) result <= 0.5) ? (uint64_t) result : (uint64_t) result + 1; fsec = numMicro % 1000000; numMicro /= 1000000; @@ -498,8 +551,6 @@ void TdsGetTimestampFromDayTime(uint32 numDays, uint64 numMicro, int tz, if (tm2timestamp(tm, fsec, &tz, timestamp) != 0) ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("timestamp out of range"))); + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); } - - diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdstypeio.c b/contrib/babelfishpg_tds/src/backend/tds/tdstypeio.c index 731249ae75..fade2ed106 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tdstypeio.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tdstypeio.c @@ -28,9 +28,10 @@ #include "parser/scansup.h" #include "utils/cash.h" #include "utils/hsearch.h" -#include "utils/builtins.h" /* for format_type_be() */ +#include "utils/builtins.h" /* for format_type_be() */ #include "utils/guc.h" -#include "utils/lsyscache.h" /* for getTypeInputInfo() and OidInputFunctionCall()*/ +#include "utils/lsyscache.h" /* for getTypeInputInfo() and + * OidInputFunctionCall() */ #include "utils/numeric.h" #include "utils/snapmgr.h" #include "utils/syscache.h" @@ -44,7 +45,8 @@ #include "src/include/err_handler.h" #include "src/include/tds_instr.h" -#include "tds_data_map.c" /* include tables that used to initialize hashmaps */ +#include "tds_data_map.c" /* include tables that used to initialize + * hashmaps */ #define TDS_RETURN_DATUM(x) return ((Datum) (x)) @@ -59,7 +61,10 @@ do { \ /* * macros to store length of metadata (including metadata for base type) for sqlvariant datatypes. */ -#define VARIANT_TYPE_METALEN_FOR_NUM_DATATYPES 2 /* for BIT, TINYINT, SMALLINT, INT, BIGINT, REAL, FLOAT, [SMALL]MONEY and UID */ +#define VARIANT_TYPE_METALEN_FOR_NUM_DATATYPES 2 /* for BIT, TINYINT, + * SMALLINT, INT, BIGINT, + * REAL, FLOAT, + * [SMALL]MONEY and UID */ #define VARIANT_TYPE_METALEN_FOR_CHAR_DATATYPES 9 /* for [N][VAR]CHAR */ #define VARIANT_TYPE_METALEN_FOR_BIN_DATATYPES 4 /* for [VAR]BINARY */ #define VARIANT_TYPE_METALEN_FOR_NUMERIC_DATATYPES 5 /* for NUMERIC */ @@ -73,7 +78,10 @@ do { \ /* * macros to store length of metadata for base type of sqlvariant datatype. */ -#define VARIANT_TYPE_BASE_METALEN_FOR_NUM_DATATYPES 0 /* for BIT, TINYINT, SMALLINT, INT, BIGINT, REAL, FLOAT, [SMALL]MONEY and UID */ +#define VARIANT_TYPE_BASE_METALEN_FOR_NUM_DATATYPES 0 /* for BIT, TINYINT, + * SMALLINT, INT, + * BIGINT, REAL, FLOAT, + * [SMALL]MONEY and UID */ #define VARIANT_TYPE_BASE_METALEN_FOR_CHAR_DATATYPES 7 /* for [N][VAR]CHAR */ #define VARIANT_TYPE_BASE_METALEN_FOR_BIN_DATATYPES 2 /* for [VAR]BINARY */ #define VARIANT_TYPE_BASE_METALEN_FOR_NUMERIC_DATATYPES 2 /* for NUMERIC */ @@ -84,41 +92,41 @@ do { \ #define VARIANT_TYPE_BASE_METALEN_FOR_DATETIME2 1 /* for DATETIME2 */ #define VARIANT_TYPE_BASE_METALEN_FOR_DATETIMEOFFSET 1 /* for DATETIMEOFFSET */ -static HTAB *functionInfoCacheByOid = NULL; -static HTAB *functionInfoCacheByTdsId = NULL; +static HTAB *functionInfoCacheByOid = NULL; +static HTAB *functionInfoCacheByTdsId = NULL; -static HTAB *TdsEncodingInfoCacheByLCID = NULL; +static HTAB *TdsEncodingInfoCacheByLCID = NULL; -void CopyMsgBytes(StringInfo msg, char *buf, int datalen); -int GetMsgByte(StringInfo msg); -const char * GetMsgBytes(StringInfo msg, int datalen); +void CopyMsgBytes(StringInfo msg, char *buf, int datalen); +int GetMsgByte(StringInfo msg); +const char *GetMsgBytes(StringInfo msg, int datalen); unsigned int GetMsgInt(StringInfo msg, int b); -int64 GetMsgInt64(StringInfo msg); -uint128 GetMsgUInt128(StringInfo msg); -float4 GetMsgFloat4(StringInfo msg); -float8 GetMsgFloat8(StringInfo msg); +int64 GetMsgInt64(StringInfo msg); +uint128 GetMsgUInt128(StringInfo msg); +float4 GetMsgFloat4(StringInfo msg); +float8 GetMsgFloat8(StringInfo msg); static void SwapData(StringInfo buf, int st, int end); static Datum TdsAnyToServerEncodingConversion(pg_enc encoding, char *str, int len, uint8_t tdsColDataType); -int TdsUTF16toUTF8XmlResult(StringInfo buf, void **resultPtr); - -Datum TdsTypeBitToDatum(StringInfo buf); -Datum TdsTypeIntegerToDatum(StringInfo buf, int maxLen); -Datum TdsTypeFloatToDatum(StringInfo buf, int maxLen); -Datum TdsTypeVarcharToDatum(StringInfo buf, pg_enc encoding, uint8_t tdsColDataType); -Datum TdsTypeNCharToDatum(StringInfo buf); -Datum TdsTypeNumericToDatum(StringInfo buf, int scale); -Datum TdsTypeVarbinaryToDatum(StringInfo buf); -Datum TdsTypeDatetime2ToDatum(StringInfo buf, int scale, int len); -Datum TdsTypeDatetimeToDatum(StringInfo buf); -Datum TdsTypeSmallDatetimeToDatum(StringInfo buf); -Datum TdsTypeDateToDatum(StringInfo buf); -Datum TdsTypeTimeToDatum(StringInfo buf, int scale, int len); -Datum TdsTypeDatetimeoffsetToDatum(StringInfo buf, int scale, int len); -Datum TdsTypeMoneyToDatum(StringInfo buf); -Datum TdsTypeSmallMoneyToDatum(StringInfo buf); -Datum TdsTypeXMLToDatum(StringInfo buf); -Datum TdsTypeUIDToDatum(StringInfo buf); -Datum TdsTypeSqlVariantToDatum(StringInfo buf); +int TdsUTF16toUTF8XmlResult(StringInfo buf, void **resultPtr); + +Datum TdsTypeBitToDatum(StringInfo buf); +Datum TdsTypeIntegerToDatum(StringInfo buf, int maxLen); +Datum TdsTypeFloatToDatum(StringInfo buf, int maxLen); +Datum TdsTypeVarcharToDatum(StringInfo buf, pg_enc encoding, uint8_t tdsColDataType); +Datum TdsTypeNCharToDatum(StringInfo buf); +Datum TdsTypeNumericToDatum(StringInfo buf, int scale); +Datum TdsTypeVarbinaryToDatum(StringInfo buf); +Datum TdsTypeDatetime2ToDatum(StringInfo buf, int scale, int len); +Datum TdsTypeDatetimeToDatum(StringInfo buf); +Datum TdsTypeSmallDatetimeToDatum(StringInfo buf); +Datum TdsTypeDateToDatum(StringInfo buf); +Datum TdsTypeTimeToDatum(StringInfo buf, int scale, int len); +Datum TdsTypeDatetimeoffsetToDatum(StringInfo buf, int scale, int len); +Datum TdsTypeMoneyToDatum(StringInfo buf); +Datum TdsTypeSmallMoneyToDatum(StringInfo buf); +Datum TdsTypeXMLToDatum(StringInfo buf); +Datum TdsTypeUIDToDatum(StringInfo buf); +Datum TdsTypeSqlVariantToDatum(StringInfo buf); static void FetchTvpTypeOid(const ParameterToken token, char *tvpName); @@ -131,8 +139,8 @@ typedef struct FunctionCacheByTdsIdKey typedef struct FunctionCacheByTdsIdEntry { - FunctionCacheByTdsIdKey key; - TdsIoFunctionData data; + FunctionCacheByTdsIdKey key; + TdsIoFunctionData data; } FunctionCacheByTdsIdEntry; /* @@ -146,36 +154,65 @@ getSendFunc(int funcId) { switch (funcId) { - case TDS_SEND_BIT: return TdsSendTypeBit; - case TDS_SEND_TINYINT: return TdsSendTypeTinyint; - case TDS_SEND_SMALLINT: return TdsSendTypeSmallint; - case TDS_SEND_INTEGER: return TdsSendTypeInteger; - case TDS_SEND_BIGINT: return TdsSendTypeBigint; - case TDS_SEND_FLOAT4: return TdsSendTypeFloat4; - case TDS_SEND_FLOAT8: return TdsSendTypeFloat8; - case TDS_SEND_VARCHAR: return TdsSendTypeVarchar; - case TDS_SEND_NVARCHAR: return TdsSendTypeNVarchar; - case TDS_SEND_MONEY: return TdsSendTypeMoney; - case TDS_SEND_SMALLMONEY: return TdsSendTypeSmallmoney; - case TDS_SEND_CHAR: return TdsSendTypeChar; - case TDS_SEND_NCHAR: return TdsSendTypeNChar; - case TDS_SEND_SMALLDATETIME: return TdsSendTypeSmalldatetime; - case TDS_SEND_TEXT: return TdsSendTypeText; - case TDS_SEND_NTEXT: return TdsSendTypeNText; - case TDS_SEND_DATE: return TdsSendTypeDate; - case TDS_SEND_DATETIME: return TdsSendTypeDatetime; - case TDS_SEND_NUMERIC: return TdsSendTypeNumeric; - case TDS_SEND_IMAGE: return TdsSendTypeImage; - case TDS_SEND_BINARY: return TdsSendTypeBinary; - case TDS_SEND_VARBINARY: return TdsSendTypeVarbinary; - case TDS_SEND_UNIQUEIDENTIFIER: return TdsSendTypeUniqueIdentifier; - case TDS_SEND_TIME: return TdsSendTypeTime; - case TDS_SEND_DATETIME2: return TdsSendTypeDatetime2; - case TDS_SEND_XML: return TdsSendTypeXml; - case TDS_SEND_SQLVARIANT: return TdsSendTypeSqlvariant; - case TDS_SEND_DATETIMEOFFSET: return TdsSendTypeDatetimeoffset; - /* TODO: should Assert here once all types are implemented */ - default: return NULL; + case TDS_SEND_BIT: + return TdsSendTypeBit; + case TDS_SEND_TINYINT: + return TdsSendTypeTinyint; + case TDS_SEND_SMALLINT: + return TdsSendTypeSmallint; + case TDS_SEND_INTEGER: + return TdsSendTypeInteger; + case TDS_SEND_BIGINT: + return TdsSendTypeBigint; + case TDS_SEND_FLOAT4: + return TdsSendTypeFloat4; + case TDS_SEND_FLOAT8: + return TdsSendTypeFloat8; + case TDS_SEND_VARCHAR: + return TdsSendTypeVarchar; + case TDS_SEND_NVARCHAR: + return TdsSendTypeNVarchar; + case TDS_SEND_MONEY: + return TdsSendTypeMoney; + case TDS_SEND_SMALLMONEY: + return TdsSendTypeSmallmoney; + case TDS_SEND_CHAR: + return TdsSendTypeChar; + case TDS_SEND_NCHAR: + return TdsSendTypeNChar; + case TDS_SEND_SMALLDATETIME: + return TdsSendTypeSmalldatetime; + case TDS_SEND_TEXT: + return TdsSendTypeText; + case TDS_SEND_NTEXT: + return TdsSendTypeNText; + case TDS_SEND_DATE: + return TdsSendTypeDate; + case TDS_SEND_DATETIME: + return TdsSendTypeDatetime; + case TDS_SEND_NUMERIC: + return TdsSendTypeNumeric; + case TDS_SEND_IMAGE: + return TdsSendTypeImage; + case TDS_SEND_BINARY: + return TdsSendTypeBinary; + case TDS_SEND_VARBINARY: + return TdsSendTypeVarbinary; + case TDS_SEND_UNIQUEIDENTIFIER: + return TdsSendTypeUniqueIdentifier; + case TDS_SEND_TIME: + return TdsSendTypeTime; + case TDS_SEND_DATETIME2: + return TdsSendTypeDatetime2; + case TDS_SEND_XML: + return TdsSendTypeXml; + case TDS_SEND_SQLVARIANT: + return TdsSendTypeSqlvariant; + case TDS_SEND_DATETIMEOFFSET: + return TdsSendTypeDatetimeoffset; + /* TODO: should Assert here once all types are implemented */ + default: + return NULL; } } @@ -190,37 +227,67 @@ getRecvFunc(int funcId) { switch (funcId) { - case TDS_RECV_BIT: return TdsRecvTypeBit; - case TDS_RECV_TINYINT: return TdsRecvTypeTinyInt; - case TDS_RECV_SMALLINT: return TdsRecvTypeSmallInt; - case TDS_RECV_INTEGER: return TdsRecvTypeInteger; - case TDS_RECV_BIGINT: return TdsRecvTypeBigInt; - case TDS_RECV_FLOAT4: return TdsRecvTypeFloat4; - case TDS_RECV_FLOAT8: return TdsRecvTypeFloat8; - case TDS_RECV_VARCHAR: return TdsRecvTypeVarchar; - case TDS_RECV_NVARCHAR: return TdsRecvTypeNVarchar; - case TDS_RECV_MONEY: return TdsRecvTypeMoney; - case TDS_RECV_SMALLMONEY: return TdsRecvTypeSmallmoney; - case TDS_RECV_CHAR: return TdsRecvTypeChar; - case TDS_RECV_NCHAR: return TdsRecvTypeNChar; - case TDS_RECV_SMALLDATETIME: return TdsRecvTypeSmalldatetime; - case TDS_RECV_TEXT: return TdsRecvTypeText; - case TDS_RECV_NTEXT: return TdsRecvTypeNText; - case TDS_RECV_DATE: return TdsRecvTypeDate; - case TDS_RECV_DATETIME: return TdsRecvTypeDatetime; - case TDS_RECV_NUMERIC: return TdsRecvTypeNumeric; - case TDS_RECV_IMAGE: return TdsRecvTypeBinary; - case TDS_RECV_BINARY: return TdsRecvTypeBinary; - case TDS_RECV_VARBINARY: return TdsRecvTypeVarbinary; - case TDS_RECV_UNIQUEIDENTIFIER: return TdsRecvTypeUniqueIdentifier; - case TDS_RECV_TIME: return TdsRecvTypeTime; - case TDS_RECV_DATETIME2: return TdsRecvTypeDatetime2; - case TDS_RECV_XML: return TdsRecvTypeXml; - case TDS_RECV_TABLE: return TdsRecvTypeTable; - case TDS_RECV_SQLVARIANT: return TdsRecvTypeSqlvariant; - case TDS_RECV_DATETIMEOFFSET: return TdsRecvTypeDatetimeoffset; - /* TODO: should Assert here once all types are implemented */ - default: return NULL; + case TDS_RECV_BIT: + return TdsRecvTypeBit; + case TDS_RECV_TINYINT: + return TdsRecvTypeTinyInt; + case TDS_RECV_SMALLINT: + return TdsRecvTypeSmallInt; + case TDS_RECV_INTEGER: + return TdsRecvTypeInteger; + case TDS_RECV_BIGINT: + return TdsRecvTypeBigInt; + case TDS_RECV_FLOAT4: + return TdsRecvTypeFloat4; + case TDS_RECV_FLOAT8: + return TdsRecvTypeFloat8; + case TDS_RECV_VARCHAR: + return TdsRecvTypeVarchar; + case TDS_RECV_NVARCHAR: + return TdsRecvTypeNVarchar; + case TDS_RECV_MONEY: + return TdsRecvTypeMoney; + case TDS_RECV_SMALLMONEY: + return TdsRecvTypeSmallmoney; + case TDS_RECV_CHAR: + return TdsRecvTypeChar; + case TDS_RECV_NCHAR: + return TdsRecvTypeNChar; + case TDS_RECV_SMALLDATETIME: + return TdsRecvTypeSmalldatetime; + case TDS_RECV_TEXT: + return TdsRecvTypeText; + case TDS_RECV_NTEXT: + return TdsRecvTypeNText; + case TDS_RECV_DATE: + return TdsRecvTypeDate; + case TDS_RECV_DATETIME: + return TdsRecvTypeDatetime; + case TDS_RECV_NUMERIC: + return TdsRecvTypeNumeric; + case TDS_RECV_IMAGE: + return TdsRecvTypeBinary; + case TDS_RECV_BINARY: + return TdsRecvTypeBinary; + case TDS_RECV_VARBINARY: + return TdsRecvTypeVarbinary; + case TDS_RECV_UNIQUEIDENTIFIER: + return TdsRecvTypeUniqueIdentifier; + case TDS_RECV_TIME: + return TdsRecvTypeTime; + case TDS_RECV_DATETIME2: + return TdsRecvTypeDatetime2; + case TDS_RECV_XML: + return TdsRecvTypeXml; + case TDS_RECV_TABLE: + return TdsRecvTypeTable; + case TDS_RECV_SQLVARIANT: + return TdsRecvTypeSqlvariant; + case TDS_RECV_DATETIMEOFFSET: + return TdsRecvTypeDatetimeoffset; + /* TODO: should Assert here once all types are implemented */ + default: + return NULL; } } @@ -230,34 +297,38 @@ static void init_collation_callbacks(void) { collation_callbacks **callbacks_ptr; - callbacks_ptr = (collation_callbacks **) find_rendezvous_variable("collation_callbacks"); + + callbacks_ptr = (collation_callbacks **) find_rendezvous_variable("collation_callbacks"); collation_callbacks_ptr = *callbacks_ptr; } -char * TdsEncodingConversion(const char *s, int len, pg_enc src_encoding, pg_enc dest_encoding, int *encodedByteLen) +char * +TdsEncodingConversion(const char *s, int len, pg_enc src_encoding, pg_enc dest_encoding, int *encodedByteLen) { if (!collation_callbacks_ptr) init_collation_callbacks(); if (collation_callbacks_ptr && collation_callbacks_ptr->EncodingConversion) - return (*collation_callbacks_ptr->EncodingConversion)(s, len, src_encoding, dest_encoding, encodedByteLen); + return (*collation_callbacks_ptr->EncodingConversion) (s, len, src_encoding, dest_encoding, encodedByteLen); else /* unlikely */ - ereport(ERROR, + ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("Could not encode the string to the client encoding"))); } -coll_info_t TdsLookupCollationTableCallback(Oid oid) +coll_info_t +TdsLookupCollationTableCallback(Oid oid) { if (!collation_callbacks_ptr) init_collation_callbacks(); if (collation_callbacks_ptr && collation_callbacks_ptr->lookup_collation_table_callback) - return (*collation_callbacks_ptr->lookup_collation_table_callback)(oid); + return (*collation_callbacks_ptr->lookup_collation_table_callback) (oid); else { coll_info_t invalidCollInfo; + invalidCollInfo.oid = InvalidOid; return invalidCollInfo; } @@ -268,23 +339,24 @@ coll_info_t TdsLookupCollationTableCallback(Oid oid) static int xmlChar_to_encoding(const xmlChar *encoding_name) { - int encoding = pg_char_to_encoding((const char *)encoding_name); + int encoding = pg_char_to_encoding((const char *) encoding_name); if (encoding < 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid encoding name \"%s\"", - (const char *)encoding_name))); + (const char *) encoding_name))); return encoding; } #endif -int TdsUTF16toUTF8XmlResult(StringInfo buf, void **resultPtr) +int +TdsUTF16toUTF8XmlResult(StringInfo buf, void **resultPtr) { - char *str; - int nbytes; + char *str; + int nbytes; StringInfoData tempBuf; - void *result; + void *result; initStringInfo(&tempBuf); enlargeStringInfo(&tempBuf, buf->len); @@ -293,7 +365,7 @@ int TdsUTF16toUTF8XmlResult(StringInfo buf, void **resultPtr) nbytes = buf->len - buf->cursor; - str = (char *)GetMsgBytes(buf, nbytes); + str = (char *) GetMsgBytes(buf, nbytes); result = palloc0(nbytes + 1 + VARHDRSZ); SET_VARSIZE(result, nbytes + VARHDRSZ); @@ -313,8 +385,8 @@ int TdsUTF16toUTF8XmlResult(StringInfo buf, void **resultPtr) static Datum TdsAnyToServerEncodingConversion(pg_enc encoding, char *str, int len, uint8_t tdsColDataType) { - char *pstring; - Datum pval; + char *pstring; + Datum pval; int actualLen; /* The dest_encoding will always be UTF8 for Babelfish */ @@ -334,7 +406,7 @@ TdsAnyToServerEncodingConversion(pg_enc encoding, char *str, int len, uint8_t td default: ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("TdsAnyToServerEncodingConversion is not supported for Tds Type: %d", tdsColDataType))); + errmsg("TdsAnyToServerEncodingConversion is not supported for Tds Type: %d", tdsColDataType))); break; } @@ -362,62 +434,67 @@ TdsResetCache(void) void TdsLoadEncodingLCIDCache(void) { - HASHCTL hashCtl; + HASHCTL hashCtl; if (TdsEncodingInfoCacheByLCID == NULL) { - /* Create the LCID - Encoding (code page in tsql's term) hash table in our TDS memory context */ + /* + * Create the LCID - Encoding (code page in tsql's term) hash table in + * our TDS memory context + */ MemSet(&hashCtl, 0, sizeof(hashCtl)); hashCtl.keysize = sizeof(int); hashCtl.entrysize = 2 * sizeof(int); hashCtl.hcxt = TdsMemoryContext; TdsEncodingInfoCacheByLCID = hash_create("LCID - Encoding map cache", - SPI_processed, - &hashCtl, - HASH_ELEM | HASH_CONTEXT | HASH_BLOBS); + SPI_processed, + &hashCtl, + HASH_ELEM | HASH_CONTEXT | HASH_BLOBS); + /* - * Load LCID - Encoding pair into our hash table. - */ + * Load LCID - Encoding pair into our hash table. + */ for (int i = 0; i < TdsLCIDToEncodingMap_datasize; i++) { - int lcid; + int lcid; TdsLCIDToEncodingMapInfo mInfo; - /* Create the hash entry for lookup by LCID*/ + /* Create the hash entry for lookup by LCID */ lcid = TdsLCIDToEncodingMap_data[i].lcid; - mInfo = (TdsLCIDToEncodingMapInfo)hash_search(TdsEncodingInfoCacheByLCID, - &lcid, - HASH_ENTER, - NULL); + mInfo = (TdsLCIDToEncodingMapInfo) hash_search(TdsEncodingInfoCacheByLCID, + &lcid, + HASH_ENTER, + NULL); mInfo->enc = TdsLCIDToEncodingMap_data[i].enc; } } } -/* - * TdsLookupEncodingByLCID - LCID - Encoding lookup +/* + * TdsLookupEncodingByLCID - LCID - Encoding lookup */ int TdsLookupEncodingByLCID(int lcid) { - bool found; + bool found; TdsLCIDToEncodingMapInfo mInfo; - mInfo = (TdsLCIDToEncodingMapInfo)hash_search(TdsEncodingInfoCacheByLCID, - &lcid, - HASH_FIND, - &found); + mInfo = (TdsLCIDToEncodingMapInfo) hash_search(TdsEncodingInfoCacheByLCID, + &lcid, + HASH_FIND, + &found); /* - * TODO: which encoding by default we should consider - * if appropriate Encoding is not found. + * TODO: which encoding by default we should consider if appropriate + * Encoding is not found. */ if (!found) { - mInfo = (TdsLCIDToEncodingMapInfo)hash_search(TdsEncodingInfoCacheByLCID, - &TdsDefaultLcid, - HASH_FIND, - &found); + mInfo = (TdsLCIDToEncodingMapInfo) hash_search(TdsEncodingInfoCacheByLCID, + &TdsDefaultLcid, + HASH_FIND, + &found); + /* * could not find encoding corresponding to default lcid still. */ @@ -430,8 +507,8 @@ TdsLookupEncodingByLCID(int lcid) void TdsLoadTypeFunctionCache(void) { - HASHCTL hashCtl; - Oid sys_nspoid = get_namespace_oid("sys", false); + HASHCTL hashCtl; + Oid sys_nspoid = get_namespace_oid("sys", false); /* Create the function info hash table in our TDS memory context */ if (functionInfoCacheByOid == NULL) /* create hash table */ @@ -441,46 +518,47 @@ TdsLoadTypeFunctionCache(void) hashCtl.entrysize = sizeof(TdsIoFunctionData); hashCtl.hcxt = TdsMemoryContext; functionInfoCacheByOid = hash_create("IO function info cache", - SPI_processed, - &hashCtl, - HASH_ELEM | HASH_CONTEXT | HASH_BLOBS); + SPI_processed, + &hashCtl, + HASH_ELEM | HASH_CONTEXT | HASH_BLOBS); } - if (functionInfoCacheByTdsId == NULL) /* create hash table */ + if (functionInfoCacheByTdsId == NULL) /* create hash table */ { MemSet(&hashCtl, 0, sizeof(hashCtl)); hashCtl.keysize = sizeof(FunctionCacheByTdsIdKey); hashCtl.entrysize = sizeof(FunctionCacheByTdsIdEntry); hashCtl.hcxt = TdsMemoryContext; functionInfoCacheByTdsId = hash_create("IO function info cache by TDS id", - SPI_processed, - &hashCtl, - HASH_ELEM | HASH_CONTEXT | HASH_BLOBS); + SPI_processed, + &hashCtl, + HASH_ELEM | HASH_CONTEXT | HASH_BLOBS); } + /* * Load the contents of the table into our hash table. */ for (int i = 0; i < TdsIoFunctionRawData_datasize; i++) { - Oid typeoid; - Oid basetypeoid; - Oid nspoid; - TdsIoFunctionInfo finfo; - FunctionCacheByTdsIdKey fc2key; - FunctionCacheByTdsIdEntry *fc2ent; + Oid typeoid; + Oid basetypeoid; + Oid nspoid; + TdsIoFunctionInfo finfo; + FunctionCacheByTdsIdKey fc2key; + FunctionCacheByTdsIdEntry *fc2ent; nspoid = strcmp(TdsIoFunctionRawData_data[i].typnsp, "sys") == 0 ? sys_nspoid : PG_CATALOG_NAMESPACE; - typeoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, - CStringGetDatum(TdsIoFunctionRawData_data[i].typname), ObjectIdGetDatum(nspoid)); + typeoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, + CStringGetDatum(TdsIoFunctionRawData_data[i].typname), ObjectIdGetDatum(nspoid)); if (OidIsValid(typeoid)) { basetypeoid = getBaseType(typeoid); - finfo = (TdsIoFunctionInfo)hash_search(functionInfoCacheByOid, - &typeoid, - HASH_ENTER, - NULL); + finfo = (TdsIoFunctionInfo) hash_search(functionInfoCacheByOid, + &typeoid, + HASH_ENTER, + NULL); finfo->ttmbasetypeid = typeoid == basetypeoid ? 0 : basetypeoid; finfo->ttmtdstypeid = TdsIoFunctionRawData_data[i].ttmtdstypeid; finfo->ttmtdstypelen = TdsIoFunctionRawData_data[i].ttmtdstypelen; @@ -494,12 +572,14 @@ TdsLoadTypeFunctionCache(void) fc2key.tdstypeid = TdsIoFunctionRawData_data[i].ttmtdstypeid; fc2key.tdstypelen = TdsIoFunctionRawData_data[i].ttmtdstypelen; - if(TdsIoFunctionRawData_data[i].ttmrecvfunc != TDS_RECV_INVALID) /* Do not load the Receiver function if its Invalid. */ + if (TdsIoFunctionRawData_data[i].ttmrecvfunc != TDS_RECV_INVALID) /* Do not load the + * Receiver function if + * its Invalid. */ { - fc2ent = (FunctionCacheByTdsIdEntry *)hash_search(functionInfoCacheByTdsId, - &fc2key, - HASH_ENTER, - NULL); + fc2ent = (FunctionCacheByTdsIdEntry *) hash_search(functionInfoCacheByTdsId, + &fc2key, + HASH_ENTER, + NULL); finfo = &(fc2ent->data); finfo->ttmtypeid = typeoid; finfo->ttmbasetypeid = basetypeoid; @@ -515,17 +595,20 @@ TdsLoadTypeFunctionCache(void) } { - /* Load Table Valued Paramerter since we can't have a static oid mapping for it.*/ + /* + * Load Table Valued Paramerter since we can't have a static oid + * mapping for it. + */ TdsIoFunctionInfo finfo_table; FunctionCacheByTdsIdKey fc2key_table; FunctionCacheByTdsIdEntry *fc2ent_table; fc2key_table.tdstypeid = TDS_TYPE_TABLE; fc2key_table.tdstypelen = -1; - fc2ent_table = (FunctionCacheByTdsIdEntry *)hash_search(functionInfoCacheByTdsId, - &fc2key_table, - HASH_ENTER, - NULL); + fc2ent_table = (FunctionCacheByTdsIdEntry *) hash_search(functionInfoCacheByTdsId, + &fc2key_table, + HASH_ENTER, + NULL); finfo_table = &(fc2ent_table->data); finfo_table->ttmtypeid = InvalidOid; finfo_table->ttmbasetypeid = InvalidOid; @@ -543,18 +626,18 @@ TdsLoadTypeFunctionCache(void) * TdsLookupTypeFunctionsByOid - IO function cache lookup */ TdsIoFunctionInfo -TdsLookupTypeFunctionsByOid(Oid typeId, int32* typmod) +TdsLookupTypeFunctionsByOid(Oid typeId, int32 *typmod) { - TdsIoFunctionInfo finfo; - bool found; - Oid tmpTypeId; + TdsIoFunctionInfo finfo; + bool found; + Oid tmpTypeId; Assert(functionInfoCacheByOid != NULL); - finfo = (TdsIoFunctionInfo)hash_search(functionInfoCacheByOid, - &typeId, - HASH_FIND, - &found); + finfo = (TdsIoFunctionInfo) hash_search(functionInfoCacheByOid, + &typeId, + HASH_FIND, + &found); /* * If an entry is not found on tds mapping table, we try to find whether @@ -582,17 +665,17 @@ TdsLookupTypeFunctionsByOid(Oid typeId, int32* typmod) tmpTypeId = typTup->typbasetype; /* - * Typmod is allowed for domain only when enable_domain_typmod - * is enabled when executing the CREATE DOMAIN Statement, - * see DefineDomain for details. + * Typmod is allowed for domain only when enable_domain_typmod is + * enabled when executing the CREATE DOMAIN Statement, see + * DefineDomain for details. */ if (*typmod == -1) *typmod = typTup->typtypmod; - finfo = (TdsIoFunctionInfo)hash_search(functionInfoCacheByOid, - &tmpTypeId, - HASH_FIND, - &found); + finfo = (TdsIoFunctionInfo) hash_search(functionInfoCacheByOid, + &tmpTypeId, + HASH_FIND, + &found); ReleaseSysCache(tup); } @@ -610,44 +693,44 @@ TdsLookupTypeFunctionsByOid(Oid typeId, int32* typmod) TdsIoFunctionInfo TdsLookupTypeFunctionsByTdsId(int32_t typeId, int32_t typeLen) { - FunctionCacheByTdsIdKey fc2key; - FunctionCacheByTdsIdEntry *fc2ent; - bool found; + FunctionCacheByTdsIdKey fc2key; + FunctionCacheByTdsIdEntry *fc2ent; + bool found; Assert(functionInfoCacheByTdsId != NULL); /* Try a lookup with the indicated length */ fc2key.tdstypeid = typeId; fc2key.tdstypelen = typeLen; - fc2ent = (FunctionCacheByTdsIdEntry *)hash_search(functionInfoCacheByTdsId, - &fc2key, - HASH_FIND, - &found); + fc2ent = (FunctionCacheByTdsIdEntry *) hash_search(functionInfoCacheByTdsId, + &fc2key, + HASH_FIND, + &found); if (found) return &(fc2ent->data); /* Variable length types are configured with len=-1, so try that */ fc2key.tdstypeid = typeId; fc2key.tdstypelen = -1; - fc2ent = (FunctionCacheByTdsIdEntry *)hash_search(functionInfoCacheByTdsId, - &fc2key, - HASH_FIND, - &found); + fc2ent = (FunctionCacheByTdsIdEntry *) hash_search(functionInfoCacheByTdsId, + &fc2key, + HASH_FIND, + &found); if (found) return &(fc2ent->data); /* * In spite of being fixed length datatypes, Numeric and Decimal at times - * come on wire with a different length as part of the column-metadata. - * We shall update the tdstypelen and search again. + * come on wire with a different length as part of the column-metadata. We + * shall update the tdstypelen and search again. */ if (typeId == TDS_TYPE_NUMERICN || typeId == TDS_TYPE_DECIMALN) { fc2key.tdstypelen = TDS_MAXLEN_NUMERIC; - fc2ent = (FunctionCacheByTdsIdEntry *)hash_search(functionInfoCacheByTdsId, - &fc2key, - HASH_FIND, - &found); + fc2ent = (FunctionCacheByTdsIdEntry *) hash_search(functionInfoCacheByTdsId, + &fc2key, + HASH_FIND, + &found); if (found) return &(fc2ent->data); } @@ -833,7 +916,8 @@ GetMsgFloat8(StringInfo msg) Datum TdsTypeBitToDatum(StringInfo buf) { - int ext = GetMsgByte(buf); + int ext = GetMsgByte(buf); + PG_RETURN_BOOL((ext != 0) ? true : false); } @@ -841,36 +925,40 @@ TdsTypeBitToDatum(StringInfo buf) Datum TdsTypeIntegerToDatum(StringInfo buf, int maxLen) { - switch(maxLen) + switch (maxLen) { - case TDS_MAXLEN_TINYINT: /* TINY INT. */ - { - uint8 res = GetMsgInt(buf, sizeof(int8)); - PG_RETURN_INT16((int16) res); - } - break; - case TDS_MAXLEN_SMALLINT: /* SMALL INT. */ - { - uint16 res = GetMsgInt(buf, sizeof(uint16)); - PG_RETURN_INT16((uint16) res); - } - break; - case TDS_MAXLEN_INT: /* INT. */ - { - unsigned int res = GetMsgInt(buf, sizeof(int32)); - PG_RETURN_INT32((int32) res); - } - break; + case TDS_MAXLEN_TINYINT: /* TINY INT. */ + { + uint8 res = GetMsgInt(buf, sizeof(int8)); + + PG_RETURN_INT16((int16) res); + } + break; + case TDS_MAXLEN_SMALLINT: /* SMALL INT. */ + { + uint16 res = GetMsgInt(buf, sizeof(uint16)); + + PG_RETURN_INT16((uint16) res); + } + break; + case TDS_MAXLEN_INT: /* INT. */ + { + unsigned int res = GetMsgInt(buf, sizeof(int32)); + + PG_RETURN_INT32((int32) res); + } + break; case TDS_MAXLEN_BIGINT: /* BIG INT. */ - { - uint64 res = GetMsgInt64(buf); - PG_RETURN_INT64((int64) res); - } - break; + { + uint64 res = GetMsgInt64(buf); + + PG_RETURN_INT64((int64) res); + } + break; default: elog(ERROR, "unsupported integer size %d", maxLen); - PG_RETURN_INT32(0); /* keep compiler quiet */ - break; + PG_RETURN_INT32(0); /* keep compiler quiet */ + break; } } @@ -878,25 +966,27 @@ TdsTypeIntegerToDatum(StringInfo buf, int maxLen) Datum TdsTypeFloatToDatum(StringInfo buf, int maxLen) { - switch(maxLen) + switch (maxLen) { case TDS_MAXLEN_FLOAT4: - { - float4 res; - res = GetMsgFloat4(buf); - PG_RETURN_FLOAT4(res); - } - break; + { + float4 res; + + res = GetMsgFloat4(buf); + PG_RETURN_FLOAT4(res); + } + break; case TDS_MAXLEN_FLOAT8: - { - float8 res; - res = GetMsgFloat8(buf); - PG_RETURN_FLOAT8(res); - } + { + float8 res; + + res = GetMsgFloat8(buf); + PG_RETURN_FLOAT8(res); + } default: elog(ERROR, "unsupported float size %d", maxLen); - PG_RETURN_FLOAT4(0); /* keep compiler quiet */ - break; + PG_RETURN_FLOAT4(0); /* keep compiler quiet */ + break; } } @@ -904,15 +994,15 @@ TdsTypeFloatToDatum(StringInfo buf, int maxLen) Datum TdsTypeVarcharToDatum(StringInfo buf, pg_enc encoding, uint8_t tdsColDataType) { - char csave; - Datum pval; + char csave; + Datum pval; csave = buf->data[buf->len]; buf->data[buf->len] = '\0'; pval = TdsAnyToServerEncodingConversion(encoding, - buf->data, buf->len, - tdsColDataType); + buf->data, buf->len, + tdsColDataType); buf->data[buf->len] = csave; return pval; } @@ -921,7 +1011,7 @@ TdsTypeVarcharToDatum(StringInfo buf, pg_enc encoding, uint8_t tdsColDataType) Datum TdsTypeNCharToDatum(StringInfo buf) { - void *result; + void *result; StringInfoData temp; initStringInfo(&temp); @@ -936,32 +1026,37 @@ TdsTypeNCharToDatum(StringInfo buf) static inline char * ReverseString(char *res) { - int lo, hi; + int lo, + hi; + if (!res) return NULL; lo = 0; - hi = strlen(res)-1; + hi = strlen(res) - 1; while (lo < hi) { res[lo] ^= res[hi]; res[hi] ^= res[lo]; res[lo] ^= res[hi]; - lo++; hi--; + lo++; + hi--; } return res; } static inline void -Integer2String(uint128 num, char* str) +Integer2String(uint128 num, char *str) { - int i = 0, rem = 0; + int i = 0, + rem = 0; + while (num) { rem = num % 10; str[i++] = rem + '0'; - num = num/10; + num = num / 10; } str[i++] = '-'; ReverseString(str); @@ -972,13 +1067,15 @@ Datum TdsTypeNumericToDatum(StringInfo buf, int scale) { Numeric res; - int len, sign; - char *decString; - int temp1, temp2; + int len, + sign; + char *decString; + int temp1, + temp2; uint128 num = 0; /* fetch the sign from the actual data which is the first byte */ - sign = (uint8_t)GetMsgInt(buf, 1); + sign = (uint8_t) GetMsgInt(buf, 1); /* fetch the data but ignore the sign byte now */ { @@ -990,7 +1087,7 @@ TdsTypeNumericToDatum(StringInfo buf, int scale) num = LEtoh128(n128); } - decString = (char *)palloc0(sizeof(char) * 40); + decString = (char *) palloc0(sizeof(char) * 40); if (num != 0) Integer2String(num, decString); @@ -1002,21 +1099,23 @@ TdsTypeNumericToDatum(StringInfo buf, int scale) /* * If scale is more than length then we need to append zeros at the start; - * Since there is a '-' at the start of decString, we should ignore it before - * appending and then add it later. + * Since there is a '-' at the start of decString, we should ignore it + * before appending and then add it later. */ if (num != 0 && scale >= len) { - int diff = scale - len + 1; - char *zeros = palloc0(sizeof(char) * diff + 1); - char *tempString = decString; - while(diff) + int diff = scale - len + 1; + char *zeros = palloc0(sizeof(char) * diff + 1); + char *tempString = decString; + + while (diff) { zeros[--diff] = '0'; } + /* - * Add extra '.' character in psprintf; Later we make use of - * this index during shifting the scale part of the string. + * Add extra '.' character in psprintf; Later we make use of this + * index during shifting the scale part of the string. */ decString = psprintf("-%s%s.", zeros, tempString + 1); len = strlen(decString) - 1; @@ -1054,8 +1153,8 @@ TdsTypeNumericToDatum(StringInfo buf, int scale) Datum TdsTypeVarbinaryToDatum(StringInfo buf) { - bytea *result; - int nbytes; + bytea *result; + int nbytes; nbytes = buf->len - buf->cursor; result = (bytea *) palloc0(nbytes + VARHDRSZ); @@ -1069,7 +1168,7 @@ TdsTypeVarbinaryToDatum(StringInfo buf) Datum TdsTypeDatetime2ToDatum(StringInfo buf, int scale, int len) { - uint64_t numMicro = 0; + uint64_t numMicro = 0; uint32_t numDays = 0; Timestamp timestamp; @@ -1084,41 +1183,43 @@ TdsTypeDatetime2ToDatum(StringInfo buf, int scale, int len) TdsGetTimestampFromDayTime(numDays, numMicro, 0, ×tamp, scale); - PG_RETURN_TIMESTAMP((Timestamp)timestamp); + PG_RETURN_TIMESTAMP((Timestamp) timestamp); } /* Helper Function to convert Datetime value into Datum. */ Datum TdsTypeDatetimeToDatum(StringInfo buf) { - uint32 numDays, numTicks; - uint64 val; + uint32 numDays, + numTicks; + uint64 val; Timestamp timestamp; - val = (uint64)GetMsgInt64(buf); + val = (uint64) GetMsgInt64(buf); numTicks = val >> 32; numDays = val & 0x00000000ffffffff; TdsTimeGetDatumFromDatetime(numDays, numTicks, ×tamp); - PG_RETURN_TIMESTAMP((uint64)timestamp); + PG_RETURN_TIMESTAMP((uint64) timestamp); } /* Helper Function to convert Small Datetime value into Datum. */ Datum TdsTypeSmallDatetimeToDatum(StringInfo buf) { - uint16 numDays, numMins; - uint32 val; + uint16 numDays, + numMins; + uint32 val; Timestamp timestamp; - val = (uint32)GetMsgInt(buf, 4); + val = (uint32) GetMsgInt(buf, 4); numMins = val >> 16; numDays = val & 0x0000ffff; TdsTimeGetDatumFromSmalldatetime(numDays, numMins, ×tamp); - PG_RETURN_TIMESTAMP((uint64)timestamp); + PG_RETURN_TIMESTAMP((uint64) timestamp); } /* Helper Function to convert Date value into Datum. */ @@ -1126,8 +1227,9 @@ Datum TdsTypeDateToDatum(StringInfo buf) { DateADT result; - uint64 val; - result = (DateADT)GetMsgInt(buf, 3); + uint64 val; + + result = (DateADT) GetMsgInt(buf, 3); TdsCheckDateValidity(result); TdsTimeGetDatumFromDays(result, &val); @@ -1143,8 +1245,8 @@ TdsTypeTimeToDatum(StringInfo buf, int scale, int len) uint64_t numMicro = 0; /* - * if time data has no specific scale specified in the query, default scale - * to be considered is 7 always. + * if time data has no specific scale specified in the query, default + * scale to be considered is 7 always. */ if (scale == 255) scale = DATETIMEOFFSETMAXSCALE; @@ -1152,32 +1254,33 @@ TdsTypeTimeToDatum(StringInfo buf, int scale, int len) memcpy(&numMicro, &buf->data[buf->cursor], len); buf->cursor += len; - result = (double)numMicro; + result = (double) numMicro; while (scale--) result /= 10; result *= 1000000; if (result < INT64CONST(0) || result > USECS_PER_DAY) ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("time out of range"))); + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("time out of range"))); - PG_RETURN_TIMEADT((TimeADT)result); + PG_RETURN_TIMEADT((TimeADT) result); } /* Helper Function to convert Datetimeoffset value into Datum. */ Datum TdsTypeDatetimeoffsetToDatum(StringInfo buf, int scale, int len) { - uint64_t numMicro = 0; + uint64_t numMicro = 0; uint32_t numDays = 0; int16_t timezone = 0; tsql_datetimeoffset *tdt = (tsql_datetimeoffset *) palloc0(DATETIMEOFFSET_LEN); - TimestampTz timestamp; + TimestampTz timestamp; + /* - * if Datetimeoffset data has no specific scale specified in the query, default scale - * to be considered is 7 always. + * if Datetimeoffset data has no specific scale specified in the query, + * default scale to be considered is 7 always. */ if (scale == 0xFF) scale = DATETIMEOFFSETMAXSCALE; @@ -1192,7 +1295,7 @@ TdsTypeDatetimeoffsetToDatum(StringInfo buf, int scale, int len) buf->cursor += 2; timezone *= -1; - TdsGetTimestampFromDayTime(numDays, numMicro, (int)timezone, ×tamp, scale); + TdsGetTimestampFromDayTime(numDays, numMicro, (int) timezone, ×tamp, scale); timestamp -= (timezone * SECS_PER_MINUTE * USECS_PER_SEC); /* since reverse is done in tm2timestamp() */ @@ -1208,7 +1311,8 @@ TdsTypeDatetimeoffsetToDatum(StringInfo buf, int scale, int len) Datum TdsTypeMoneyToDatum(StringInfo buf) { - uint64 high, low; + uint64 high, + low; uint64 val = GetMsgInt64(buf); high = val & 0xffffffff00000000; @@ -1216,7 +1320,7 @@ TdsTypeMoneyToDatum(StringInfo buf) val = high >> 32 | low << 32; - PG_RETURN_CASH((Cash)val); + PG_RETURN_CASH((Cash) val); } /* Helper Function to convert Small Money value into Datum. */ @@ -1226,21 +1330,21 @@ TdsTypeSmallMoneyToDatum(StringInfo buf) uint64 val = 0; uint32 low = GetMsgInt(buf, 4); - val = (uint64)low; + val = (uint64) low; - PG_RETURN_CASH((Cash)val); + PG_RETURN_CASH((Cash) val); } /* Helper Function to convert XML value into Datum. */ Datum TdsTypeXMLToDatum(StringInfo buf) { - void *result; + void *result; char *str; int nbytes; - void *doc; + void *doc; int encoding = PG_UTF8; - xmlChar *encodingStr = NULL; + xmlChar *encodingStr = NULL; /* * Read the data in raw format. We don't know yet what the encoding is, as @@ -1249,7 +1353,7 @@ TdsTypeXMLToDatum(StringInfo buf) */ nbytes = buf->len - buf->cursor; - str = (char *)GetMsgBytes(buf, nbytes); + str = (char *) GetMsgBytes(buf, nbytes); /* * We need a null-terminated string to pass to parse_xml_decl(). Rather @@ -1263,11 +1367,11 @@ TdsTypeXMLToDatum(StringInfo buf) str[nbytes] = '\0'; /* - * TODO: handle the encoding list - * tds_parse_xml_decl((const char *) str, NULL, NULL, NULL, NULL); - * encoding = encodingStr ? xmlChar_to_encoding(encodingStr) : PG_UTF8; + * TODO: handle the encoding list tds_parse_xml_decl((const char *) str, + * NULL, NULL, NULL, NULL); encoding = encodingStr ? + * xmlChar_to_encoding(encodingStr) : PG_UTF8; */ - tds_parse_xml_decl((const xmlChar *)str, NULL, NULL, &encodingStr, NULL); + tds_parse_xml_decl((const xmlChar *) str, NULL, NULL, &encodingStr, NULL); encoding = encodingStr ? xmlChar_to_encoding(encodingStr) : TdsUTF16toUTF8XmlResult(buf, &result); /* @@ -1287,9 +1391,9 @@ TdsTypeUIDToDatum(StringInfo buf) pg_uuid_t *uuid; /* - * Valid values for UUID are NULL or 16 byte value. - * NULL values are handled in the caller, so in the recv - * function we will only get 16 byte value + * Valid values for UUID are NULL or 16 byte value. NULL values are + * handled in the caller, so in the recv function we will only get 16 byte + * value */ Assert(buf->len == TDS_MAXLEN_UNIQUEIDENTIFIER); @@ -1308,9 +1412,10 @@ TdsTypeUIDToDatum(StringInfo buf) StringInfo TdsGetPlpStringInfoBufferFromToken(const char *message, const ParameterToken token) { - StringInfo pbuf; - Plp plpHead = token->plp, temp; - uint64_t len = 0; + StringInfo pbuf; + Plp plpHead = token->plp, + temp; + uint64_t len = 0; temp = plpHead; pbuf = makeStringInfo(); @@ -1319,7 +1424,7 @@ TdsGetPlpStringInfoBufferFromToken(const char *message, const ParameterToken tok if (temp == NULL) return pbuf; - while(temp != NULL) + while (temp != NULL) { len += temp->len; temp = temp->next; @@ -1327,9 +1432,8 @@ TdsGetPlpStringInfoBufferFromToken(const char *message, const ParameterToken tok /* - * Explicitly calling enlargeStringInfo. This will save - * some overhead incase the data is very large and needs - * repalloc again and again + * Explicitly calling enlargeStringInfo. This will save some overhead + * incase the data is very large and needs repalloc again and again */ enlargeStringInfo(pbuf, len); @@ -1347,15 +1451,15 @@ TdsGetPlpStringInfoBufferFromToken(const char *message, const ParameterToken tok StringInfo TdsGetStringInfoBufferFromToken(const char *message, const ParameterToken token) { - StringInfo pbuf; + StringInfo pbuf; const char *pvalue = &message[token->dataOffset]; pbuf = palloc(sizeof(StringInfoData)); + /* - * Rather than copying data around, we just set up a phony - * StringInfo pointing to the correct portion of the TDS message - * buffer. + * Rather than copying data around, we just set up a phony StringInfo + * pointing to the correct portion of the TDS message buffer. */ pbuf->data = (char *) pvalue; pbuf->maxlen = token->len; @@ -1376,7 +1480,7 @@ TdsGetStringInfoBufferFromToken(const char *message, const ParameterToken token) Datum TdsRecvTypeBit(const char *message, const ParameterToken token) { - Datum res; + Datum res; StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); res = TdsTypeBitToDatum(buf); @@ -1393,7 +1497,7 @@ Datum TdsRecvTypeTinyInt(const char *message, const ParameterToken token) { StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); - Datum res; + Datum res; res = TdsTypeIntegerToDatum(buf, sizeof(int8)); @@ -1410,7 +1514,7 @@ Datum TdsRecvTypeSmallInt(const char *message, const ParameterToken token) { StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); - Datum res; + Datum res; res = TdsTypeIntegerToDatum(buf, sizeof(int16)); @@ -1426,7 +1530,7 @@ TdsRecvTypeSmallInt(const char *message, const ParameterToken token) Datum TdsRecvTypeInteger(const char *message, const ParameterToken token) { - Datum res; + Datum res; StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); res = TdsTypeIntegerToDatum(buf, sizeof(int32)); @@ -1443,7 +1547,7 @@ TdsRecvTypeInteger(const char *message, const ParameterToken token) Datum TdsRecvTypeBigInt(const char *message, const ParameterToken token) { - Datum res; + Datum res; StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); res = TdsTypeIntegerToDatum(buf, sizeof(int64)); @@ -1460,7 +1564,7 @@ TdsRecvTypeBigInt(const char *message, const ParameterToken token) Datum TdsRecvTypeFloat4(const char *message, const ParameterToken token) { - Datum res; + Datum res; StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); res = TdsTypeFloatToDatum(buf, sizeof(float4)); @@ -1477,7 +1581,7 @@ TdsRecvTypeFloat4(const char *message, const ParameterToken token) Datum TdsRecvTypeFloat8(const char *message, const ParameterToken token) { - Datum res; + Datum res; StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); res = TdsTypeFloatToDatum(buf, sizeof(float8)); @@ -1493,7 +1597,7 @@ TdsRecvTypeFloat8(const char *message, const ParameterToken token) Datum TdsRecvTypeBinary(const char *message, const ParameterToken token) { - Datum result; + Datum result; StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); result = TdsTypeVarbinaryToDatum(buf); @@ -1509,8 +1613,8 @@ TdsRecvTypeBinary(const char *message, const ParameterToken token) Datum TdsRecvTypeVarbinary(const char *message, const ParameterToken token) { - Datum result; - StringInfo buf; + Datum result; + StringInfo buf; if (token->maxLen == 0xffff) buf = TdsGetPlpStringInfoBufferFromToken(message, token); @@ -1540,8 +1644,8 @@ Datum TdsRecvTypeVarchar(const char *message, const ParameterToken token) { StringInfo buf; - char csave; - Datum pval; + char csave; + Datum pval; if (token->maxLen == 0xFFFF) { @@ -1555,7 +1659,7 @@ TdsRecvTypeVarchar(const char *message, const ParameterToken token) csave = buf->data[buf->len]; buf->data[buf->len] = '\0'; pval = TdsAnyToServerEncodingConversion(token->paramMeta.encoding, - buf->data, buf->len, TDS_TYPE_VARCHAR); + buf->data, buf->len, TDS_TYPE_VARCHAR); buf->data[buf->len] = csave; if (token->maxLen == 0xFFFF) @@ -1571,9 +1675,9 @@ TdsReadUnicodeDataFromTokenCommon(const char *message, const ParameterToken toke StringInfo buf; /* - * XXX: We reuse this code for extracting the query from the TDS request. In - * some cases, the query is sent as non-unicode datatypes. In those cases, the - * data can come as PLP. + * XXX: We reuse this code for extracting the query from the TDS request. + * In some cases, the query is sent as non-unicode datatypes. In those + * cases, the data can come as PLP. */ if ((token->type == TDS_TYPE_NVARCHAR || token->type == TDS_TYPE_VARCHAR) && (token->maxLen == 0xFFFF)) @@ -1601,7 +1705,7 @@ TdsReadUnicodeDataFromTokenCommon(const char *message, const ParameterToken toke Datum TdsRecvTypeNVarchar(const char *message, const ParameterToken token) { - void *result; + void *result; StringInfoData temp; if (token->maxLen == 0xFFFF) @@ -1620,14 +1724,14 @@ TdsRecvTypeNVarchar(const char *message, const ParameterToken token) Datum TdsRecvTypeText(const char *message, const ParameterToken token) { - char csave; - Datum pval; + char csave; + Datum pval; StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); csave = buf->data[buf->len]; buf->data[buf->len] = '\0'; pval = TdsAnyToServerEncodingConversion(token->paramMeta.encoding, buf->data, buf->len, - TDS_TYPE_TEXT); + TDS_TYPE_TEXT); buf->data[buf->len] = csave; pfree(buf); @@ -1637,7 +1741,7 @@ TdsRecvTypeText(const char *message, const ParameterToken token) Datum TdsRecvTypeNText(const char *message, const ParameterToken token) { - Datum result; + Datum result; StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); result = TdsTypeNCharToDatum(buf); @@ -1655,8 +1759,8 @@ TdsRecvTypeNText(const char *message, const ParameterToken token) Datum TdsRecvTypeChar(const char *message, const ParameterToken token) { - char csave; - Datum pval; + char csave; + Datum pval; StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); csave = buf->data[buf->len]; @@ -1677,7 +1781,7 @@ TdsRecvTypeChar(const char *message, const ParameterToken token) Datum TdsRecvTypeNChar(const char *message, const ParameterToken token) { - Datum result; + Datum result; StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); result = TdsTypeNCharToDatum(buf); @@ -1694,8 +1798,8 @@ TdsRecvTypeNChar(const char *message, const ParameterToken token) Datum TdsRecvTypeXml(const char *message, const ParameterToken token) { - Datum result; - StringInfo buf = TdsGetPlpStringInfoBufferFromToken(message, token); + Datum result; + StringInfo buf = TdsGetPlpStringInfoBufferFromToken(message, token); TDSInstrumentation(INSTR_TDS_DATATYPE_XML); @@ -1715,7 +1819,7 @@ TdsRecvTypeXml(const char *message, const ParameterToken token) Datum TdsRecvTypeUniqueIdentifier(const char *message, const ParameterToken token) { - Datum result; + Datum result; StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); result = TdsTypeUIDToDatum(buf); @@ -1735,7 +1839,8 @@ TdsRecvTypeMoney(const char *message, const ParameterToken token) { StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); - uint64 high, low; + uint64 high, + low; uint64 val = GetMsgInt64(buf); TDSInstrumentation(INSTR_TDS_DATATYPE_MONEY); @@ -1745,7 +1850,7 @@ TdsRecvTypeMoney(const char *message, const ParameterToken token) val = high >> 32 | low << 32; pfree(buf); - PG_RETURN_CASH((Cash)val); + PG_RETURN_CASH((Cash) val); } /* -------------------------------- @@ -1764,9 +1869,9 @@ TdsRecvTypeSmallmoney(const char *message, const ParameterToken token) TDSInstrumentation(INSTR_TDS_DATATYPE_SMALLMONEY); - val = (uint64)low; + val = (uint64) low; pfree(buf); - PG_RETURN_CASH((Cash)val); + PG_RETURN_CASH((Cash) val); } /* -------------------------------- @@ -1777,7 +1882,7 @@ TdsRecvTypeSmallmoney(const char *message, const ParameterToken token) Datum TdsRecvTypeSmalldatetime(const char *message, const ParameterToken token) { - Datum result; + Datum result; StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); result = TdsTypeSmallDatetimeToDatum(buf); @@ -1794,7 +1899,7 @@ TdsRecvTypeSmalldatetime(const char *message, const ParameterToken token) Datum TdsRecvTypeDate(const char *message, const ParameterToken token) { - Datum result; + Datum result; StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); result = TdsTypeDateToDatum(buf); @@ -1811,7 +1916,7 @@ TdsRecvTypeDate(const char *message, const ParameterToken token) Datum TdsRecvTypeDatetime(const char *message, const ParameterToken token) { - Datum result; + Datum result; StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); result = TdsTypeDatetimeToDatum(buf); @@ -1828,10 +1933,11 @@ TdsRecvTypeDatetime(const char *message, const ParameterToken token) Datum TdsRecvTypeTime(const char *message, const ParameterToken token) { - Datum result; - int scale = 0; + Datum result; + int scale = 0; StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); - TdsColumnMetaData col = token->paramMeta; + TdsColumnMetaData col = token->paramMeta; + scale = col.metaEntry.type6.scale; result = TdsTypeTimeToDatum(buf, scale, token->len); @@ -1843,10 +1949,10 @@ TdsRecvTypeTime(const char *message, const ParameterToken token) Datum TdsRecvTypeDatetime2(const char *message, const ParameterToken token) { - Datum result; - int scale = 0; - StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); - TdsColumnMetaData col = token->paramMeta; + Datum result; + int scale = 0; + StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); + TdsColumnMetaData col = token->paramMeta; scale = col.metaEntry.type6.scale; @@ -1860,15 +1966,16 @@ TdsRecvTypeDatetime2(const char *message, const ParameterToken token) static inline uint128 StringToInteger(char *str) { - int i = 0, len = 0; - uint128 num = 0; + int i = 0, + len = 0; + uint128 num = 0; if (!str) return 0; len = strlen(str); - for ( ; i < len; i++) + for (; i < len; i++) num = num * 10 + (str[i] - '0'); return num; @@ -1884,19 +1991,23 @@ Datum TdsRecvTypeNumeric(const char *message, const ParameterToken token) { Numeric res; - int scale, len, sign; - char *decString, *wholeString; - int temp1, temp2; + int scale, + len, + sign; + char *decString, + *wholeString; + int temp1, + temp2; uint128 num = 0; - TdsColumnMetaData col = token->paramMeta; + TdsColumnMetaData col = token->paramMeta; - StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); + StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); /* scale and precision are part of the type info */ scale = col.metaEntry.type5.scale; /* fetch the sign from the actual data which is the first byte */ - sign = (uint8_t)GetMsgInt(buf, 1); + sign = (uint8_t) GetMsgInt(buf, 1); /* fetch the data but ignore the sign byte now */ { @@ -1905,8 +2016,8 @@ TdsRecvTypeNumeric(const char *message, const ParameterToken token) if ((token->len - 1) > sizeof(n128)) ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("Data length %d is invalid for NUMERIC/DECIMAL data types.", - token->len))); + errmsg("Data length %d is invalid for NUMERIC/DECIMAL data types.", + token->len))); memcpy(&n128, &buf->data[buf->cursor], token->len - 1); buf->cursor += token->len - 1; @@ -1914,7 +2025,7 @@ TdsRecvTypeNumeric(const char *message, const ParameterToken token) num = LEtoh128(n128); } - decString = (char *)palloc0(sizeof(char) * 40); + decString = (char *) palloc0(sizeof(char) * 40); if (num != 0) Integer2String(num, decString); @@ -1927,21 +2038,23 @@ TdsRecvTypeNumeric(const char *message, const ParameterToken token) /* * If scale is more than length then we need to append zeros at the start; - * Since there is a '-' at the start of decString, we should ignore it before - * appending and then add it later. + * Since there is a '-' at the start of decString, we should ignore it + * before appending and then add it later. */ if (num != 0 && scale >= len) { - int diff = scale - len + 1; - char *zeros = palloc0(sizeof(char) * diff + 1); - char *tempString = decString; - while(diff) + int diff = scale - len + 1; + char *zeros = palloc0(sizeof(char) * diff + 1); + char *tempString = decString; + + while (diff) { zeros[--diff] = '0'; } + /* - * Add extra '.' character in psprintf; Later we make use of - * this index during shifting the scale part of the string. + * Add extra '.' character in psprintf; Later we make use of this + * index during shifting the scale part of the string. */ decString = psprintf("-%s%s.", zeros, tempString + 1); len = strlen(decString) - 1; @@ -1967,9 +2080,10 @@ TdsRecvTypeNumeric(const char *message, const ParameterToken token) scale--; } } + /* - * We use wholeString just to free the address at decString later, - * since it gets updated later. + * We use wholeString just to free the address at decString later, since + * it gets updated later. */ wholeString = decString; @@ -1994,38 +2108,38 @@ TdsRecvTypeNumeric(const char *message, const ParameterToken token) static void FetchTvpTypeOid(const ParameterToken token, char *tvpName) { - int rc; - HeapTuple row; - bool isnull; - TupleDesc tupdesc; - char *query; + int rc; + HeapTuple row; + bool isnull; + TupleDesc tupdesc; + char *query; if ((rc = SPI_connect()) < 0) { /* Reset dialect. */ set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); elog(ERROR, "SPI_connect() failed in TDS Listener " - "with return code %d", rc); + "with return code %d", rc); } query = psprintf("SELECT '%s'::regtype::oid", tvpName); rc = SPI_execute(query, false, 1); - if(rc != SPI_OK_SELECT) + if (rc != SPI_OK_SELECT) { /* Reset dialect. */ set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); elog(ERROR, "Failed to insert in the underlying table for table-valued parameter: %d", rc); } tupdesc = SPI_tuptable->tupdesc; row = SPI_tuptable->vals[0]; token->paramMeta.pgTypeOid = DatumGetObjectId(SPI_getbinval(row, tupdesc, - 1, &isnull)); + 1, &isnull)); pfree(query); SPI_finish(); @@ -2040,35 +2154,36 @@ FetchTvpTypeOid(const ParameterToken token, char *tvpName) Datum TdsRecvTypeTable(const char *message, const ParameterToken token) { - char *tableName; - char *query; - StringInfo temp; - int rc; + char *tableName; + char *query; + StringInfo temp; + int rc; TvpRowData *row = token->tvpInfo->rowData; TvpColMetaData *colMetaData = token->tvpInfo->colMetaData; - bool xactStarted = IsTransactionOrTransactionBlock(); - char *finalTableName; - char *tvpTypeName; - TvpLookupItem *item; + bool xactStarted = IsTransactionOrTransactionBlock(); + char *finalTableName; + char *tvpTypeName; + TvpLookupItem *item; + temp = palloc(sizeof(StringInfoData)); initStringInfo(temp); TDSInstrumentation(INSTR_TDS_DATATYPE_TABLE_VALUED_PARAMETER); tvpTypeName = downcase_truncate_identifier(token->tvpInfo->tvpTypeName, - strlen(token->tvpInfo->tvpTypeName), true); + strlen(token->tvpInfo->tvpTypeName), true); /* - * If schema is provided we convert it to physical schema - * and then update the tvpTypeName to have 2 part names. + * If schema is provided we convert it to physical schema and then update + * the tvpTypeName to have 2 part names. */ if (token->tvpInfo->tvpTypeSchemaName) { - char *db_name = pltsql_plugin_handler_ptr->get_cur_db_name(); - char *logical_schema = downcase_truncate_identifier(token->tvpInfo->tvpTypeSchemaName, - strlen(token->tvpInfo->tvpTypeSchemaName), true); - char *physical_schema = pltsql_plugin_handler_ptr->get_physical_schema_name(db_name, logical_schema); - char *tempStr = psprintf("%s.%s", physical_schema, tvpTypeName); + char *db_name = pltsql_plugin_handler_ptr->get_cur_db_name(); + char *logical_schema = downcase_truncate_identifier(token->tvpInfo->tvpTypeSchemaName, + strlen(token->tvpInfo->tvpTypeSchemaName), true); + char *physical_schema = pltsql_plugin_handler_ptr->get_physical_schema_name(db_name, logical_schema); + char *tempStr = psprintf("%s.%s", physical_schema, tvpTypeName); pfree(tvpTypeName); tvpTypeName = tempStr; @@ -2078,7 +2193,7 @@ TdsRecvTypeTable(const char *message, const ParameterToken token) pfree(db_name); } - /* Setting a unique name for TVP temp table. */ + /* Setting a unique name for TVP temp table. */ tableName = psprintf("%s_TDS_TVP_TEMP_TABLE_%d", token->tvpInfo->tableName, rand()); finalTableName = downcase_truncate_identifier(tableName, strlen(tableName), true); pfree(tableName); @@ -2086,33 +2201,33 @@ TdsRecvTypeTable(const char *message, const ParameterToken token) /* Connect to the SPI manager. */ if ((rc = SPI_connect()) < 0) elog(ERROR, "SPI_connect() failed in TDS Listener " - "with return code %d", rc); + "with return code %d", rc); /* - * We change the dialect to postgres to create temp tables - * and execute a prep/exec insert query via SPI. + * We change the dialect to postgres to create temp tables and execute a + * prep/exec insert query via SPI. */ set_config_option("babelfishpg_tsql.sql_dialect", "postgres", - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); if (!xactStarted) StartTransactionCommand(); - PushActiveSnapshot(GetTransactionSnapshot()); + PushActiveSnapshot(GetTransactionSnapshot()); /* Explicity retrieve the oid for TVP type and map it. */ if (token->paramMeta.pgTypeOid == InvalidOid) FetchTvpTypeOid(token, tvpTypeName); query = psprintf("CREATE TEMPORARY TABLE IF NOT EXISTS %s (like %s including all)", - finalTableName, tvpTypeName); + finalTableName, tvpTypeName); pfree(tvpTypeName); /* - * If table with the same name already exists, we should just use that table - * and ignore the NOTICE of "relation already exists, skipping". + * If table with the same name already exists, we should just use that + * table and ignore the NOTICE of "relation already exists, skipping". */ rc = SPI_execute(query, false, 1); @@ -2120,8 +2235,8 @@ TdsRecvTypeTable(const char *message, const ParameterToken token) { /* Reset dialect. */ set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); elog(ERROR, "Failed to create the underlying table for table-valued parameter: %d", rc); } @@ -2131,25 +2246,27 @@ TdsRecvTypeTable(const char *message, const ParameterToken token) CommitTransactionCommand(); { - char *src; - int nargs = token->tvpInfo->colCount * token->tvpInfo->rowCount; - Datum *values = palloc(nargs * sizeof(Datum)); - char *nulls = palloc(nargs * sizeof(char)); - Oid *argtypes= palloc(nargs * sizeof(Datum)); - int i = 0; + char *src; + int nargs = token->tvpInfo->colCount * token->tvpInfo->rowCount; + Datum *values = palloc(nargs * sizeof(Datum)); + char *nulls = palloc(nargs * sizeof(char)); + Oid *argtypes = palloc(nargs * sizeof(Datum)); + int i = 0; + query = " "; if (!xactStarted) StartTransactionCommand(); PushActiveSnapshot(GetTransactionSnapshot()); - while (row) /* Create the prep/exec query to insert the rows. */ + while (row) /* Create the prep/exec query to insert the + * rows. */ { TdsIoFunctionInfo tempFuncInfo; - int currentColumn = 0; - char *currentQuery = " "; + int currentColumn = 0; + char *currentQuery = " "; - while(currentColumn != token->tvpInfo->colCount) + while (currentColumn != token->tvpInfo->colCount) { temp = &(row->columnValues[currentColumn]); tempFuncInfo = TdsLookupTypeFunctionsByTdsId(colMetaData[currentColumn].columnTdsType, colMetaData[currentColumn].maxLen); @@ -2157,65 +2274,65 @@ TdsRecvTypeTable(const char *message, const ParameterToken token) if (row->isNull[currentColumn] == 'n') nulls[i] = row->isNull[currentColumn]; else - switch(colMetaData[currentColumn].columnTdsType) + switch (colMetaData[currentColumn].columnTdsType) { case TDS_TYPE_CHAR: case TDS_TYPE_VARCHAR: values[i] = TdsTypeVarcharToDatum(temp, colMetaData[currentColumn].encoding, colMetaData[currentColumn].columnTdsType); - break; + break; case TDS_TYPE_NCHAR: values[i] = TdsTypeNCharToDatum(temp); - break; + break; case TDS_TYPE_NVARCHAR: - if (!row->isNull[currentColumn]) /* NULL. */ + if (!row->isNull[currentColumn]) /* NULL. */ currentQuery = psprintf("%s,\'NULL\'", currentQuery); else currentQuery = psprintf("%s,\'%s\'", currentQuery, temp->data); nargs--; - break; + break; case TDS_TYPE_INTEGER: case TDS_TYPE_BIT: values[i] = TdsTypeIntegerToDatum(temp, colMetaData[currentColumn].maxLen); - break; + break; case TDS_TYPE_FLOAT: values[i] = TdsTypeFloatToDatum(temp, colMetaData[currentColumn].maxLen); - break; + break; case TDS_TYPE_NUMERICN: case TDS_TYPE_DECIMALN: values[i] = TdsTypeNumericToDatum(temp, colMetaData[currentColumn].scale); - break; + break; case TDS_TYPE_VARBINARY: case TDS_TYPE_BINARY: values[i] = TdsTypeVarbinaryToDatum(temp); argtypes[i] = tempFuncInfo->ttmtypeid; - break; + break; case TDS_TYPE_DATE: values[i] = TdsTypeDateToDatum(temp); - break; + break; case TDS_TYPE_TIME: values[i] = TdsTypeTimeToDatum(temp, colMetaData[currentColumn].scale, temp->len); - break; + break; case TDS_TYPE_DATETIMEOFFSET: values[i] = TdsTypeDatetimeoffsetToDatum(temp, colMetaData[currentColumn].scale, temp->len); - break; + break; case TDS_TYPE_DATETIME2: values[i] = TdsTypeDatetime2ToDatum(temp, colMetaData[currentColumn].scale, temp->len); - break; + break; case TDS_TYPE_DATETIMEN: values[i] = TdsTypeDatetimeToDatum(temp); - break; + break; case TDS_TYPE_MONEYN: values[i] = TdsTypeMoneyToDatum(temp); - break; + break; case TDS_TYPE_XML: values[i] = TdsTypeXMLToDatum(temp); - break; + break; case TDS_TYPE_UNIQUEIDENTIFIER: values[i] = TdsTypeUIDToDatum(temp); - break; + break; case TDS_TYPE_SQLVARIANT: values[i] = TdsTypeSqlVariantToDatum(temp); - break; + break; } /* Build a string for bind parameters. */ if (colMetaData[currentColumn].columnTdsType != TDS_TYPE_NVARCHAR || row->isNull[currentColumn] == 'n') @@ -2226,38 +2343,42 @@ TdsRecvTypeTable(const char *message, const ParameterToken token) currentColumn++; } row = row->nextRow; - currentQuery[1] = ' '; /* Convert the first ',' into a blank space. */ + currentQuery[1] = ' '; /* Convert the first ',' into a blank + * space. */ - /* Add each row values in a single insert query so that we call SPI only once. */ + /* + * Add each row values in a single insert query so that we call + * SPI only once. + */ query = psprintf("%s,(%s)", query, currentQuery); } - if (token->tvpInfo->rowData) /* If any row in TVP */ + if (token->tvpInfo->rowData) /* If any row in TVP */ { - query[1] = ' '; /* Convert the first ',' into a blank space. */ + query[1] = ' '; /* Convert the first ',' into a blank space. */ src = psprintf("Insert into %s values %s", finalTableName, query); if ((rc = SPI_connect()) < 0) { /* Reset dialect. */ set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); elog(ERROR, "SPI_connect() failed in TDS Listener " - "with return code %d", rc); + "with return code %d", rc); } rc = SPI_execute_with_args(src, - nargs, argtypes, - values, nulls, - false, 1); + nargs, argtypes, + values, nulls, + false, 1); if (rc != SPI_OK_INSERT) { /* Reset dialect. */ set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); elog(ERROR, "Failed to insert in the underlying table for table-valued parameter: %d", rc); } @@ -2268,14 +2389,15 @@ TdsRecvTypeTable(const char *message, const ParameterToken token) } set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); } /* Free all the pointers. */ while (token->tvpInfo->rowData) { TvpRowData *tempRow = token->tvpInfo->rowData; + token->tvpInfo->rowData = token->tvpInfo->rowData->nextRow; pfree(tempRow); } @@ -2283,8 +2405,8 @@ TdsRecvTypeTable(const char *message, const ParameterToken token) item = (TvpLookupItem *) palloc(sizeof(TvpLookupItem)); item->name = downcase_truncate_identifier(token->paramMeta.colName.data, - strlen(token->paramMeta.colName.data), - true); + strlen(token->paramMeta.colName.data), + true); item->tableRelid = InvalidOid; item->tableName = finalTableName; tvp_lookup_list = lappend(tvp_lookup_list, item); @@ -2299,8 +2421,8 @@ TdsRecvTypeTable(const char *message, const ParameterToken token) Datum TdsRecvTypeSqlvariant(const char *message, const ParameterToken token) { - Datum result; - StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); + Datum result; + StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); TDSInstrumentation(INSTR_TDS_DATATYPE_SQLVARIANT); @@ -2317,7 +2439,7 @@ TdsSendTypeBit(FmgrInfo *finfo, Datum value, void *vMetaData) int8_t out = DatumGetBool(value); /* Don't send the length if the column type is not null. */ - if (!((TdsColumnMetaData *)vMetaData)->attNotNull) + if (!((TdsColumnMetaData *) vMetaData)->attNotNull) rc = TdsPutInt8(sizeof(out)); if (rc == 0) @@ -2332,7 +2454,7 @@ TdsSendTypeTinyint(FmgrInfo *finfo, Datum value, void *vMetaData) int8_t out = DatumGetUInt8(value); /* Don't send the length if the column type is not null. */ - if (!((TdsColumnMetaData *)vMetaData)->attNotNull) + if (!((TdsColumnMetaData *) vMetaData)->attNotNull) rc = TdsPutInt8(sizeof(out)); if (rc == 0) @@ -2346,7 +2468,7 @@ TdsSendTypeSmallint(FmgrInfo *finfo, Datum value, void *vMetaData) int16_t out = DatumGetInt16(value); /* Don't send the length if the column type is not null. */ - if (!((TdsColumnMetaData *)vMetaData)->attNotNull) + if (!((TdsColumnMetaData *) vMetaData)->attNotNull) rc = TdsPutInt8(sizeof(out)); if (rc == 0) @@ -2361,7 +2483,7 @@ TdsSendTypeInteger(FmgrInfo *finfo, Datum value, void *vMetaData) int32_t out = DatumGetInt32(value); /* Don't send the length if the column type is not null. */ - if (!((TdsColumnMetaData *)vMetaData)->attNotNull) + if (!((TdsColumnMetaData *) vMetaData)->attNotNull) rc = TdsPutInt8(sizeof(out)); if (rc == 0) @@ -2376,7 +2498,7 @@ TdsSendTypeBigint(FmgrInfo *finfo, Datum value, void *vMetaData) int64_t out = DatumGetInt64(value); /* Don't send the length if the column type is not null. */ - if (!((TdsColumnMetaData *)vMetaData)->attNotNull) + if (!((TdsColumnMetaData *) vMetaData)->attNotNull) rc = TdsPutInt8(sizeof(out)); if (rc == 0) @@ -2391,7 +2513,7 @@ TdsSendTypeFloat4(FmgrInfo *finfo, Datum value, void *vMetaData) float4 out = DatumGetFloat4(value); /* Don't send the length if the column type is not null. */ - if (!((TdsColumnMetaData *)vMetaData)->attNotNull) + if (!((TdsColumnMetaData *) vMetaData)->attNotNull) rc = TdsPutInt8(sizeof(out)); if (rc == 0) @@ -2406,7 +2528,7 @@ TdsSendTypeFloat8(FmgrInfo *finfo, Datum value, void *vMetaData) float8 out = DatumGetFloat8(value); /* Don't send the length if the column type is not null. */ - if (!((TdsColumnMetaData *)vMetaData)->attNotNull) + if (!((TdsColumnMetaData *) vMetaData)->attNotNull) rc = TdsPutInt8(sizeof(out)); if (rc == 0) @@ -2417,10 +2539,10 @@ TdsSendTypeFloat8(FmgrInfo *finfo, Datum value, void *vMetaData) static int TdsSendPlpDataHelper(char *data, int len) { - int rc; - uint32_t plpTerminator = PLP_TERMINATOR; - uint64_t tempOffset = 0; - uint32_t plpChunckLen = PLP_CHUNCK_LEN; + int rc; + uint32_t plpTerminator = PLP_TERMINATOR; + uint64_t tempOffset = 0; + uint32_t plpChunckLen = PLP_CHUNCK_LEN; if ((rc = TdsPutInt64LE(len)) == 0) { @@ -2429,11 +2551,11 @@ TdsSendPlpDataHelper(char *data, int len) if (plpChunckLen > (len - tempOffset)) plpChunckLen = (len - tempOffset); - // Either data is "0" or no more data to send + /* Either data is "0" or no more data to send */ if (plpChunckLen == 0) break; - // need testing for "0" len + /* need testing for "0" len */ if ((rc = TdsPutUInt32LE(plpChunckLen)) == 0) { TdsPutbytes(&(data[tempOffset]), plpChunckLen); @@ -2454,12 +2576,12 @@ int TdsSendTypeXml(FmgrInfo *finfo, Datum value, void *vMetaData) { int rc; - char *out = OutputFunctionCall(finfo, value); - StringInfoData buf; + char *out = OutputFunctionCall(finfo, value); + StringInfoData buf; /* - * If client being connected is using TDS version lower than or equal to 7.1 - * then TSQL treats XML as NText. + * If client being connected is using TDS version lower than or equal to + * 7.1 then TSQL treats XML as NText. */ if (GetClientTDSVersion() <= TDS_VERSION_7_1_1) return TdsSendTypeNText(finfo, value, vMetaData); @@ -2470,7 +2592,7 @@ TdsSendTypeXml(FmgrInfo *finfo, Datum value, void *vMetaData) TdsUTF8toUTF16StringInfo(&buf, out, strlen(out)); rc = TdsSendPlpDataHelper(buf.data, buf.len); - + pfree(buf.data); return rc; @@ -2479,18 +2601,19 @@ TdsSendTypeXml(FmgrInfo *finfo, Datum value, void *vMetaData) int TdsSendTypeBinary(FmgrInfo *finfo, Datum value, void *vMetaData) { - int rc = EOF,maxLen = 0; - bytea *vlena = DatumGetByteaPCopy(value); - bytea *buf; - TdsColumnMetaData *col = (TdsColumnMetaData *)vMetaData; + int rc = EOF, + maxLen = 0; + bytea *vlena = DatumGetByteaPCopy(value); + bytea *buf; + TdsColumnMetaData *col = (TdsColumnMetaData *) vMetaData; maxLen = col->metaEntry.type7.maxSize; - buf = (bytea *)palloc0(sizeof(bytea) * maxLen); + buf = (bytea *) palloc0(sizeof(bytea) * maxLen); memcpy(buf, VARDATA_ANY(vlena), VARSIZE_ANY_EXHDR(vlena)); if ((rc = TdsPutUInt16LE(maxLen)) == 0) TdsPutbytes(buf, maxLen); - + pfree(buf); return rc; } @@ -2498,12 +2621,14 @@ TdsSendTypeBinary(FmgrInfo *finfo, Datum value, void *vMetaData) int TdsSendTypeVarchar(FmgrInfo *finfo, Datum value, void *vMetaData) { - int rc = EOF, - len, /* number of bytes used to store the string. */ - actualLen, /* Number of bytes that would be needed to store given string in given encoding. */ - maxLen; /* max size of given column in bytes */ - char *destBuf, *buf = OutputFunctionCall(finfo, value); - TdsColumnMetaData *col = (TdsColumnMetaData *)vMetaData; + int rc = EOF, + len, /* number of bytes used to store the string. */ + actualLen, /* Number of bytes that would be needed to + * store given string in given encoding. */ + maxLen; /* max size of given column in bytes */ + char *destBuf, + *buf = OutputFunctionCall(finfo, value); + TdsColumnMetaData *col = (TdsColumnMetaData *) vMetaData; len = strlen(buf); @@ -2520,7 +2645,7 @@ TdsSendTypeVarchar(FmgrInfo *finfo, Datum value, void *vMetaData) } else { - /* We can store upto 2GB (2^31 - 1 bytes) for the varchar(max). */ + /* We can store upto 2GB (2^31 - 1 bytes) for the varchar(max). */ if (unlikely(actualLen > VARCHAR_MAX)) elog(ERROR, "Number of bytes required for the field of varchar(max) exeeds 2GB"); TDSInstrumentation(INSTR_TDS_DATATYPE_VARCHAR_MAX); @@ -2534,13 +2659,15 @@ TdsSendTypeVarchar(FmgrInfo *finfo, Datum value, void *vMetaData) int TdsSendTypeChar(FmgrInfo *finfo, Datum value, void *vMetaData) -{ +{ int rc = EOF, - maxLen, /* max size of given column in bytes */ - actualLen, /* Number of bytes that would be needed to store given string in given encoding. */ - len; /* number of bytes used to store the string. */ - char *destBuf, *buf = OutputFunctionCall(finfo, value); - TdsColumnMetaData *col = (TdsColumnMetaData *)vMetaData; + maxLen, /* max size of given column in bytes */ + actualLen, /* Number of bytes that would be needed to + * store given string in given encoding. */ + len; /* number of bytes used to store the string. */ + char *destBuf, + *buf = OutputFunctionCall(finfo, value); + TdsColumnMetaData *col = (TdsColumnMetaData *) vMetaData; len = strlen(buf); @@ -2560,10 +2687,12 @@ TdsSendTypeChar(FmgrInfo *finfo, Datum value, void *vMetaData) int TdsSendTypeVarbinary(FmgrInfo *finfo, Datum value, void *vMetaData) { - int rc = EOF, len = 0, maxlen = 0; - bytea *vlena = DatumGetByteaPCopy(value); - char *buf = VARDATA_ANY(vlena); - TdsColumnMetaData *col = (TdsColumnMetaData *)vMetaData; + int rc = EOF, + len = 0, + maxlen = 0; + bytea *vlena = DatumGetByteaPCopy(value); + char *buf = VARDATA_ANY(vlena); + TdsColumnMetaData *col = (TdsColumnMetaData *) vMetaData; maxlen = col->metaEntry.type7.maxSize; len = VARSIZE_ANY_EXHDR(vlena); @@ -2579,21 +2708,21 @@ TdsSendTypeVarbinary(FmgrInfo *finfo, Datum value, void *vMetaData) rc = TdsSendPlpDataHelper(buf, len); } - return rc; + return rc; } static inline void SendTextPtrInfo(void) { /* - * For now, we are sending dummy data for textptr and texttimestamp - * TODO: Once the engine supports TEXTPTR, TIMESTAMP - BABEL-260, - * query & send the actual values + * For now, we are sending dummy data for textptr and texttimestamp TODO: + * Once the engine supports TEXTPTR, TIMESTAMP - BABEL-260, query & send + * the actual values */ - uint8_t temp = 16; - char textptr[] = {0x64, 0x75, 0x6d, 0x6d, 0x79, 0x20, 0x74, 0x65, 0x78, 0x74, - 0x70, 0x74, 0x72, 0x00, 0x00, 0x00}; - char texttimestamp[] = { 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x54, 0x53, 0x00}; + uint8_t temp = 16; + char textptr[] = {0x64, 0x75, 0x6d, 0x6d, 0x79, 0x20, 0x74, 0x65, 0x78, 0x74, + 0x70, 0x74, 0x72, 0x00, 0x00, 0x00}; + char texttimestamp[] = {0x64, 0x75, 0x6d, 0x6d, 0x79, 0x54, 0x53, 0x00}; TdsPutUInt8(temp); @@ -2604,11 +2733,12 @@ SendTextPtrInfo(void) int TdsSendTypeText(FmgrInfo *finfo, Datum value, void *vMetaData) { - int rc; - uint32_t len; - char *destBuf, *buf = OutputFunctionCall(finfo, value); - TdsColumnMetaData *col = (TdsColumnMetaData *)vMetaData; - int encodedByteLen; + int rc; + uint32_t len; + char *destBuf, + *buf = OutputFunctionCall(finfo, value); + TdsColumnMetaData *col = (TdsColumnMetaData *) vMetaData; + int encodedByteLen; SendTextPtrInfo(); @@ -2625,9 +2755,10 @@ TdsSendTypeText(FmgrInfo *finfo, Datum value, void *vMetaData) int TdsSendTypeImage(FmgrInfo *finfo, Datum value, void *vMetaData) { - int rc = EOF, len; - bytea *vlena = DatumGetByteaPCopy(value); - char *buf = VARDATA(vlena); + int rc = EOF, + len; + bytea *vlena = DatumGetByteaPCopy(value); + char *buf = VARDATA(vlena); TDSInstrumentation(INSTR_TDS_DATATYPE_IMAGE); @@ -2643,9 +2774,9 @@ TdsSendTypeImage(FmgrInfo *finfo, Datum value, void *vMetaData) int TdsSendTypeNText(FmgrInfo *finfo, Datum value, void *vMetaData) { - int rc; - char *out = OutputFunctionCall(finfo, value); - StringInfoData buf; + int rc; + char *out = OutputFunctionCall(finfo, value); + StringInfoData buf; SendTextPtrInfo(); @@ -2653,21 +2784,21 @@ TdsSendTypeNText(FmgrInfo *finfo, Datum value, void *vMetaData) TdsUTF8toUTF16StringInfo(&buf, out, strlen(out)); /* - * TODO: Enable below check: BABEL-298 - * This is a special case we are making for TDS clients. TSQL treats - * on-the-wire data really as UCS2, not UTF16. While we try our best - * to detect possible problems on input, the special rules about - * truncating trailing spaces allow to enter data that exceeds the - * number of 16-bit units to be sent here. In a best effort approach - * we strip extra spaces here. The FATAL error will never happen - * if the input rules are correct. + * TODO: Enable below check: BABEL-298 This is a special case we are + * making for TDS clients. TSQL treats on-the-wire data really as UCS2, + * not UTF16. While we try our best to detect possible problems on input, + * the special rules about truncating trailing spaces allow to enter data + * that exceeds the number of 16-bit units to be sent here. In a best + * effort approach we strip extra spaces here. The FATAL error will never + * happen if the input rules are correct. + */ + + /* + * while (buf.len > 0 && buf.len > col->metaEntry.type2.maxSize) { if + * (buf.data[buf.len - 2] != ' ' || buf.data[buf.len - 1] != '\0') + * elog(FATAL, "UTF16 output of varchar/bpchar exceeds max length"); + * buf.len -= 2; } */ - /*while (buf.len > 0 && buf.len > col->metaEntry.type2.maxSize) - { - if (buf.data[buf.len - 2] != ' ' || buf.data[buf.len - 1] != '\0') - elog(FATAL, "UTF16 output of varchar/bpchar exceeds max length"); - buf.len -= 2; - }*/ if ((rc = TdsPutUInt32LE(buf.len)) == 0) TdsPutbytes(buf.data, buf.len); @@ -2679,10 +2810,11 @@ int TdsSendTypeNVarchar(FmgrInfo *finfo, Datum value, void *vMetaData) { - int rc, maxlen; - char *out = OutputFunctionCall(finfo, value); - TdsColumnMetaData *col = (TdsColumnMetaData *)vMetaData; - StringInfoData buf; + int rc, + maxlen; + char *out = OutputFunctionCall(finfo, value); + TdsColumnMetaData *col = (TdsColumnMetaData *) vMetaData; + StringInfoData buf; initStringInfo(&buf); TdsUTF8toUTF16StringInfo(&buf, out, strlen(out)); @@ -2690,16 +2822,16 @@ TdsSendTypeNVarchar(FmgrInfo *finfo, Datum value, void *vMetaData) if (maxlen != 0xffff) { - + /* * This is a special case we are making for TDS clients. TSQL treats * on-the-wire data really as UCS2, not UTF16. While we try our best - * to detect possible problems on input, the special rules about - * truncating trailing spaces allow to enter data that exceeds the - * number of 16-bit units to be sent here. In a best effort approach - * we strip extra spaces here. The FATAL error will never happen - * if the input rules are correct. - */ + * to detect possible problems on input, the special rules about + * truncating trailing spaces allow to enter data that exceeds the + * number of 16-bit units to be sent here. In a best effort approach + * we strip extra spaces here. The FATAL error will never happen if + * the input rules are correct. + */ while (buf.len > 0 && buf.len > col->metaEntry.type2.maxSize) { if (buf.data[buf.len - 2] != ' ' || buf.data[buf.len - 1] != '\0') @@ -2716,7 +2848,7 @@ TdsSendTypeNVarchar(FmgrInfo *finfo, Datum value, void *vMetaData) rc = TdsSendPlpDataHelper(buf.data, buf.len); } - pfree(buf.data); + pfree(buf.data); return rc; } @@ -2724,22 +2856,22 @@ int TdsSendTypeNChar(FmgrInfo *finfo, Datum value, void *vMetaData) { - int rc, len; - char *out = OutputFunctionCall(finfo, value); - TdsColumnMetaData *col = (TdsColumnMetaData *)vMetaData; - StringInfoData buf; + int rc, + len; + char *out = OutputFunctionCall(finfo, value); + TdsColumnMetaData *col = (TdsColumnMetaData *) vMetaData; + StringInfoData buf; initStringInfo(&buf); TdsUTF8toUTF16StringInfo(&buf, out, strlen(out)); /* * This is a special case we are making for TDS clients. TSQL treats - * on-the-wire data really as UCS2, not UTF16. While we try our best - * to detect possible problems on input, the special rules about - * truncating trailing spaces allow to enter data that exceeds the - * number of 16-bit units to be sent here. In a best effort approach - * we strip extra spaces here. The FATAL error will never happen - * if the input rules are correct. + * on-the-wire data really as UCS2, not UTF16. While we try our best to + * detect possible problems on input, the special rules about truncating + * trailing spaces allow to enter data that exceeds the number of 16-bit + * units to be sent here. In a best effort approach we strip extra spaces + * here. The FATAL error will never happen if the input rules are correct. */ while (buf.len > 0 && buf.len > col->metaEntry.type2.maxSize) { @@ -2749,9 +2881,9 @@ TdsSendTypeNChar(FmgrInfo *finfo, Datum value, void *vMetaData) } /* - * Add explicit padding, Otherwise can give garbage in some cases. - * This code needs to be removed and padding should be handled - * internally - BABEL-273 + * Add explicit padding, Otherwise can give garbage in some cases. This + * code needs to be removed and padding should be handled internally - + * BABEL-273 */ len = buf.len; while (len < col->metaEntry.type2.maxSize) @@ -2761,7 +2893,7 @@ TdsSendTypeNChar(FmgrInfo *finfo, Datum value, void *vMetaData) len += 2; } - len = col->metaEntry.type2.maxSize; + len = col->metaEntry.type2.maxSize; if ((rc = TdsPutInt16LE(len)) == 0) TdsPutbytes(buf.data, len); @@ -2773,9 +2905,11 @@ TdsSendTypeNChar(FmgrInfo *finfo, Datum value, void *vMetaData) int TdsSendTypeMoney(FmgrInfo *finfo, Datum value, void *vMetaData) { - int rc = 0, length = 8; - uint32 low = 0, high = 0; - uint64 out = DatumGetUInt64(value); + int rc = 0, + length = 8; + uint32 low = 0, + high = 0; + uint64 out = DatumGetUInt64(value); TDSInstrumentation(INSTR_TDS_DATATYPE_MONEY); @@ -2783,7 +2917,7 @@ TdsSendTypeMoney(FmgrInfo *finfo, Datum value, void *vMetaData) high = (out >> 32) & 0xffffffff; /* Don't send the length if the column type is not null. */ - if (!((TdsColumnMetaData *)vMetaData)->attNotNull) + if (!((TdsColumnMetaData *) vMetaData)->attNotNull) rc = TdsPutInt8(length); if (rc == 0) @@ -2797,9 +2931,11 @@ TdsSendTypeMoney(FmgrInfo *finfo, Datum value, void *vMetaData) int TdsSendTypeSmallmoney(FmgrInfo *finfo, Datum value, void *vMetaData) { - int rc = 0, length = 4; - uint32 low = 0, high = 0; - uint64 out = DatumGetUInt64(value); + int rc = 0, + length = 4; + uint32 low = 0, + high = 0; + uint64 out = DatumGetUInt64(value); TDSInstrumentation(INSTR_TDS_DATATYPE_SMALLMONEY); @@ -2807,13 +2943,13 @@ TdsSendTypeSmallmoney(FmgrInfo *finfo, Datum value, void *vMetaData) high = (out >> 32) & 0xffffffff; if (high != 0xffffffff && high != 0) { - ereport(ERROR,(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("SMALLMONEY exceeds permissible range of 4 bytes!"))); + ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("SMALLMONEY exceeds permissible range of 4 bytes!"))); return EOF; } /* Don't send the length if the column type is not null. */ - if (!((TdsColumnMetaData *)vMetaData)->attNotNull) + if (!((TdsColumnMetaData *) vMetaData)->attNotNull) rc = TdsPutInt8(length); if (rc == 0) @@ -2824,13 +2960,15 @@ TdsSendTypeSmallmoney(FmgrInfo *finfo, Datum value, void *vMetaData) int TdsSendTypeSmalldatetime(FmgrInfo *finfo, Datum value, void *vMetaData) { - int rc = 0, length = 4; - uint16 numDays = 0, numMins = 0; + int rc = 0, + length = 4; + uint16 numDays = 0, + numMins = 0; TdsTimeDifferenceSmalldatetime(value, &numDays, &numMins); /* Don't send the length if the column type is not null. */ - if (!((TdsColumnMetaData *)vMetaData)->attNotNull) + if (!((TdsColumnMetaData *) vMetaData)->attNotNull) rc = TdsPutInt8(length); if (rc == 0) @@ -2844,13 +2982,15 @@ TdsSendTypeSmalldatetime(FmgrInfo *finfo, Datum value, void *vMetaData) int TdsSendTypeDate(FmgrInfo *finfo, Datum value, void *vMetaData) { - int rc = 0, length = 3; - uint32 numDays = 0; + int rc = 0, + length = 3; + uint32 numDays = 0; if (GetClientTDSVersion() < TDS_VERSION_7_3_A) + /* - * If client being connected is using TDS version lower than 7.3A - * then TSQL treats DATE as NVARCHAR. + * If client being connected is using TDS version lower than 7.3A then + * TSQL treats DATE as NVARCHAR. */ return TdsSendTypeNVarchar(finfo, value, vMetaData); @@ -2864,13 +3004,15 @@ TdsSendTypeDate(FmgrInfo *finfo, Datum value, void *vMetaData) int TdsSendTypeDatetime(FmgrInfo *finfo, Datum value, void *vMetaData) { - int rc = 0, length = 8; - uint32 numDays = 0, numTicks = 0; + int rc = 0, + length = 8; + uint32 numDays = 0, + numTicks = 0; TdsTimeDifferenceDatetime(value, &numDays, &numTicks); /* Don't send the length if the column type is not null. */ - if (!((TdsColumnMetaData *)vMetaData)->attNotNull) + if (!((TdsColumnMetaData *) vMetaData)->attNotNull) rc = TdsPutInt8(length); if (rc == 0) @@ -2890,13 +3032,17 @@ TdsSendTypeDatetime(FmgrInfo *finfo, Datum value, void *vMetaData) int TdsSendTypeNumeric(FmgrInfo *finfo, Datum value, void *vMetaData) { - int rc = EOF, precision = 0, scale = -1; - uint8 sign = 1, length = 0; - char *out, *decString; - uint128 num = 0; - TdsColumnMetaData *col = (TdsColumnMetaData *)vMetaData; - uint8_t max_scale = col->metaEntry.type5.scale; - uint8_t max_precision = col->metaEntry.type5.precision; + int rc = EOF, + precision = 0, + scale = -1; + uint8 sign = 1, + length = 0; + char *out, + *decString; + uint128 num = 0; + TdsColumnMetaData *col = (TdsColumnMetaData *) vMetaData; + uint8_t max_scale = col->metaEntry.type5.scale; + uint8_t max_precision = col->metaEntry.type5.precision; out = OutputFunctionCall(finfo, value); if (out[0] == '-') @@ -2906,11 +3052,12 @@ TdsSendTypeNumeric(FmgrInfo *finfo, Datum value, void *vMetaData) } if (out[0] == '0') out++; + /* - * response string is formatted to obtain string representation - * of TDS unsigned integer along with its precision and scale + * response string is formatted to obtain string representation of TDS + * unsigned integer along with its precision and scale */ - decString = (char *)palloc(sizeof(char) * (strlen(out) + 1)); + decString = (char *) palloc(sizeof(char) * (strlen(out) + 1)); /* While there is still digit in out and we haven't reached max_scale */ while (*out && scale < max_scale) { @@ -2932,10 +3079,11 @@ TdsSendTypeNumeric(FmgrInfo *finfo, Datum value, void *vMetaData) scale = 0; /* - * Fill in the remaining 0's if the processed scale from out is less than max_scale - * This is needed because the output generated by engine may not always - * produce the same precision/scale as calculated by resolve_numeric_typmod_from_exp, - * which is the precision/scale we have sent to the client with column metadata. + * Fill in the remaining 0's if the processed scale from out is less than + * max_scale This is needed because the output generated by engine may not + * always produce the same precision/scale as calculated by + * resolve_numeric_typmod_from_exp, which is the precision/scale we have + * sent to the client with column metadata. */ while (scale++ < max_scale) { @@ -2946,7 +3094,7 @@ TdsSendTypeNumeric(FmgrInfo *finfo, Datum value, void *vMetaData) if (precision > TDS_MAX_NUM_PRECISION || precision > max_precision) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("Arithmetic overflow error for data type numeric."))); + errmsg("Arithmetic overflow error for data type numeric."))); if (precision >= 1 && precision < 10) length = 4; @@ -3005,23 +3153,26 @@ TdsSendTypeUniqueIdentifier(FmgrInfo *finfo, Datum value, void *vMetaData) int TdsSendTypeTime(FmgrInfo *finfo, Datum value, void *vMetaData) { - int rc = EOF, length = 0, scale = 0; + int rc = EOF, + length = 0, + scale = 0; uint64_t res = 0; double numSec = 0; - TdsColumnMetaData *col = (TdsColumnMetaData *)vMetaData; + TdsColumnMetaData *col = (TdsColumnMetaData *) vMetaData; if (GetClientTDSVersion() < TDS_VERSION_7_3_A) + /* - * If client being connected is using TDS version lower than 7.3A - * then TSQL treats TIME as NVARCHAR. + * If client being connected is using TDS version lower than 7.3A then + * TSQL treats TIME as NVARCHAR. */ return TdsSendTypeNVarchar(finfo, value, vMetaData); scale = col->metaEntry.type6.scale; /* - * if time data has no specific scale specified in the query, default scale - * to be considered is 7 always. + * if time data has no specific scale specified in the query, default + * scale to be considered is 7 always. */ if (scale == 255) scale = DATETIMEOFFSETMAXSCALE; @@ -3033,13 +3184,13 @@ TdsSendTypeTime(FmgrInfo *finfo, Datum value, void *vMetaData) else if (scale >= 5 && scale <= 7) length = 5; - numSec = (double)value / 1000000; + numSec = (double) value / 1000000; while (scale--) numSec *= 10; /* Round res to the nearest integer */ numSec += 0.5; - res = (uint64_t)numSec; + res = (uint64_t) numSec; if ((rc = TdsPutInt8(length)) == 0) rc = TdsPutbytes(&res, length); return rc; @@ -3048,22 +3199,26 @@ TdsSendTypeTime(FmgrInfo *finfo, Datum value, void *vMetaData) int TdsSendTypeDatetime2(FmgrInfo *finfo, Datum value, void *vMetaData) { - int rc = EOF, length = 0, scale = 0; + int rc = EOF, + length = 0, + scale = 0; uint64 numSec = 0; uint32 numDays = 0; - TdsColumnMetaData *col = (TdsColumnMetaData *)vMetaData; + TdsColumnMetaData *col = (TdsColumnMetaData *) vMetaData; if (GetClientTDSVersion() < TDS_VERSION_7_3_A) + /* - * If client being connected is using TDS version lower than 7.3A - * then TSQL treats DATETIME2 as NVARCHAR. + * If client being connected is using TDS version lower than 7.3A then + * TSQL treats DATETIME2 as NVARCHAR. */ return TdsSendTypeNVarchar(finfo, value, vMetaData); scale = col->metaEntry.type6.scale; + /* - * if Datetime2 data has no specific scale specified in the query, default scale - * to be considered is 7 always. + * if Datetime2 data has no specific scale specified in the query, default + * scale to be considered is 7 always. */ if (scale == 255) scale = DATETIMEOFFSETMAXSCALE; @@ -3075,11 +3230,11 @@ TdsSendTypeDatetime2(FmgrInfo *finfo, Datum value, void *vMetaData) else if (scale >= 5 && scale <= 7) length = 8; - TdsGetDayTimeFromTimestamp((Timestamp)value, &numDays, - &numSec, scale); + TdsGetDayTimeFromTimestamp((Timestamp) value, &numDays, + &numSec, scale); if (TdsPutInt8(length) == 0 && - TdsPutbytes(&numSec, length - 3) == 0) + TdsPutbytes(&numSec, length - 3) == 0) rc = TdsPutDate(numDays); return rc; @@ -3088,7 +3243,8 @@ TdsSendTypeDatetime2(FmgrInfo *finfo, Datum value, void *vMetaData) static void SwapByte(char *buf, int st, int end) { - char temp = buf[st]; + char temp = buf[st]; + buf[st] = buf[end]; buf[end] = temp; } @@ -3097,70 +3253,78 @@ SwapByte(char *buf, int st, int end) Datum TdsTypeSqlVariantToDatum(StringInfo buf) { - bytea *result = 0; + bytea *result = 0; uint8 variantBaseType = 0; - int pgBaseType = 0; - int dataLen = 0, i = 0, len = 0; - int tempScale = 0, tempLen = 0; - int variantHeaderLen = 0, maxLen = 0, resLen = 0; - uint8_t scale = 0, precision = 0, sign = 1, temp = 0; + int pgBaseType = 0; + int dataLen = 0, + i = 0, + len = 0; + int tempScale = 0, + tempLen = 0; + int variantHeaderLen = 0, + maxLen = 0, + resLen = 0; + uint8_t scale = 0, + precision = 0, + sign = 1, + temp = 0; DateADT date = 0; - uint64 numMicro = 0, dateval = 0; - uint16 numDays = 0, numMins = 0; + uint64 numMicro = 0, + dateval = 0; + uint16 numDays = 0, + numMins = 0; int16 timezone = 0; - uint32 numDays32 = 0, numTicks = 0; + uint32 numDays32 = 0, + numTicks = 0; Timestamp timestamp = 0; - TimestampTz timestamptz = 0; + TimestampTz timestamptz = 0; Numeric res = 0; - char *decString, temp1, temp2; - uint128 n128 = 0, num = 0; - StringInfoData strbuf; - tsql_datetimeoffset *tdt = (tsql_datetimeoffset *) palloc0(DATETIMEOFFSET_LEN); + char *decString, + temp1, + temp2; + uint128 n128 = 0, + num = 0; + StringInfoData strbuf; + tsql_datetimeoffset *tdt = (tsql_datetimeoffset *) palloc0(DATETIMEOFFSET_LEN); variantBaseType = buf->data[0]; tempLen = buf->len - buf->cursor; pltsql_plugin_handler_ptr->sqlvariant_get_pg_base_type(variantBaseType, &pgBaseType, - tempLen, &dataLen, &variantHeaderLen); + tempLen, &dataLen, &variantHeaderLen); /* * Header formats: * - * 3-byte Header (for datetime series types with typmod): - * 1. One byte varlena Header - * 2. One byte type code (5bit) + MD ver (3bit) - * 3. One byte scale + * 3-byte Header (for datetime series types with typmod): 1. One byte + * varlena Header 2. One byte type code (5bit) + MD ver (3bit) 3. One byte + * scale * - * 2-byte Header (for fixed length types without typmod): - * 1. One byte varlena Header - * 2. One byte type code (5bit) + MD ver (3bit) + * 2-byte Header (for fixed length types without typmod): 1. One byte + * varlena Header 2. One byte type code (5bit) + MD ver (3bit) * - * 4-byte Header (for decimal type): - * 1. One byte varlena Header - * 2. One byte type code (5bit) + MD ver (3bit) - * 3. Two bytes typmod (encoded precision and scale) + * 4-byte Header (for decimal type): 1. One byte varlena Header 2. One + * byte type code (5bit) + MD ver (3bit) 3. Two bytes typmod (encoded + * precision and scale) * - * Header for binary types: - * 1. 1 or 4 bytes varlena header - * 2. One byte type code ( 5bit ) + MD ver (3bit) - * 3. 2 Bytes max length + * Header for binary types: 1. 1 or 4 bytes varlena header 2. One byte + * type code ( 5bit ) + MD ver (3bit) 3. 2 Bytes max length * - * Header for string types: - * 1. 1 or 4 bytes varlena Header - * 2. One byte type code (5bit) + MD ver (3bit) - * 3. Two bytes for max length - * 4. Two bytes for collation code + * Header for string types: 1. 1 or 4 bytes varlena Header 2. One byte + * type code (5bit) + MD ver (3bit) 3. Two bytes for max length 4. Two + * bytes for collation code */ - + /* - * If base type is N[VAR]CHAR then we have to use length of data in UTF8 format as datalen. + * If base type is N[VAR]CHAR then we have to use length of data in UTF8 + * format as datalen. */ if (variantBaseType == VARIANT_TYPE_NCHAR || variantBaseType == VARIANT_TYPE_NVARCHAR) { /* - * dataformat: totalLen(4B) + metadata(9B)( baseType(1B) + metadatalen(1B) + - * encodingLen(5B) + dataLen(2B) ) + data(dataLen) + * dataformat: totalLen(4B) + metadata(9B)( baseType(1B) + + * metadatalen(1B) + encodingLen(5B) + dataLen(2B) ) + data(dataLen) * Data is in UTF16 format. */ initStringInfo(&strbuf); @@ -3171,11 +3335,11 @@ TdsTypeSqlVariantToDatum(StringInfo buf) resLen = dataLen + variantHeaderLen; /* We need an extra varlena header for varlena datatypes */ - if (variantBaseType == VARIANT_TYPE_CHAR || + if (variantBaseType == VARIANT_TYPE_CHAR || variantBaseType == VARIANT_TYPE_NCHAR || - variantBaseType == VARIANT_TYPE_VARCHAR || + variantBaseType == VARIANT_TYPE_VARCHAR || variantBaseType == VARIANT_TYPE_NVARCHAR || - variantBaseType == VARIANT_TYPE_BINARY || + variantBaseType == VARIANT_TYPE_BINARY || variantBaseType == VARIANT_TYPE_VARBINARY || variantBaseType == VARIANT_TYPE_NUMERIC || variantBaseType == VARIANT_TYPE_DECIMAL || @@ -3200,19 +3364,19 @@ TdsTypeSqlVariantToDatum(StringInfo buf) SET_VARSIZE(result, resLen); } - if (variantBaseType == VARIANT_TYPE_CHAR || + if (variantBaseType == VARIANT_TYPE_CHAR || variantBaseType == VARIANT_TYPE_NCHAR || - variantBaseType == VARIANT_TYPE_VARCHAR || - variantBaseType == VARIANT_TYPE_NVARCHAR) + variantBaseType == VARIANT_TYPE_VARCHAR || + variantBaseType == VARIANT_TYPE_NVARCHAR) { SET_VARSIZE(READ_DATA(result, variantHeaderLen), VARHDRSZ + dataLen); memcpy(&maxLen, &buf->data[7], 2); if (variantBaseType == VARIANT_TYPE_NCHAR || variantBaseType == VARIANT_TYPE_NVARCHAR) { /* - * dataformat: totalLen(4B) + metadata(9B)( baseType(1B) + metadatalen(1B) + - * encodingLen(5B) + dataLen(2B) ) + data(dataLen) - * Data is in UTF16 format. + * dataformat: totalLen(4B) + metadata(9B)( baseType(1B) + + * metadatalen(1B) + encodingLen(5B) + dataLen(2B) ) + + * data(dataLen) Data is in UTF16 format. */ memcpy(VARDATA(READ_DATA(result, variantHeaderLen)), strbuf.data, dataLen); pfree(strbuf.data); @@ -3220,18 +3384,19 @@ TdsTypeSqlVariantToDatum(StringInfo buf) else { /* - * dataformat: totalLen(4B) + metadata(9B)( baseType(1B) + metadatalen(1B) + - * encodingLen(5B) + dataLen(2B) ) + data(dataLen) + * dataformat: totalLen(4B) + metadata(9B)( baseType(1B) + + * metadatalen(1B) + encodingLen(5B) + dataLen(2B) ) + + * data(dataLen) */ memcpy(VARDATA(READ_DATA(result, variantHeaderLen)), &buf->data[VARIANT_TYPE_METALEN_FOR_CHAR_DATATYPES], dataLen); } } - else if (variantBaseType == VARIANT_TYPE_BINARY || - variantBaseType == VARIANT_TYPE_VARBINARY) + else if (variantBaseType == VARIANT_TYPE_BINARY || + variantBaseType == VARIANT_TYPE_VARBINARY) { /* - * dataformat : totalLen(4B) + metadata(4B)( baseType(1B) + metadatalen(1B) + - * dataLen(2B) ) + data(dataLen) + * dataformat : totalLen(4B) + metadata(4B)( baseType(1B) + + * metadatalen(1B) + dataLen(2B) ) + data(dataLen) */ SET_VARSIZE(READ_DATA(result, variantHeaderLen), VARHDRSZ + dataLen); memcpy(&maxLen, &buf->data[2], 2); @@ -3240,8 +3405,8 @@ TdsTypeSqlVariantToDatum(StringInfo buf) else if (variantBaseType == VARIANT_TYPE_DATE) { /* - * dataformat : totalLen(4B) + metadata(2B)( baseType(1B) + metadatalen(1B) ) + - * data(3B) + * dataformat : totalLen(4B) + metadata(2B)( baseType(1B) + + * metadatalen(1B) ) + data(3B) */ memset(&date, 0, sizeof(date)); memcpy(&date, &buf->data[VARIANT_TYPE_METALEN_FOR_DATE], 3); @@ -3252,8 +3417,8 @@ TdsTypeSqlVariantToDatum(StringInfo buf) else if (variantBaseType == VARIANT_TYPE_SMALLDATETIME) { /* - * dataformat : totalLen(4B) + metadata(2B)( baseType(1B) + metadatalen(1B) ) + - * data(4B) + * dataformat : totalLen(4B) + metadata(2B)( baseType(1B) + + * metadatalen(1B) ) + data(4B) */ memcpy(&numDays, &buf->data[VARIANT_TYPE_METALEN_FOR_SMALLDATETIME], 2); memcpy(&numMins, &buf->data[4], 2); @@ -3263,8 +3428,8 @@ TdsTypeSqlVariantToDatum(StringInfo buf) else if (variantBaseType == VARIANT_TYPE_DATETIME) { /* - * dataformat : totalLen(4B) + metadata(2B)( baseType(1B) + metadatalen(1B) ) + - * data(8B) + * dataformat : totalLen(4B) + metadata(2B)( baseType(1B) + + * metadatalen(1B) ) + data(8B) */ memcpy(&numDays32, &buf->data[VARIANT_TYPE_METALEN_FOR_DATETIME], 4); memcpy(&numTicks, &buf->data[6], 4); @@ -3274,11 +3439,11 @@ TdsTypeSqlVariantToDatum(StringInfo buf) else if (variantBaseType == VARIANT_TYPE_TIME) { /* - * dataformat : totalLen(4B) + metadata(3B)( baseType(1B) + metadatalen(1B) + - * scale(1B) ) + data(3B-5B) + * dataformat : totalLen(4B) + metadata(3B)( baseType(1B) + + * metadatalen(1B) + scale(1B) ) + data(3B-5B) */ scale = buf->data[2]; - temp = scale; + temp = scale; /* postgres limitation */ if (scale > 7 || scale < 0) scale = DATETIMEOFFSETMAXSCALE; @@ -3295,25 +3460,25 @@ TdsTypeSqlVariantToDatum(StringInfo buf) if (temp == 7 || temp == 0xff) numMicro /= 10; - + while (scale < 6) { numMicro *= 10; scale++; } scale = temp; - memcpy(READ_DATA(result, variantHeaderLen), &numMicro, sizeof(numMicro)); + memcpy(READ_DATA(result, variantHeaderLen), &numMicro, sizeof(numMicro)); } else if (variantBaseType == VARIANT_TYPE_DATETIME2) { /* - * dataformat : totalLen(4B) + metadata(3B)( baseType(1B) + metadatalen(1B) + - * scale(1B) ) + data(6B-8B) + * dataformat : totalLen(4B) + metadata(3B)( baseType(1B) + + * metadatalen(1B) + scale(1B) ) + data(6B-8B) */ scale = buf->data[2]; - + /* postgres limitation */ - if (scale > 7 || scale == 0xff || scale < 0) + if (scale > 7 || scale == 0xff || scale < 0) scale = DATETIMEOFFSETMAXSCALE; if (scale <= 2) @@ -3322,7 +3487,7 @@ TdsTypeSqlVariantToDatum(StringInfo buf) dataLen = 7; else if (scale <= 7) dataLen = 8; - + memset(&numDays32, 0, sizeof(numDays32)); memset(&numMicro, 0, sizeof(numMicro)); memcpy(&numDays32, &buf->data[VARIANT_TYPE_METALEN_FOR_DATETIME2], 3); @@ -3333,11 +3498,11 @@ TdsTypeSqlVariantToDatum(StringInfo buf) else if (variantBaseType == VARIANT_TYPE_DATETIMEOFFSET) { /* - * dataformat : totalLen(4B) + metadata(3B)(baseType(1B) + metadatalen(1B) + - * scale(1B)) + data(8B-10B) + * dataformat : totalLen(4B) + metadata(3B)(baseType(1B) + + * metadatalen(1B) + scale(1B)) + data(8B-10B) */ scale = buf->data[2]; - + /* postgres limitation */ if (scale > 7 || scale == 0xff || scale < 0) scale = DATETIMEOFFSETMAXSCALE; @@ -3348,7 +3513,7 @@ TdsTypeSqlVariantToDatum(StringInfo buf) dataLen = 9; else if (scale <= 7) dataLen = 10; - + memset(&numDays32, 0, sizeof(numDays32)); memset(&numMicro, 0, sizeof(numMicro)); memcpy(&numDays32, &buf->data[dataLen - 2], 3); @@ -3356,7 +3521,7 @@ TdsTypeSqlVariantToDatum(StringInfo buf) memcpy(&timezone, &buf->data[dataLen + 1], 2); timezone *= -1; - TdsGetTimestampFromDayTime(numDays32, numMicro, (int)timezone, ×tamptz, scale); + TdsGetTimestampFromDayTime(numDays32, numMicro, (int) timezone, ×tamptz, scale); timestamptz -= (timezone * SECS_PER_MINUTE * USECS_PER_SEC); timestamptz -= (timezone * USECS_PER_SEC); @@ -3367,8 +3532,9 @@ TdsTypeSqlVariantToDatum(StringInfo buf) else if (variantBaseType == VARIANT_TYPE_NUMERIC || variantBaseType == VARIANT_TYPE_DECIMAL) { /* - * dataformat : totalLen(4B) + metdata(5B)( baseType(1B) + metadatalen(1B) + - * precision(1B) + scale(1B) + sign(1B) ) + data(dataLen) + * dataformat : totalLen(4B) + metdata(5B)( baseType(1B) + + * metadatalen(1B) + precision(1B) + scale(1B) + sign(1B) ) + + * data(dataLen) */ SET_VARSIZE(READ_DATA(result, variantHeaderLen), VARHDRSZ + dataLen); precision = buf->data[2]; @@ -3379,7 +3545,7 @@ TdsTypeSqlVariantToDatum(StringInfo buf) dataLen = 16; memcpy(&n128, &buf->data[VARIANT_TYPE_METALEN_FOR_NUMERIC_DATATYPES], dataLen); num = LEtoh128(n128); - decString = (char *)palloc0(sizeof(char) * 40); + decString = (char *) palloc0(sizeof(char) * 40); if (num != 0) Integer2String(num, decString); else @@ -3410,7 +3576,7 @@ TdsTypeSqlVariantToDatum(StringInfo buf) if (sign == 1 && num != 0) decString++; res = TdsSetVarFromStrWrapper(decString); - memcpy(READ_DATA(result, variantHeaderLen), (bytea *)DatumGetPointer(res), dataLen); + memcpy(READ_DATA(result, variantHeaderLen), (bytea *) DatumGetPointer(res), dataLen); } else { @@ -3422,8 +3588,8 @@ TdsTypeSqlVariantToDatum(StringInfo buf) if (variantBaseType == VARIANT_TYPE_MONEY) { /* - * swap positions of 2 nibbles for money type - * to match SQL behaviour + * swap positions of 2 nibbles for money type to match SQL + * behaviour */ for (i = 0; i < 4; i++) SwapByte(READ_DATA(result, variantHeaderLen), i, i + 4); @@ -3439,7 +3605,7 @@ TdsTypeSqlVariantToDatum(StringInfo buf) } pltsql_plugin_handler_ptr->sqlvariant_set_metadata(result, - pgBaseType, scale, precision, maxLen); + pgBaseType, scale, precision, maxLen); buf->cursor += tempLen; @@ -3450,36 +3616,52 @@ TdsTypeSqlVariantToDatum(StringInfo buf) int TdsSendTypeSqlvariant(FmgrInfo *finfo, Datum value, void *vMetaData) { - int rc = EOF, variantBaseType = 0; + int rc = EOF, + variantBaseType = 0; uint8_t pgBaseType = 0; - int dataLen = 0, totalLen = 0, maxLen = 0, variantHeaderLen = 0; - bytea *vlena = DatumGetByteaPCopy(value); - char *buf = VARDATA(vlena), *decString = NULL, *out = NULL; - bool isBaseNum = false, isBaseChar = false; - bool isBaseBin = false, isBaseDec = false, isBaseDate = false; - uint32 numDays = 0, numTicks = 0, dateval = 0; - uint16 numMins = 0, numDays16 = 0; + int dataLen = 0, + totalLen = 0, + maxLen = 0, + variantHeaderLen = 0; + bytea *vlena = DatumGetByteaPCopy(value); + char *buf = VARDATA(vlena), + *decString = NULL, + *out = NULL; + bool isBaseNum = false, + isBaseChar = false; + bool isBaseBin = false, + isBaseDec = false, + isBaseDate = false; + uint32 numDays = 0, + numTicks = 0, + dateval = 0; + uint16 numMins = 0, + numDays16 = 0; uint64 numMicro = 0; int16 timezone = 0; - int precision = 0, scale = -1, sign = 1, i = 0, temp = 0; + int precision = 0, + scale = -1, + sign = 1, + i = 0, + temp = 0; uint128 num = 0; Timestamp timestamp = 0; - TimestampTz timestamptz = 0; + TimestampTz timestamptz = 0; TDSInstrumentation(INSTR_TDS_DATATYPE_SQLVARIANT); /* - * First sql variant header byte contains: - * type code ( 5bit ) + MD ver (3bit) + * First sql variant header byte contains: type code ( 5bit ) + MD ver + * (3bit) */ pgBaseType = pltsql_plugin_handler_ptr->sqlvariant_inline_pg_base_type(vlena); pltsql_plugin_handler_ptr->sqlvariant_get_metadata(vlena, pgBaseType, - &scale, &precision, &maxLen); + &scale, &precision, &maxLen); pltsql_plugin_handler_ptr->sqlvariant_get_variant_base_type(pgBaseType, - &variantBaseType, &isBaseNum, &isBaseChar, - &isBaseDec, &isBaseBin, &isBaseDate, &variantHeaderLen); + &variantBaseType, &isBaseNum, &isBaseChar, + &isBaseDec, &isBaseBin, &isBaseDate, &variantHeaderLen); dataLen = VARSIZE_ANY_EXHDR(vlena) - variantHeaderLen; buf += variantHeaderLen; @@ -3488,7 +3670,7 @@ TdsSendTypeSqlvariant(FmgrInfo *finfo, Datum value, void *vMetaData) { /* * dataformat: totalLen(4B) + baseType(1B) + metadatalen(1B) + - * data(dataLen) + * data(dataLen) */ if (variantBaseType == VARIANT_TYPE_TINYINT) dataLen = 1; @@ -3499,8 +3681,8 @@ TdsSendTypeSqlvariant(FmgrInfo *finfo, Datum value, void *vMetaData) if (variantBaseType == VARIANT_TYPE_MONEY) { /* - * swap positions of 2 nibbles for money type - * to match SQL behaviour + * swap positions of 2 nibbles for money type to match SQL + * behaviour */ for (i = 0; i < 4; i++) SwapByte(buf, i, i + 4); @@ -3525,14 +3707,17 @@ TdsSendTypeSqlvariant(FmgrInfo *finfo, Datum value, void *vMetaData) { /* * dataformat: totalLen(4B) + baseType(1B) + metadatalen(1B) + - * encodingLen(5B) + dataLen(2B) + data(dataLen) + * encodingLen(5B) + dataLen(2B) + data(dataLen) */ - StringInfoData strbuf; - int actualDataLen = 0; /* Number of bytes that would be needed to store given string in given encoding. */ - char *destBuf = NULL; + StringInfoData strbuf; + int actualDataLen = 0; /* Number of bytes that would be + * needed to store given string in + * given encoding. */ + char *destBuf = NULL; + dataLen -= VARHDRSZ; if (variantBaseType == VARIANT_TYPE_NCHAR || - variantBaseType == VARIANT_TYPE_NVARCHAR) + variantBaseType == VARIANT_TYPE_NVARCHAR) { initStringInfo(&strbuf); TdsUTF8toUTF16StringInfo(&strbuf, buf + VARHDRSZ, dataLen); @@ -3540,12 +3725,12 @@ TdsSendTypeSqlvariant(FmgrInfo *finfo, Datum value, void *vMetaData) } else { - /* - * TODO: [BABEL-1069] Remove collation related hardcoding - * from sql_variant sender for char class basetypes + /* + * TODO: [BABEL-1069] Remove collation related hardcoding from + * sql_variant sender for char class basetypes */ if (dataLen > 0) - destBuf = TdsEncodingConversion(buf + VARHDRSZ, dataLen, PG_UTF8 ,PG_WIN1252, &actualDataLen); + destBuf = TdsEncodingConversion(buf + VARHDRSZ, dataLen, PG_UTF8, PG_WIN1252, &actualDataLen); else /* We can not assume that buf would be NULL terminated. */ actualDataLen = 0; @@ -3556,10 +3741,10 @@ TdsSendTypeSqlvariant(FmgrInfo *finfo, Datum value, void *vMetaData) rc = TdsPutUInt32LE(totalLen); rc |= TdsPutInt8(variantBaseType); rc |= TdsPutInt8(VARIANT_TYPE_BASE_METALEN_FOR_CHAR_DATATYPES); + /* - * 5B of fixed collation - * TODO: [BABEL-1069] Remove collation related hardcoding - * from sql_variant sender for char class basetypes + * 5B of fixed collation TODO: [BABEL-1069] Remove collation related + * hardcoding from sql_variant sender for char class basetypes */ rc |= TdsPutInt8(9); rc |= TdsPutInt8(4); @@ -3570,12 +3755,12 @@ TdsSendTypeSqlvariant(FmgrInfo *finfo, Datum value, void *vMetaData) rc |= TdsPutUInt16LE(actualDataLen); if (variantBaseType == VARIANT_TYPE_NCHAR || - variantBaseType == VARIANT_TYPE_NVARCHAR) + variantBaseType == VARIANT_TYPE_NVARCHAR) { rc |= TdsPutbytes(strbuf.data, actualDataLen); pfree(strbuf.data); } - else + else rc |= TdsPutbytes(destBuf, actualDataLen); if (destBuf) @@ -3585,7 +3770,7 @@ TdsSendTypeSqlvariant(FmgrInfo *finfo, Datum value, void *vMetaData) { /* * dataformat : totalLen(4B) + baseType(1B) + metadatalen(1B) + - * dataLen(2B) + data(dataLen) + * dataLen(2B) + data(dataLen) */ dataLen = dataLen - VARHDRSZ; totalLen = dataLen + VARIANT_TYPE_METALEN_FOR_BIN_DATATYPES; @@ -3600,7 +3785,7 @@ TdsSendTypeSqlvariant(FmgrInfo *finfo, Datum value, void *vMetaData) { /* * dataformat : totalLen(4B) + baseType(1B) + metadatalen(1B) + - * precision(1B) + scale(1B) + sign(1B) + data(dataLen) + * precision(1B) + scale(1B) + sign(1B) + data(dataLen) */ dataLen = 16; totalLen = dataLen + VARIANT_TYPE_METALEN_FOR_NUMERIC_DATATYPES; @@ -3611,7 +3796,7 @@ TdsSendTypeSqlvariant(FmgrInfo *finfo, Datum value, void *vMetaData) sign = 0; out++; } - decString = (char *)palloc(sizeof(char) * (strlen(out) + 1)); + decString = (char *) palloc(sizeof(char) * (strlen(out) + 1)); precision = 0, scale = -1; while (out && *out) { @@ -3643,7 +3828,7 @@ TdsSendTypeSqlvariant(FmgrInfo *finfo, Datum value, void *vMetaData) { /* * dataformat : totalLen(4B) + baseType(1B) + metadatalen(1B) + - * data(3B) + * data(3B) */ if (variantBaseType == VARIANT_TYPE_DATE) @@ -3658,15 +3843,16 @@ TdsSendTypeSqlvariant(FmgrInfo *finfo, Datum value, void *vMetaData) rc |= TdsPutInt8(VARIANT_TYPE_BASE_METALEN_FOR_DATE); rc |= TdsPutDate(numDays); } + /* * dataformat : totalLen(4B) + baseType(1B) + metadatalen(1B) + - * data(4B) + * data(4B) */ else if (variantBaseType == VARIANT_TYPE_SMALLDATETIME) { memcpy(×tamp, buf, sizeof(timestamp)); dataLen = 4; - totalLen = dataLen + VARIANT_TYPE_METALEN_FOR_SMALLDATETIME; + totalLen = dataLen + VARIANT_TYPE_METALEN_FOR_SMALLDATETIME; TdsTimeDifferenceSmalldatetime(timestamp, &numDays16, &numMins); rc = TdsPutUInt32LE(totalLen); rc |= TdsPutInt8(variantBaseType); @@ -3674,9 +3860,10 @@ TdsSendTypeSqlvariant(FmgrInfo *finfo, Datum value, void *vMetaData) rc |= TdsPutUInt16LE(numDays16); rc |= TdsPutUInt16LE(numMins); } + /* * dataformat : totalLen(4B) + baseType(1B) + metadatalen(1B) + - * data(8B) + * data(8B) */ else if (variantBaseType == VARIANT_TYPE_DATETIME) { @@ -3692,10 +3879,10 @@ TdsSendTypeSqlvariant(FmgrInfo *finfo, Datum value, void *vMetaData) } else if (variantBaseType == VARIANT_TYPE_TIME) { - /* - * dataformat : totalLen(4B) + baseType(1B) + metadatalen(1B) + - * scale(1B) + data(3B-5B) - */ + /* + * dataformat : totalLen(4B) + baseType(1B) + metadatalen(1B) + + * scale(1B) + data(3B-5B) + */ if (scale == 0xff || scale < 0 || scale > 7) scale = DATETIMEOFFSETMAXSCALE; @@ -3723,12 +3910,12 @@ TdsSendTypeSqlvariant(FmgrInfo *finfo, Datum value, void *vMetaData) rc |= TdsPutInt8(scale); rc = TdsPutbytes(&numMicro, dataLen); } - else if(variantBaseType == VARIANT_TYPE_DATETIME2) + else if (variantBaseType == VARIANT_TYPE_DATETIME2) { - /* - * dataformat : totalLen(4B) + baseType(1B) + metadatalen(1B) + - * scale(1B) + data(6B-8B) - */ + /* + * dataformat : totalLen(4B) + baseType(1B) + metadatalen(1B) + + * scale(1B) + data(6B-8B) + */ if (scale == 0xff || scale < 0 || scale > 7) scale = DATETIMEOFFSETMAXSCALE; @@ -3740,8 +3927,8 @@ TdsSendTypeSqlvariant(FmgrInfo *finfo, Datum value, void *vMetaData) dataLen = 8; memcpy(×tamp, buf, sizeof(timestamp)); - TdsGetDayTimeFromTimestamp((Timestamp)timestamp, &numDays, - &numMicro, scale); + TdsGetDayTimeFromTimestamp((Timestamp) timestamp, &numDays, + &numMicro, scale); totalLen = dataLen + VARIANT_TYPE_METALEN_FOR_DATETIME2; rc = TdsPutUInt32LE(totalLen); @@ -3753,15 +3940,16 @@ TdsSendTypeSqlvariant(FmgrInfo *finfo, Datum value, void *vMetaData) } else if (variantBaseType == VARIANT_TYPE_DATETIMEOFFSET) { - /* - * dataformat : totalLen(4B) + baseType(1B) + metadatalen(1B) + - * scale(1B) + data(8B-10B) - */ - tsql_datetimeoffset *tdt = (tsql_datetimeoffset *)buf; + /* + * dataformat : totalLen(4B) + baseType(1B) + metadatalen(1B) + + * scale(1B) + data(8B-10B) + */ + tsql_datetimeoffset *tdt = (tsql_datetimeoffset *) buf; + timestamptz = tdt->tsql_ts; timezone = tdt->tsql_tz; timestamptz += (timezone * SECS_PER_MINUTE * USECS_PER_SEC); - + if (scale == 0xff || scale < 0 || scale > 7) scale = DATETIMEOFFSETMAXSCALE; @@ -3772,8 +3960,8 @@ TdsSendTypeSqlvariant(FmgrInfo *finfo, Datum value, void *vMetaData) else if (scale >= 5 && scale <= 7) dataLen = 10; - TdsGetDayTimeFromTimestamp((Timestamp)timestamptz, &numDays, - &numMicro, scale); + TdsGetDayTimeFromTimestamp((Timestamp) timestamptz, &numDays, + &numMicro, scale); timezone *= -1; totalLen = dataLen + VARIANT_TYPE_METALEN_FOR_DATETIMEOFFSET; @@ -3795,10 +3983,10 @@ TdsSendTypeSqlvariant(FmgrInfo *finfo, Datum value, void *vMetaData) Datum TdsRecvTypeDatetimeoffset(const char *message, const ParameterToken token) { - StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); - Datum result; - TdsColumnMetaData col = token->paramMeta; - int scale = col.metaEntry.type6.scale; + StringInfo buf = TdsGetStringInfoBufferFromToken(message, token); + Datum result; + TdsColumnMetaData col = token->paramMeta; + int scale = col.metaEntry.type6.scale; TDSInstrumentation(INSTR_TDS_DATATYPE_DATETIME_OFFSET); @@ -3811,19 +3999,22 @@ TdsRecvTypeDatetimeoffset(const char *message, const ParameterToken token) int TdsSendTypeDatetimeoffset(FmgrInfo *finfo, Datum value, void *vMetaData) { - int rc = EOF, length = 0, scale = 0; + int rc = EOF, + length = 0, + scale = 0; uint64 numSec = 0; uint32 numDays = 0; int16_t timezone = 0; - TimestampTz timestamp = 0; - TdsColumnMetaData *col = (TdsColumnMetaData *)vMetaData; - - tsql_datetimeoffset *tdt = (tsql_datetimeoffset *)value; + TimestampTz timestamp = 0; + TdsColumnMetaData *col = (TdsColumnMetaData *) vMetaData; + + tsql_datetimeoffset *tdt = (tsql_datetimeoffset *) value; if (GetClientTDSVersion() < TDS_VERSION_7_3_A) + /* - * If client being connected is using TDS version lower than 7.3A - * then TSQL treats DATETIMEOFFSET as NVARCHAR. + * If client being connected is using TDS version lower than 7.3A then + * TSQL treats DATETIMEOFFSET as NVARCHAR. */ return TdsSendTypeNVarchar(finfo, value, vMetaData); @@ -3834,9 +4025,10 @@ TdsSendTypeDatetimeoffset(FmgrInfo *finfo, Datum value, void *vMetaData) timestamp += (timezone * SECS_PER_MINUTE * USECS_PER_SEC); scale = col->metaEntry.type6.scale; + /* - * if Datetimeoffset data has no specific scale specified in the query, default scale - * to be considered is 7 always. + * if Datetimeoffset data has no specific scale specified in the query, + * default scale to be considered is 7 always. */ if (scale == 0xFF) scale = DATETIMEOFFSETMAXSCALE; @@ -3848,20 +4040,21 @@ TdsSendTypeDatetimeoffset(FmgrInfo *finfo, Datum value, void *vMetaData) else if (scale >= 5 && scale <= 7) length = 10; - - TdsGetDayTimeFromTimestamp((Timestamp)timestamp, &numDays, - &numSec, scale); + + TdsGetDayTimeFromTimestamp((Timestamp) timestamp, &numDays, + &numSec, scale); timezone *= -1; if (TdsPutInt8(length) == 0 && - TdsPutbytes(&numSec, length - 5) == 0 && - TdsPutDate(numDays) == 0) + TdsPutbytes(&numSec, length - 5) == 0 && + TdsPutDate(numDays) == 0) rc = TdsPutUInt16LE(timezone); return rc; } -Datum TdsBytePtrToDatum(StringInfo buf, int datatype, int scale) -{ +Datum +TdsBytePtrToDatum(StringInfo buf, int datatype, int scale) +{ switch (datatype) { case TDS_TYPE_DATETIMEN: @@ -3881,21 +4074,22 @@ Datum TdsBytePtrToDatum(StringInfo buf, int datatype, int scale) } } -Datum TdsDateTimeTypeToDatum (uint64 time, int32 date, int datatype, int optional_attr) +Datum +TdsDateTimeTypeToDatum(uint64 time, int32 date, int datatype, int optional_attr) { switch (datatype) { case TDS_TYPE_DATE: { - DateADT result; - uint64 val; + DateADT result; + uint64 val; - /* - * By default we calculate date from 01-01-0001 - * but buf has number of days from 01-01-1900. So adding - * number of days between 01-01-1900 and 01-01-0001 + /* + * By default we calculate date from 01-01-0001 but buf has + * number of days from 01-01-1900. So adding number of days + * between 01-01-1900 and 01-01-0001 */ - result = (DateADT)date + (DateADT)TdsGetDayDifferenceHelper(1, 1, 1900, true); + result = (DateADT) date + (DateADT) TdsGetDayDifferenceHelper(1, 1, 1900, true); TdsCheckDateValidity(result); TdsTimeGetDatumFromDays(result, &val); @@ -3911,42 +4105,42 @@ Datum TdsDateTimeTypeToDatum (uint64 time, int32 date, int datatype, int optiona time *= 1000000; if (time < INT64CONST(0) || time > USECS_PER_DAY) ereport(ERROR, - (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("time out of range"))); + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("time out of range"))); - PG_RETURN_TIMEADT((TimeADT)time); + PG_RETURN_TIMEADT((TimeADT) time); } case TDS_TYPE_DATETIME2: - { + { Timestamp timestamp; - /* - * By default we calculate date from 01-01-0001 - * but buf has number of days from 01-01-1900. So adding - * number of days between 01-01-1900 and 01-01-0001 + /* + * By default we calculate date from 01-01-0001 but buf has + * number of days from 01-01-1900. So adding number of days + * between 01-01-1900 and 01-01-0001 */ date += TdsGetDayDifferenceHelper(1, 1, 1900, true); /* optional attribute here is scale */ TdsGetTimestampFromDayTime(date, time, 0, ×tamp, optional_attr); - PG_RETURN_TIMESTAMP((Timestamp)timestamp); + PG_RETURN_TIMESTAMP((Timestamp) timestamp); } case TDS_TYPE_DATETIMEOFFSET: - { + { tsql_datetimeoffset *tdt = (tsql_datetimeoffset *) palloc0(DATETIMEOFFSET_LEN); - TimestampTz timestamp; + TimestampTz timestamp; - /* - * By default we calculate date from 01-01-0001 - * but buf has number of days from 01-01-1900. So adding - * number of days between 01-01-1900 and 01-01-0001 + /* + * By default we calculate date from 01-01-0001 but buf has + * number of days from 01-01-1900. So adding number of days + * between 01-01-1900 and 01-01-0001 */ date += TdsGetDayDifferenceHelper(1, 1, 1900, true); /* optional attribute here is time offset */ optional_attr *= -1; - TdsGetTimestampFromDayTime(date, time, (int)optional_attr, ×tamp, 7); + TdsGetTimestampFromDayTime(date, time, (int) optional_attr, ×tamp, 7); timestamp -= (optional_attr * SECS_PER_MINUTE * USECS_PER_SEC); /* since reverse is done in tm2timestamp() */ diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdsutils.c b/contrib/babelfishpg_tds/src/backend/tds/tdsutils.c index c587c3062f..2bc6de7041 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tdsutils.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tdsutils.c @@ -35,18 +35,18 @@ #include "miscadmin.h" #include "utils/builtins.h" -static int FindMatchingParam(List *params, const char *name); -static Node * TransformParamRef(ParseState *pstate, ParamRef *pref); -Node * TdsFindParam(ParseState *pstate, ColumnRef *cref); -void TdsErrorContextCallback(void *arg); +static int FindMatchingParam(List *params, const char *name); +static Node *TransformParamRef(ParseState *pstate, ParamRef *pref); +Node *TdsFindParam(ParseState *pstate, ColumnRef *cref); +void TdsErrorContextCallback(void *arg); /* Create an object_access_hook */ object_access_hook_type next_object_access_hook = NULL; -void babelfish_object_access(ObjectAccessType access, Oid classId, Oid objectId, int subId, void *arg); +void babelfish_object_access(ObjectAccessType access, Oid classId, Oid objectId, int subId, void *arg); -void tdsutils_ProcessUtility (PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *completionTag); +void tdsutils_ProcessUtility(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *completionTag); ProcessUtility_hook_type next_ProcessUtility = NULL; -static void call_next_ProcessUtility (PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *completionTag); +static void call_next_ProcessUtility(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *completionTag); static void check_babelfish_droprole_restrictions(char *role); static void check_babelfish_renamerole_restrictions(char *role); static void check_babelfish_renamedb_restrictions(Oid target_db_id); @@ -55,15 +55,15 @@ static bool is_babelfish_ownership_enabled(ArrayType *array); static bool is_babelfish_role(const char *role); /* Role specific handlers */ -static bool handle_drop_role (DropRoleStmt* drop_role_stmt); -static bool handle_rename(RenameStmt* rename_stmt); +static bool handle_drop_role(DropRoleStmt *drop_role_stmt); +static bool handle_rename(RenameStmt *rename_stmt); /* Drop database handler */ static bool handle_dropdb(DropdbStmt *dropdb_stmt); static char *get_role_name(RoleSpec *role); static bool have_createdb_privilege(void); -char * get_rolespec_name_internal(const RoleSpec *role, bool missing_ok); +char *get_rolespec_name_internal(const RoleSpec *role, bool missing_ok); /* * GetUTF8CodePoint - extract the next Unicode code point from 1..4 @@ -131,7 +131,7 @@ GetUTF8CodePoint(const unsigned char *in, int len, int *consumed_p) errmsg("invalid UTF8 byte sequence starting with 0x%02x", in[0]))); code = ((in[0] & 0x07) << 18) | ((in[1] & 0x3F) << 12) | - ((in[2] & 0x3F) << 6) | (in[3] & 0x3F); + ((in[2] & 0x3F) << 6) | (in[3] & 0x3F); consumed = 4; } else @@ -184,9 +184,9 @@ GetUTF16CodePoint(const unsigned char *in, int len, int *consumed) { /* * This is a single 16 bit code point, which is equal to code1. - * PostgreSQL does not support NUL bytes in character data as - * it internally needs the ability to convert any datum to a - * NUL terminated C-string without explicit length information. + * PostgreSQL does not support NUL bytes in character data as it + * internally needs the ability to convert any datum to a NUL + * terminated C-string without explicit length information. */ if (code1 == 0) ereport(ERROR, @@ -195,7 +195,7 @@ GetUTF16CodePoint(const unsigned char *in, int len, int *consumed) "code point 0 not supported"))); if (consumed) *consumed = 2; - return (int32_t)code1; + return (int32_t) code1; } /* This is a surrogate pair - check that it is the high part */ @@ -241,7 +241,7 @@ AddUTF8ToStringInfo(int32_t code, StringInfo buf) (errcode(ERRCODE_DATA_EXCEPTION), errmsg("invalid Unicode code point 0x%x", code))); - /* Range U+0000 .. U+007F (7 bit)*/ + /* Range U+0000 .. U+007F (7 bit) */ if (code <= 0x7F) { appendStringInfoChar(buf, code); @@ -278,10 +278,11 @@ AddUTF8ToStringInfo(int32_t code, StringInfo buf) static inline void AddUTF16ToStringInfo(int32_t code, StringInfo buf) { - union { + union + { uint16_t value; uint8_t half[2]; - } temp16; + } temp16; /* Check that this is a valid code point */ if ((code > 0xD800 && code < 0xE000) || code < 0x0001 || code > 0x10FFFF) @@ -312,10 +313,10 @@ AddUTF16ToStringInfo(int32_t code, StringInfo buf) void TdsUTF16toUTF8StringInfo(StringInfo out, void *vin, int len) { - unsigned char *in = vin; - int i; - int consumed; - int32_t code; + unsigned char *in = vin; + int i; + int consumed; + int32_t code; /* UTF16 data allways comes in 16-bit units */ if ((len & 0x0001) != 0) @@ -339,10 +340,10 @@ TdsUTF16toUTF8StringInfo(StringInfo out, void *vin, int len) void TdsUTF8toUTF16StringInfo(StringInfo out, const void *vin, size_t len) { - const unsigned char *in = vin; - size_t i; - int consumed; - int32_t code; + const unsigned char *in = vin; + size_t i; + int consumed; + int32_t code; for (i = 0; i < len;) { @@ -360,7 +361,7 @@ TdsUTF8toUTF16StringInfo(StringInfo out, const void *vin, size_t len) int TdsUTF8LengthInUTF16(const void *vin, int len) { - const unsigned char *in = vin; + const unsigned char *in = vin; int result = 0; int i; int consumed; @@ -393,7 +394,8 @@ TdsUTF8LengthInUTF16(const void *vin, int len) int32_t ProcessStreamHeaders(const StringInfo message) { - int32_t header_len; + int32_t header_len; + /* We expect at least the packet type and header length */ if (message->len < 4) elog(FATAL, "corrupted TDS_QUERY packet - len=%d", @@ -422,9 +424,9 @@ FindMatchingParam(List *params, const char *name) foreach(cell, params) { - TdsParamName item = lfirst(cell); + TdsParamName item = lfirst(cell); - if (pg_strcasecmp(name, item->name) == 0) + if (pg_strcasecmp(name, item->name) == 0) return i + 1; i++; } @@ -444,8 +446,8 @@ FindMatchingParam(List *params, const char *name) Node * TdsFindParam(ParseState *pstate, ColumnRef *cref) { - extern int sql_dialect; - List *params = NULL; + extern int sql_dialect; + List *params = NULL; if (sql_dialect != SQL_DIALECT_TSQL) return NULL; @@ -460,9 +462,9 @@ TdsFindParam(ParseState *pstate, ColumnRef *cref) return NULL; else { - char *colname = strVal(linitial(cref->fields)); - int paramNo = 0; - ParamRef *pref; + char *colname = strVal(linitial(cref->fields)); + int paramNo = 0; + ParamRef *pref; if (params != NULL) { @@ -478,7 +480,7 @@ TdsFindParam(ParseState *pstate, ColumnRef *cref) pref = makeNode(ParamRef); - pref->number = paramNo; + pref->number = paramNo; pref->location = cref->location; return TransformParamRef(pstate, pref); @@ -517,77 +519,77 @@ TdsErrorContextCallback(void *arg) TdsErrorContextData *tdsErrorContext = (TdsErrorContextData *) arg; /* - * err_text should not be NULL. Initialise to Empty String - * if it need's to be ignored. + * err_text should not be NULL. Initialise to Empty String if it need's to + * be ignored. */ Assert(tdsErrorContext != NULL && tdsErrorContext->err_text != NULL); switch (tdsErrorContext->reqType) { - case TDS_LOGIN7: /* Login7 request */ + case TDS_LOGIN7: /* Login7 request */ { errcontext("TDS Protocol: Message Type: TDS Login7, Phase: Login. %s", - tdsErrorContext->err_text); + tdsErrorContext->err_text); } break; - case TDS_PRELOGIN: /* Pre-login Request*/ + case TDS_PRELOGIN: /* Pre-login Request */ { errcontext("TDS Protocol: Message Type: TDS Pre-Login, Phase: Login. %s", - tdsErrorContext->err_text); + tdsErrorContext->err_text); } break; - case TDS_QUERY: /* Simple SQL BATCH */ + case TDS_QUERY: /* Simple SQL BATCH */ { errcontext("TDS Protocol: Message Type: SQL BATCH, Phase: %s. %s", - tdsErrorContext->phase, - tdsErrorContext->err_text); + tdsErrorContext->phase, + tdsErrorContext->err_text); } break; - case TDS_RPC: /* Remote procedure call */ + case TDS_RPC: /* Remote procedure call */ { errcontext("TDS Protocol: Message Type: RPC, SP Type: %s, Phase: %s. %s", - tdsErrorContext->spType, - tdsErrorContext->phase, - tdsErrorContext->err_text); + tdsErrorContext->spType, + tdsErrorContext->phase, + tdsErrorContext->err_text); } break; - case TDS_TXN: /* Transaction management request */ + case TDS_TXN: /* Transaction management request */ { - errcontext("TDS Protocol: Message Type: Txn Manager, Txn Type: %s, Phase: %s. %s", - tdsErrorContext->txnType, - tdsErrorContext->phase, - tdsErrorContext->err_text); + errcontext("TDS Protocol: Message Type: Txn Manager, Txn Type: %s, Phase: %s. %s", + tdsErrorContext->txnType, + tdsErrorContext->phase, + tdsErrorContext->err_text); } break; - case TDS_ATTENTION: /* Attention request */ + case TDS_ATTENTION: /* Attention request */ { errcontext("TDS Protocol: Message Type: Attention, Phase: %s. %s", - tdsErrorContext->phase, - tdsErrorContext->err_text); + tdsErrorContext->phase, + tdsErrorContext->err_text); } break; - case TDS_BULK_LOAD: /* Bulk Load request */ + case TDS_BULK_LOAD: /* Bulk Load request */ { errcontext("TDS Protocol: Message Type: Bulk Load, Phase: %s. %s", - tdsErrorContext->phase, - tdsErrorContext->err_text); + tdsErrorContext->phase, + tdsErrorContext->err_text); } break; default: errcontext("TDS Protocol: %s", - tdsErrorContext->err_text); + tdsErrorContext->err_text); } } void babelfish_object_access(ObjectAccessType access, - Oid classId, - Oid objectId, - int subId, - void *arg) + Oid classId, + Oid objectId, + int subId, + void *arg) { if (next_object_access_hook) - (* next_object_access_hook) (access, classId, objectId, subId, arg); + (*next_object_access_hook) (access, classId, objectId, subId, arg); switch (access) { @@ -600,14 +602,15 @@ babelfish_object_access(ObjectAccessType access, /* * Prevent the user from dropping a babelfish role * when not in babelfish mode by checking for - * dependency on the master_guest, tempdb_guest, and - * msdb_guest roles. User can override if needed. + * dependency on the master_guest, tempdb_guest, + * and msdb_guest roles. User can override if + * needed. */ if (sql_dialect != SQL_DIALECT_TSQL) { - Oid bbf_master_guest_oid; - Oid bbf_tempdb_guest_oid; - Oid bbf_msdb_guest_oid; + Oid bbf_master_guest_oid; + Oid bbf_tempdb_guest_oid; + Oid bbf_msdb_guest_oid; bbf_master_guest_oid = get_role_oid("master_guest", true); bbf_tempdb_guest_oid = get_role_oid("tempdb_guest", true); @@ -644,17 +647,19 @@ babelfish_object_access(ObjectAccessType access, * * Returns: Nothing */ -void tdsutils_ProcessUtility(PlannedStmt *pstmt, - const char *queryString, - bool readOnlyTree, - ProcessUtilityContext context, - ParamListInfo params, - QueryEnvironment *queryEnv, - DestReceiver *dest, - QueryCompletion *completionTag) +void +tdsutils_ProcessUtility(PlannedStmt *pstmt, + const char *queryString, + bool readOnlyTree, + ProcessUtilityContext context, + ParamListInfo params, + QueryEnvironment *queryEnv, + DestReceiver *dest, + QueryCompletion *completionTag) { - Node *parsetree; - bool handle_result = true; + Node *parsetree; + bool handle_result = true; + /* * If the given node tree is read-only, make a copy to ensure that parse * transformations don't damage the original tree. This might cause us to @@ -666,14 +671,14 @@ void tdsutils_ProcessUtility(PlannedStmt *pstmt, parsetree = pstmt->utilityStmt; /* - * Explicitly skip TransactionStmt commands prior to calling the superuser() - * function. + * Explicitly skip TransactionStmt commands prior to calling the + * superuser() function. * * If we are in an aborted transaction, some TransactionStmts (e.g. * ROLLBACK) will be allowed to pass through to the process utility hooks. * In this aborted state, the syscache lookup that superuser() does is not - * safe. However, we do not do any kind of handling for TransactionStmts in - * this hook anyway, so we can easily avoid this issue by skipping it. + * safe. However, we do not do any kind of handling for TransactionStmts + * in this hook anyway, so we can easily avoid this issue by skipping it. */ if (parsetree && IsA(parsetree, TransactionStmt)) { @@ -689,29 +694,28 @@ void tdsutils_ProcessUtility(PlannedStmt *pstmt, } switch (nodeTag(parsetree)) { - /* Role lock down. */ + /* Role lock down. */ case T_DropRoleStmt: - handle_result = handle_drop_role((DropRoleStmt *)parsetree); + handle_result = handle_drop_role((DropRoleStmt *) parsetree); break; case T_RenameStmt: - handle_result = handle_rename((RenameStmt *)parsetree); + handle_result = handle_rename((RenameStmt *) parsetree); break; - /* Case that deal with Drop Database */ + /* Case that deal with Drop Database */ case T_DropdbStmt: - handle_result = handle_dropdb((DropdbStmt *)parsetree); + handle_result = handle_dropdb((DropdbStmt *) parsetree); break; default: break; } /* - * handle_result: - * true - If this is a command that we're not going to handle, allow it to - * processed in the normal way. - * false - Do nothing else. We've most likely reported an error, and most likely - * won't end up hitting this. + * handle_result: true - If this is a command that we're not going to + * handle, allow it to processed in the normal way. false - Do nothing + * else. We've most likely reported an error, and most likely won't end + * up hitting this. */ - if(handle_result) + if (handle_result) call_next_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, queryEnv, dest, completionTag); } @@ -725,19 +729,19 @@ void tdsutils_ProcessUtility(PlannedStmt *pstmt, * Returns: nothing */ static void -call_next_ProcessUtility (PlannedStmt *pstmt, - const char *queryString, - bool readOnlyTree, - ProcessUtilityContext context, - ParamListInfo params, - QueryEnvironment *queryEnv, - DestReceiver *dest, - QueryCompletion *completionTag) +call_next_ProcessUtility(PlannedStmt *pstmt, + const char *queryString, + bool readOnlyTree, + ProcessUtilityContext context, + ParamListInfo params, + QueryEnvironment *queryEnv, + DestReceiver *dest, + QueryCompletion *completionTag) { - if (next_ProcessUtility) - next_ProcessUtility (pstmt, queryString, readOnlyTree, context, params, queryEnv, dest, completionTag); - else - standard_ProcessUtility (pstmt, queryString, readOnlyTree, context, params, queryEnv, dest, completionTag); + if (next_ProcessUtility) + next_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, queryEnv, dest, completionTag); + else + standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, queryEnv, dest, completionTag); } /* @@ -749,37 +753,37 @@ call_next_ProcessUtility (PlannedStmt *pstmt, * false - otherwise */ static bool -handle_drop_role (DropRoleStmt* drop_role_stmt) +handle_drop_role(DropRoleStmt *drop_role_stmt) { - ListCell* item = NULL; - - /* We should not be handling superusers */ - Assert(!superuser()); - Assert(NULL != drop_role_stmt); - - /* - * Postgres allows you to drop multiple roles at the same time, which means - * we get to parse out the roles by hand. We could theoretically allow for skipping - * this role if it's specified in a list; however, blocking the statement seems less error - * prone at this point. - */ - foreach(item, drop_role_stmt->roles) - { - char *role = NULL; - - /* Roles is a list of RoleSpecs now */ - RoleSpec *node = lfirst(item); - - /* If the role does not exist, the role name will be NULL */ - role = get_role_name(node); - if (NULL == role) - continue; - - check_babelfish_droprole_restrictions(role); - pfree(role); - role = NULL; - } - return true; + ListCell *item = NULL; + + /* We should not be handling superusers */ + Assert(!superuser()); + Assert(NULL != drop_role_stmt); + + /* + * Postgres allows you to drop multiple roles at the same time, which + * means we get to parse out the roles by hand. We could theoretically + * allow for skipping this role if it's specified in a list; however, + * blocking the statement seems less error prone at this point. + */ + foreach(item, drop_role_stmt->roles) + { + char *role = NULL; + + /* Roles is a list of RoleSpecs now */ + RoleSpec *node = lfirst(item); + + /* If the role does not exist, the role name will be NULL */ + role = get_role_name(node); + if (NULL == role) + continue; + + check_babelfish_droprole_restrictions(role); + pfree(role); + role = NULL; + } + return true; } /* @@ -792,21 +796,22 @@ handle_drop_role (DropRoleStmt* drop_role_stmt) static char * get_role_name(RoleSpec *role) { - Assert(NULL != role); - - /* - * get_rolespec_name_internal will return NULL if called for ROLESPEC_PUBLIC. - * Postgres will return a different error if the user tries to modify the public role. - * It will be a better user experience to return that instead of tdsutils returning an error - * here by calling get_rolespec_name_internal. So return the public role name from here - * instead of calling get_rolespec_name_internal. - */ - if(ROLESPEC_PUBLIC == role->roletype) - { - /* Callers are expecting the return value to be palloc'd */ - return pstrdup(PUBLIC_ROLE_NAME); - } - return (char *) get_rolespec_name_internal(role, true); + Assert(NULL != role); + + /* + * get_rolespec_name_internal will return NULL if called for + * ROLESPEC_PUBLIC. Postgres will return a different error if the user + * tries to modify the public role. It will be a better user experience to + * return that instead of tdsutils returning an error here by calling + * get_rolespec_name_internal. So return the public role name from here + * instead of calling get_rolespec_name_internal. + */ + if (ROLESPEC_PUBLIC == role->roletype) + { + /* Callers are expecting the return value to be palloc'd */ + return pstrdup(PUBLIC_ROLE_NAME); + } + return (char *) get_rolespec_name_internal(role, true); } /* @@ -880,10 +885,10 @@ check_babelfish_droprole_restrictions(char *role) return; if (is_babelfish_role(role)) { - pfree(role); /* avoid mem leak */ + pfree(role); /* avoid mem leak */ ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("Babelfish-created users/roles cannot be dropped or altered outside of a Babelfish session"))); + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("Babelfish-created users/roles cannot be dropped or altered outside of a Babelfish session"))); } } @@ -904,11 +909,11 @@ check_babelfish_droprole_restrictions(char *role) static bool is_babelfish_role(const char *role) { - Oid sysadmin_oid; - Oid role_oid; + Oid sysadmin_oid; + Oid role_oid; - sysadmin_oid = get_role_oid(BABELFISH_SYSADMIN, true); /* missing OK */ - role_oid = get_role_oid(role, true); /* missing OK */ + sysadmin_oid = get_role_oid(BABELFISH_SYSADMIN, true); /* missing OK */ + role_oid = get_role_oid(role, true); /* missing OK */ if (sysadmin_oid == InvalidOid || role_oid == InvalidOid) return false; @@ -928,42 +933,42 @@ is_babelfish_role(const char *role) * Returns: true - If it passes through all the basic checks. */ static bool -handle_rename(RenameStmt* rename_stmt) +handle_rename(RenameStmt *rename_stmt) { - Assert(NULL != rename_stmt); - - /* - * The majority of potential renames should not be coming through - * here as they're handled by the event trigger infrastructure. We - * will; however, intercept calls for databases, table spaces, and - * (obviously) event triggers, so we need to ignore those. - */ - if (OBJECT_ROLE == rename_stmt->renameType) - check_babelfish_renamerole_restrictions(rename_stmt->subname); - - else if (OBJECT_DATABASE == rename_stmt->renameType) - { - Oid target_db_id = InvalidOid; - - /* - * Basic checks to avoid non-privileged user to access metadata. - * Always let backend to handle error. - */ - target_db_id = get_database_oid(rename_stmt->subname, true); - if (target_db_id == InvalidOid) - return true; - - /* must be owner */ - if (!pg_database_ownercheck(target_db_id, GetUserId())) - return true; - - /* must have createdb rights */ - if (!have_createdb_privilege()) - return true; - - check_babelfish_renamedb_restrictions(target_db_id); - } - return true; + Assert(NULL != rename_stmt); + + /* + * The majority of potential renames should not be coming through here as + * they're handled by the event trigger infrastructure. We will; however, + * intercept calls for databases, table spaces, and (obviously) event + * triggers, so we need to ignore those. + */ + if (OBJECT_ROLE == rename_stmt->renameType) + check_babelfish_renamerole_restrictions(rename_stmt->subname); + + else if (OBJECT_DATABASE == rename_stmt->renameType) + { + Oid target_db_id = InvalidOid; + + /* + * Basic checks to avoid non-privileged user to access metadata. + * Always let backend to handle error. + */ + target_db_id = get_database_oid(rename_stmt->subname, true); + if (target_db_id == InvalidOid) + return true; + + /* must be owner */ + if (!pg_database_ownercheck(target_db_id, GetUserId())) + return true; + + /* must have createdb rights */ + if (!have_createdb_privilege()) + return true; + + check_babelfish_renamedb_restrictions(target_db_id); + } + return true; } /* @@ -979,7 +984,7 @@ check_babelfish_renamerole_restrictions(char *role) return; if (is_babelfish_role(role)) { - pfree(role); /* avoid mem leak */ + pfree(role); /* avoid mem leak */ ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("Babelfish-created users/roles cannot be dropped or altered outside of a Babelfish session"))); @@ -1017,15 +1022,17 @@ have_createdb_privilege(void) static void check_babelfish_renamedb_restrictions(Oid target_db_id) { - const char *babelfish_db_name = NULL; + const char *babelfish_db_name = NULL; Oid babelfish_db_id = InvalidOid; + babelfish_db_name = GetConfigOption("babelfishpg_tsql.database_name", true, false); - if (!babelfish_db_name) /* not defined */ + if (!babelfish_db_name) /* not defined */ return; babelfish_db_id = get_database_oid(babelfish_db_name, true); - if (babelfish_db_id == target_db_id) /* rename active babelfish database */ + if (babelfish_db_id == target_db_id) /* rename active babelfish + * database */ ereport(ERROR, (errcode(ERRCODE_OBJECT_IN_USE), errmsg("cannot rename active babelfish database"))); @@ -1041,10 +1048,11 @@ check_babelfish_renamedb_restrictions(Oid target_db_id) static bool handle_dropdb(DropdbStmt *dropdb_stmt) { - Oid target_db_id = InvalidOid; + Oid target_db_id = InvalidOid; + /* - * Basic checkings to avoid non-privileged user to access metadata - * allways let backend to handle error + * Basic checkings to avoid non-privileged user to access metadata allways + * let backend to handle error */ target_db_id = get_database_oid(dropdb_stmt->dbname, true); if (target_db_id == InvalidOid) @@ -1061,26 +1069,25 @@ handle_dropdb(DropdbStmt *dropdb_stmt) static void check_babelfish_dropdb_restrictions(Oid target_db_id) { - Relation relsetting; - HeapTuple tuple; + Relation relsetting; + HeapTuple tuple; ScanKeyData scankey[2]; SysScanDesc scan; - const char *babelfish_db_name = NULL; + const char *babelfish_db_name = NULL; Oid babelfish_db_id = InvalidOid; - bool has_bbf_md = false; + bool has_bbf_md = false; babelfish_db_name = GetConfigOption("babelfishpg_tsql.database_name", true, false); - if (!babelfish_db_name) /* not define */ + if (!babelfish_db_name) /* not define */ return; babelfish_db_id = get_database_oid(babelfish_db_name, true); - if (babelfish_db_id == target_db_id) /* drop active babelfish database */ + if (babelfish_db_id == target_db_id) /* drop active babelfish database */ ereport(ERROR, (errcode(ERRCODE_OBJECT_IN_USE), errmsg("cannot drop active babelfish database"))); /* - * check if it's an inactive babelfish database. - * get db configs + * check if it's an inactive babelfish database. get db configs */ relsetting = table_open(DbRoleSettingRelationId, AccessShareLock); ScanKeyInit(&scankey[0], @@ -1092,16 +1099,16 @@ check_babelfish_dropdb_restrictions(Oid target_db_id) BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(InvalidOid)); scan = systable_beginscan(relsetting, DbRoleSettingDatidRolidIndexId, true, - NULL, 2, scankey); + NULL, 2, scankey); tuple = systable_getnext(scan); if (HeapTupleIsValid(tuple)) { - bool isnull; - Datum datum; - ArrayType *configs = NULL; + bool isnull; + Datum datum; + ArrayType *configs = NULL; datum = heap_getattr(tuple, Anum_pg_db_role_setting_setconfig, - RelationGetDescr(relsetting), &isnull); + RelationGetDescr(relsetting), &isnull); if (!isnull) configs = DatumGetArrayTypeP(datum); @@ -1124,7 +1131,8 @@ check_babelfish_dropdb_restrictions(Oid target_db_id) static bool is_babelfish_ownership_enabled(ArrayType *array) { - int i; + int i; + for (i = 1; i <= ARR_DIMS(array)[0]; i++) { Datum d; @@ -1132,6 +1140,7 @@ is_babelfish_ownership_enabled(ArrayType *array) char *s; char *name; char *value; + d = array_ref(array, 1, &i, -1 /* varlenarray */ , -1 /* TEXT's typlen */ , diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdsxact.c b/contrib/babelfishpg_tds/src/backend/tds/tdsxact.c index 2ec3e8e17a..731a79376f 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tdsxact.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tdsxact.c @@ -71,7 +71,7 @@ IsValidTxnName(char *txnName, int len) { if (len > 0 && IsValidIdentFirstChar(txnName[0])) { - for(int i=1; i < len; ++i) + for (int i = 1; i < len; ++i) if (!IsValidIdentChar(txnName[i])) return false; return true; @@ -83,7 +83,8 @@ IsValidTxnName(char *txnName, int len) static int GetTxnName(const StringInfo message, TDSRequestTxnMgmt request, int offset) { - uint8_t len; + uint8_t len; + memcpy(&len, message->data + offset, sizeof(len)); offset += sizeof(len); @@ -97,8 +98,8 @@ GetTxnName(const StringInfo message, TDSRequestTxnMgmt request, int offset) initStringInfo(&(request->txnName)); TdsUTF16toUTF8StringInfo(&(request->txnName), - message->data + offset, - len); + message->data + offset, + len); if (!IsValidTxnName(request->txnName.data, request->txnName.len)) ereport(ERROR, (errcode(ERRCODE_INVALID_NAME), @@ -133,7 +134,7 @@ GetNewTxnRequest(const StringInfo message, static const char * GetIsolationLevelStr(uint8_t isolationLevel) { - switch(isolationLevel) + switch (isolationLevel) { case TDS_ISOLATION_LEVEL_READ_UNCOMMITTED: return "READ UNCOMMITTED "; @@ -154,6 +155,7 @@ static void BuildTxnMgmtRequestQuery(TDSRequest requestParam, StringInfo cmdStr) { TDSRequestTxnMgmt request = (TDSRequestTxnMgmt) requestParam; + switch (request->txnReqType) { case TDS_TM_BEGIN_XACT: @@ -166,7 +168,7 @@ BuildTxnMgmtRequestQuery(TDSRequest requestParam, StringInfo cmdStr) appendStringInfoString(cmdStr, "; SET TRANSACTION ISOLATION LEVEL "); appendStringInfoString(cmdStr, GetIsolationLevelStr( - request->isolationLevel)); + request->isolationLevel)); } } break; @@ -184,14 +186,14 @@ BuildTxnMgmtRequestQuery(TDSRequest requestParam, StringInfo cmdStr) appendStringInfoString(cmdStr, "; BEGIN TRANSACTION "); if (request->nextTxn->txnName.len != 0) appendStringInfoString(cmdStr, - request->nextTxn->txnName.data); + request->nextTxn->txnName.data); if (request->nextTxn->isolationLevel != TDS_ISOLATION_LEVEL_NONE) { appendStringInfoString(cmdStr, "; SET TRANSACTION ISOLATION LEVEL "); appendStringInfoString(cmdStr, - GetIsolationLevelStr( - request->nextTxn->isolationLevel)); + GetIsolationLevelStr( + request->nextTxn->isolationLevel)); } } } @@ -210,18 +212,20 @@ BuildTxnMgmtRequestQuery(TDSRequest requestParam, StringInfo cmdStr) TDSRequest GetTxnMgmtRequest(const StringInfo message) { - TDSRequestTxnMgmt request; - int txnReqOffset = 0; - uint8_t flags; - uint32_t tdsVersion = GetClientTDSVersion(); + TDSRequestTxnMgmt request; + int txnReqOffset = 0; + uint8_t flags; + uint32_t tdsVersion = GetClientTDSVersion(); TDSInstrumentation(INSTR_TDS_TM_REQUEST); TdsErrorContext->err_text = "Fetching Transaction Management Request"; + /* - * In the ALL_HEADERS rule, the Query Notifications header and the Transaction - * Descriptor header were introduced in TDS 7.2. We need to to Process them only - * for TDS versions more than or equal to 7.2, otherwise we do not increment the offset. + * In the ALL_HEADERS rule, the Query Notifications header and the + * Transaction Descriptor header were introduced in TDS 7.2. We need to to + * Process them only for TDS versions more than or equal to 7.2, otherwise + * we do not increment the offset. */ if (tdsVersion > TDS_VERSION_7_1_1) txnReqOffset = ProcessStreamHeaders(message); @@ -303,30 +307,31 @@ GetTxnMgmtRequest(const StringInfo message) /* Build the internal query corresponding to the txn request */ initStringInfo(&(request->query)); - BuildTxnMgmtRequestQuery((TDSRequest)request, &(request->query)); + BuildTxnMgmtRequestQuery((TDSRequest) request, &(request->query)); pfree(message->data); - return (TDSRequest)request; + return (TDSRequest) request; } void ProcessTxnMgmtRequest(TDSRequest request) { - uint64_t txnId = (uint64_t) MyProc->lxid; - TDSRequestTxnMgmt req; + uint64_t txnId = (uint64_t) MyProc->lxid; + TDSRequestTxnMgmt req; InlineCodeBlock *codeblock = makeNode(InlineCodeBlock); - int cmd_type = TDS_CMD_UNKNOWN; - char *activity; - LOCAL_FCINFO(fcinfo,1); + int cmd_type = TDS_CMD_UNKNOWN; + char *activity; + + LOCAL_FCINFO(fcinfo, 1); TdsErrorContext->err_text = "Processing Transaction Management Request"; - req = (TDSRequestTxnMgmt)request; + req = (TDSRequestTxnMgmt) request; /* Only source text matters to handler */ codeblock->source_text = req->query.data; - codeblock->langOid = 0; /* TODO does it matter */ + codeblock->langOid = 0; /* TODO does it matter */ codeblock->langIsTrusted = true; codeblock->atomic = false; @@ -335,7 +340,7 @@ ProcessTxnMgmtRequest(TDSRequest request) fcinfo->args[0].value = PointerGetDatum(codeblock); fcinfo->args[0].isnull = false; - pltsql_plugin_handler_ptr->sp_executesql_callback (fcinfo); + pltsql_plugin_handler_ptr->sp_executesql_callback(fcinfo); MemoryContextSwitchTo(MessageContext); /* @@ -363,8 +368,8 @@ ProcessTxnMgmtRequest(TDSRequest request) * header). To support MARS, fix it. */ TdsSendEnvChangeBinary(TDS_ENVID_BEGINTXN, - &txnId, sizeof(uint64_t), - NULL, 0); + &txnId, sizeof(uint64_t), + NULL, 0); } break; case TDS_TM_COMMIT_XACT: @@ -376,17 +381,17 @@ ProcessTxnMgmtRequest(TDSRequest request) cmd_type = TDS_CMD_COMMIT; /* - * As BEGIN commands sends 0 as new transaction id, COMMIT - * has to do the same thing. + * As BEGIN commands sends 0 as new transaction id, COMMIT has + * to do the same thing. */ TdsSendEnvChangeBinary(TDS_ENVID_COMMITTXN, NULL, 0, - &txnId, sizeof(uint64_t)); - if(req->nextTxn != NULL) + &txnId, sizeof(uint64_t)); + if (req->nextTxn != NULL) { txnId = (uint64_t) MyProc->lxid; TdsSendEnvChangeBinary(TDS_ENVID_BEGINTXN, - &txnId, sizeof(uint64_t), - NULL, 0); + &txnId, sizeof(uint64_t), + NULL, 0); } } break; @@ -406,13 +411,13 @@ ProcessTxnMgmtRequest(TDSRequest request) */ if (GetTopTransactionIdIfAny() == InvalidTransactionId) TdsSendEnvChangeBinary(TDS_ENVID_ROLLBACKTXN, NULL, 0, - &txnId, sizeof(uint64_t)); - if(req->nextTxn != NULL) + &txnId, sizeof(uint64_t)); + if (req->nextTxn != NULL) { txnId = (uint64_t) MyProc->lxid; TdsSendEnvChangeBinary(TDS_ENVID_BEGINTXN, - &txnId, sizeof(uint64_t), - NULL, 0); + &txnId, sizeof(uint64_t), + NULL, 0); } } break; @@ -427,7 +432,7 @@ ProcessTxnMgmtRequest(TDSRequest request) int TestTxnMgmtRequest(TDSRequest request, const char *expectedStr) { - int res = 0; + int res = 0; StringInfoData cmdStr; Assert(request->reqType == TDS_REQUEST_TXN_MGMT); diff --git a/contrib/babelfishpg_tds/src/backend/utils/adt/numeric.c b/contrib/babelfishpg_tds/src/backend/utils/adt/numeric.c index c43b92ed84..476ad54683 100644 --- a/contrib/babelfishpg_tds/src/backend/utils/adt/numeric.c +++ b/contrib/babelfishpg_tds/src/backend/utils/adt/numeric.c @@ -288,7 +288,7 @@ typedef struct NumericVar current; NumericVar stop; NumericVar step; -} generate_series_numeric_fctx; +} generate_series_numeric_fctx; /* ---------- @@ -302,7 +302,7 @@ typedef struct bool estimating; /* true if estimating cardinality */ hyperLogLogState abbr_card; /* cardinality estimator */ -} NumericSortSupport; +} NumericSortSupport; /* ---------- @@ -344,7 +344,7 @@ typedef struct NumericSumAccum bool have_carry_space; int32 *pos_digits; int32 *neg_digits; -} NumericSumAccum; +} NumericSumAccum; /* @@ -399,7 +399,7 @@ static void dump_var(const char *str, NumericVar *var); static void alloc_var(NumericVar *var, int ndigits); static void free_var(NumericVar *var); static const char *set_var_from_str(const char *str, const char *cp, - NumericVar *dest); + NumericVar *dest); static Numeric make_result(const NumericVar *var); static void strip_var(NumericVar *var); @@ -738,8 +738,9 @@ strip_var(NumericVar *var) Numeric TdsSetVarFromStrWrapper(const char *str) { - NumericVar value; - Numeric res; + NumericVar value; + Numeric res; + init_var(&value); set_var_from_str(str, str, &value); res = make_result(&value); @@ -747,20 +748,20 @@ TdsSetVarFromStrWrapper(const char *str) return res; } -/* +/* * Get Precision & Scale from Numeric Value */ int32_t numeric_get_typmod(Numeric num) { - int32_t scale = NUMERIC_DSCALE(num); - int32_t weight = NUMERIC_WEIGHT(num); - int32_t precision; + int32_t scale = NUMERIC_DSCALE(num); + int32_t weight = NUMERIC_WEIGHT(num); + int32_t precision; /* - * We can identify a zero by the fact that there are no digits at all. - * In case of zero both precision and scale will be evaluated to zero, - * so we will set (precision,scale) to T-SQL default (18,0). + * We can identify a zero by the fact that there are no digits at all. In + * case of zero both precision and scale will be evaluated to zero, so we + * will set (precision,scale) to T-SQL default (18,0). */ if (NUMERIC_NDIGITS(num) == 0) { @@ -775,14 +776,15 @@ numeric_get_typmod(Numeric num) 10, 1, }; - int leading_digits = NUMERIC_DIGITS(num)[0]; + int leading_digits = NUMERIC_DIGITS(num)[0]; + precision = weight * DEC_DIGITS + scale; - for(int i = 0; i < DEC_DIGITS; i++) + for (int i = 0; i < DEC_DIGITS; i++) { - if(leading_digits >= timescales[i]) + if (leading_digits >= timescales[i]) { - precision += (4-i); + precision += (4 - i); break; } } @@ -791,5 +793,5 @@ numeric_get_typmod(Numeric num) /* weight < 0 means the integral part of the number is 0 */ precision = 1 + scale; - return (((precision & 0xFFFF) << 16 ) | (scale & 0xFFFF)) + VARHDRSZ; + return (((precision & 0xFFFF) << 16) | (scale & 0xFFFF)) + VARHDRSZ; } diff --git a/contrib/babelfishpg_tds/src/backend/utils/adt/varchar.c b/contrib/babelfishpg_tds/src/backend/utils/adt/varchar.c index e9cab2f44b..43afe962c1 100644 --- a/contrib/babelfishpg_tds/src/backend/utils/adt/varchar.c +++ b/contrib/babelfishpg_tds/src/backend/utils/adt/varchar.c @@ -19,7 +19,7 @@ #include "catalog/pg_collation.h" #include "libpq/pqformat.h" #include "nodes/nodeFuncs.h" -#include "parser/parser.h" /* only needed for GUC variables */ +#include "parser/parser.h" /* only needed for GUC variables */ #include "utils/array.h" #include "utils/builtins.h" #include "utils/varlena.h" @@ -29,9 +29,9 @@ static inline void CheckUTF16Length(const char *utf8_str, size_t len, size_t maxlen, - char *varstr) + char *varstr) { - int i; + int i; if (sql_dialect == SQL_DIALECT_TSQL) { @@ -43,7 +43,7 @@ CheckUTF16Length(const char *utf8_str, size_t len, size_t maxlen, (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), errmsg("value too long for type character%s(%d) " "as UTF16 output", - varstr, (int)maxlen))); + varstr, (int) maxlen))); } } diff --git a/contrib/babelfishpg_tds/src/backend/utils/adt/xml.c b/contrib/babelfishpg_tds/src/backend/utils/adt/xml.c index ad1a689992..31a18a5f2c 100644 --- a/contrib/babelfishpg_tds/src/backend/utils/adt/xml.c +++ b/contrib/babelfishpg_tds/src/backend/utils/adt/xml.c @@ -11,7 +11,7 @@ * *------------------------------------------------------------------------- */ - + /* * Generally, XML type support is only available when libxml use was * configured during the build. But even if that is not done, the @@ -22,7 +22,7 @@ * linked with libxml. Thus, make sure xml_out() works even if nothing * else does. */ - + /* * Notes on memory management: * @@ -42,9 +42,9 @@ * external modules. */ /* #define USE_LIBXMLCONTEXT */ - + #include "postgres.h" - + #ifdef USE_LIBXML #include #include @@ -58,7 +58,7 @@ #include #include "src/include/tds_int.h" - + /* * We used to check for xmlStructuredErrorContext via a configure test; but * that doesn't work on Windows, so instead use this grottier method of @@ -68,7 +68,7 @@ #define HAVE_XMLSTRUCTUREDERRORCONTEXT 1 #endif #endif /* USE_LIBXML */ - + #include "access/htup_details.h" #include "catalog/namespace.h" #include "catalog/pg_class.h" @@ -92,16 +92,16 @@ #include "utils/rel.h" #include "utils/syscache.h" #include "utils/xml.h" - + /* GUC variables */ int xmlbinary; int xmloption; - + #ifdef USE_LIBXML - + /* random number to identify PgXmlErrorContext */ #define ERRCXT_MAGIC 68275028 - + struct PgXmlErrorContext { int magic; @@ -118,27 +118,27 @@ struct PgXmlErrorContext }; static void xml_ereport_by_code(int level, int sqlcode, - const char *msg, int errcode); - + const char *msg, int errcode); + #ifdef USE_LIBXMLCONTEXT - + static MemoryContext LibxmlContext = NULL; - + static void xml_memory_init(void); static void *xml_palloc(size_t size); static void *xml_repalloc(void *ptr, size_t size); static void xml_pfree(void *ptr); static char *xml_pstrdup(const char *string); #endif /* USE_LIBXMLCONTEXT */ - + static xmlChar *xml_text2xmlChar(text *in); -static int parse_xml_decl(const xmlChar *str, size_t *lenp, - xmlChar **version, xmlChar **encoding, int *standalone); +static int parse_xml_decl(const xmlChar *str, size_t *lenp, + xmlChar **version, xmlChar **encoding, int *standalone); static bool xml_doctype_in_content(const xmlChar *str); static xmlDocPtr xml_parse(text *data, XmlOptionType xmloption_arg, - bool preserve_whitespace, int encoding); + bool preserve_whitespace, int encoding); #endif /* USE_LIBXML */ - + /* XMLTABLE support */ #ifdef USE_LIBXML /* random number to identify XmlTableContext */ @@ -155,24 +155,24 @@ typedef struct XmlTableBuilderData xmlXPathCompExprPtr xpathcomp; xmlXPathObjectPtr xpathobj; xmlXPathCompExprPtr *xpathscomp; -} XmlTableBuilderData; +} XmlTableBuilderData; #endif - + #define NO_XML_SUPPORT() \ ereport(ERROR, \ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \ errmsg("unsupported XML feature"), \ errdetail("This functionality requires the server to be built with libxml support."), \ errhint("You need to rebuild PostgreSQL using --with-libxml."))) - - + + /* from SQL/XML:2008 section 4.9 */ #define NAMESPACE_XSD "http://www.w3.org/2001/XMLSchema" #define NAMESPACE_XSI "http://www.w3.org/2001/XMLSchema-instance" #define NAMESPACE_SQLXML "http://standards.iso.org/iso/9075/2003/sqlxml" - + #ifdef USE_LIBXML - + /* * SQL/XML allows storing "XML documents" or "XML content". "XML * documents" are specified by the XML specification and are parsed @@ -181,16 +181,16 @@ typedef struct XmlTableBuilderData * "content" part, so we have to parse the XML declaration ourselves * to complete this. */ - + #define CHECK_XML_SPACE(p) \ do { \ if (!xmlIsBlank_ch(*(p))) \ return XML_ERR_SPACE_REQUIRED; \ } while (0) - + #define SKIP_XML_SPACE(p) \ while (xmlIsBlank_ch(*(p))) (p)++ - + /* Letter | Digit | '.' | '-' | '_' | ':' | CombiningChar | Extender */ /* Beware of multiple evaluations of argument! */ #define PG_XMLISNAMECHAR(c) \ @@ -199,19 +199,19 @@ typedef struct XmlTableBuilderData || c == '.' || c == '-' || c == '_' || c == ':' \ || xmlIsCombiningQ(c) \ || xmlIsExtender_ch(c)) - + /* pnstrdup, but deal with xmlChar not char; len is measured in xmlChars */ static xmlChar * xml_pnstrdup(const xmlChar *str, size_t len) { xmlChar *result; - + result = (xmlChar *) palloc((len + 1) * sizeof(xmlChar)); memcpy(result, str, len * sizeof(xmlChar)); result[len] = 0; return result; } - + /* * str is the null-terminated input string. Remaining arguments are * output arguments; each can be NULL if value is not wanted. @@ -227,7 +227,7 @@ parse_xml_decl(const xmlChar *str, size_t *lenp, size_t len; int utf8char; int utf8len; - + /* * Only initialize libxml. We don't need error handling here, but we do * need to make sure libxml is initialized before calling any of its @@ -235,7 +235,7 @@ parse_xml_decl(const xmlChar *str, size_t *lenp, * done pg_xml_init(). */ pg_xml_init_library(); - + /* Initialize output arguments to "not present" */ if (version) *version = NULL; @@ -243,12 +243,12 @@ parse_xml_decl(const xmlChar *str, size_t *lenp, *encoding = NULL; if (standalone) *standalone = -1; - + p = str; - + if (xmlStrncmp(p, (xmlChar *) " * rather than an XMLDecl, so we have done what we came to do and found no @@ -261,9 +261,9 @@ parse_xml_decl(const xmlChar *str, size_t *lenp, utf8char = xmlGetUTF8Char(p + 5, &utf8len); if (PG_XMLISNAMECHAR(utf8char)) goto finished; - + p += 5; - + /* version */ CHECK_XML_SPACE(p); SKIP_XML_SPACE(p); @@ -275,22 +275,22 @@ parse_xml_decl(const xmlChar *str, size_t *lenp, return XML_ERR_VERSION_MISSING; p += 1; SKIP_XML_SPACE(p); - + if (*p == '\'' || *p == '"') { const xmlChar *q; - + q = xmlStrchr(p + 1, *p); if (!q) return XML_ERR_VERSION_MISSING; - + if (version) *version = xml_pnstrdup(p + 1, q - p - 1); p = q + 1; } else return XML_ERR_VERSION_MISSING; - + /* encoding */ save_p = p; SKIP_XML_SPACE(p); @@ -303,15 +303,15 @@ parse_xml_decl(const xmlChar *str, size_t *lenp, return XML_ERR_MISSING_ENCODING; p += 1; SKIP_XML_SPACE(p); - + if (*p == '\'' || *p == '"') { const xmlChar *q; - + q = xmlStrchr(p + 1, *p); if (!q) return XML_ERR_MISSING_ENCODING; - + if (encoding) *encoding = xml_pnstrdup(p + 1, q - p - 1); p = q + 1; @@ -323,7 +323,7 @@ parse_xml_decl(const xmlChar *str, size_t *lenp, { p = save_p; } - + /* standalone */ save_p = p; SKIP_XML_SPACE(p); @@ -357,25 +357,25 @@ parse_xml_decl(const xmlChar *str, size_t *lenp, { p = save_p; } - + SKIP_XML_SPACE(p); if (xmlStrncmp(p, (xmlChar *) "?>", 2) != 0) return XML_ERR_XMLDECL_NOT_FINISHED; p += 2; - + finished: len = p - str; - + for (p = str; p < str + len; p++) if (*p > 127) return XML_ERR_INVALID_CHAR; - + if (lenp) *lenp = len; - + return XML_ERR_OK; } - + /* * Test whether an input that is to be parsed as CONTENT contains a DTD. * @@ -409,24 +409,24 @@ static bool xml_doctype_in_content(const xmlChar *str) { const xmlChar *p = str; - + for (;;) { const xmlChar *e; - + SKIP_XML_SPACE(p); if (*p != '<') return false; p++; - + if (*p == '!') { p++; - + /* if we see , fail */ if (*p != '?') return false; p++; - + /* find end of PI (the string ?> is forbidden within a PI) */ e = xmlStrstr(p, (xmlChar *) "?>"); if (!e) return false; - + /* advance over PI, keep scanning */ p = e + 2; } } - - + + /* * Convert a C string to XML internal representation * @@ -474,18 +474,18 @@ xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace, PgXmlErrorContext *xmlerrcxt; volatile xmlParserCtxtPtr ctxt = NULL; volatile xmlDocPtr doc = NULL; - + len = VARSIZE_ANY_EXHDR(data); /* will be useful later */ string = xml_text2xmlChar(data); - + utf8string = pg_do_encoding_conversion(string, len, encoding, PG_UTF8); - + /* Start up libxml and its parser */ xmlerrcxt = pg_xml_init(PG_XML_STRICTNESS_WELLFORMED); - + /* Use a TRY block to ensure we clean up correctly */ PG_TRY(); { @@ -494,14 +494,14 @@ xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace, size_t count = 0; xmlChar *version = NULL; int standalone = 0; - + xmlInitParser(); - + ctxt = xmlNewParserCtxt(); if (ctxt == NULL || xmlerrcxt->err_occurred) xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, "could not allocate parser context"); - + /* Decide whether to parse as document or content */ if (xmloption_arg == XMLOPTION_DOCUMENT) parse_as_document = true; @@ -514,12 +514,12 @@ xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace, xml_ereport_by_code(ERROR, ERRCODE_INVALID_XML_CONTENT, "invalid XML content: invalid XML declaration", res_code); - + /* Is there a DOCTYPE element? */ if (xml_doctype_in_content(utf8string + count)) parse_as_document = true; } - + if (parse_as_document) { /* @@ -551,7 +551,7 @@ xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace, Assert(doc->encoding == NULL); doc->encoding = xmlStrdup((const xmlChar *) "UTF-8"); doc->standalone = standalone; - + /* allow empty content */ if (*(utf8string + count)) { @@ -569,21 +569,21 @@ xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace, xmlFreeDoc(doc); if (ctxt != NULL) xmlFreeParserCtxt(ctxt); - + pg_xml_done(xmlerrcxt, true); - + PG_RE_THROW(); } PG_END_TRY(); - + xmlFreeParserCtxt(ctxt); - + pg_xml_done(xmlerrcxt, false); - + return doc; } - - + + /* * xmlChar<->text conversions */ @@ -592,10 +592,10 @@ xml_text2xmlChar(text *in) { return (xmlChar *) text_to_cstring(in); } - - + + #ifdef USE_LIBXMLCONTEXT - + /* * Manage the special context used for all libxml allocations (but only * in special debug builds; see notes at top of file) @@ -608,11 +608,11 @@ xml_memory_init(void) LibxmlContext = AllocSetContextCreate(TopMemoryContext, MC_Libxml_context, ALLOCSET_DEFAULT_SIZES); - + /* Re-establish the callbacks even if already set */ xmlMemSetup(xml_pfree, xml_palloc, xml_repalloc, xml_pstrdup); } - + /* * Wrappers for memory management functions */ @@ -621,15 +621,15 @@ xml_palloc(size_t size) { return MemoryContextAlloc(LibxmlContext, size); } - - + + static void * xml_repalloc(void *ptr, size_t size) { return repalloc(ptr, size); } - - + + static void xml_pfree(void *ptr) { @@ -637,16 +637,16 @@ xml_pfree(void *ptr) if (ptr) pfree(ptr); } - - + + static char * xml_pstrdup(const char *string) { return MemoryContextStrdup(LibxmlContext, string); } #endif /* USE_LIBXMLCONTEXT */ - - + + /* * Wrapper for "ereport" function for XML-related errors. The "msg" * is the SQL-level message; some can be adopted from the SQL/XML @@ -659,7 +659,7 @@ xml_ereport_by_code(int level, int sqlcode, const char *msg, int code) { const char *det; - + switch (code) { case XML_ERR_INVALID_CHAR: @@ -684,42 +684,42 @@ xml_ereport_by_code(int level, int sqlcode, det = gettext_noop("Unrecognized libxml error code: %d."); break; } - + ereport(level, (errcode(sqlcode), errmsg_internal("%s", msg), errdetail(det, code))); } #endif /* USE_LIBXML */ - + /* * support functions for XMLTABLE * */ #ifdef USE_LIBXML - + /* * Returns private data from executor state. Ensure validity by check with * MAGIC number. */ static inline XmlTableBuilderData * -GetXmlTableBuilderPrivateData(TableFuncScanState *state, const char *fname) +GetXmlTableBuilderPrivateData(TableFuncScanState * state, const char *fname) { XmlTableBuilderData *result; - + if (!IsA(state, TableFuncScanState)) elog(ERROR, "%s called with invalid TableFuncScanState", fname); result = (XmlTableBuilderData *) state->opaque; if (result->magic != XMLTABLE_CONTEXT_MAGIC) elog(ERROR, "%s called with invalid TableFuncScanState", fname); - + return result; } #endif void * tds_xml_parse(text *data, int xmloption_arg, bool preserve_whitespace, - int encoding) + int encoding) { return xml_parse(data, xmloption_arg, preserve_whitespace, encoding); } @@ -730,9 +730,9 @@ tds_xmlFreeDoc(void *doc) return xmlFreeDoc(doc); } -int +int tds_parse_xml_decl(const xmlChar *str, size_t *lenp, - xmlChar **version, xmlChar **encoding, int *standalone) + xmlChar **version, xmlChar **encoding, int *standalone) { return parse_xml_decl(str, lenp, version, encoding, standalone); } diff --git a/contrib/babelfishpg_tds/src/include/err_handler.h b/contrib/babelfishpg_tds/src/include/err_handler.h index 138bcd3181..15d761c868 100644 --- a/contrib/babelfishpg_tds/src/include/err_handler.h +++ b/contrib/babelfishpg_tds/src/include/err_handler.h @@ -1,52 +1,57 @@ #include "utils/elog.h" -typedef struct error_map_details{ - char sql_state[5]; +typedef struct error_map_details +{ + char sql_state[5]; const char *error_message; - int tsql_error_code; - int tsql_error_severity; - char *error_msg_keywords; -}error_map_details; + int tsql_error_code; + int tsql_error_severity; + char *error_msg_keywords; +} error_map_details; /* Function in err_handler.c */ extern void emit_tds_log(ErrorData *edata); extern void load_error_mapping(void); extern bool get_tsql_error_details(ErrorData *edata, - int *tsql_error_code, - int *tsql_error_severity, - int *tsql_error_state, - char *error_context); + int *tsql_error_code, + int *tsql_error_severity, + int *tsql_error_state, + char *error_context); extern void reset_error_mapping_cache(void); -extern void* get_mapped_error_list(void); -extern int* get_mapped_tsql_error_code_list(void); +extern void *get_mapped_error_list(void); +extern int *get_mapped_tsql_error_code_list(void); -/* +/* * Structure to store key information for error mapping. - * Hash of error message along with sqlerrorcode is key here. + * Hash of error message along with sqlerrorcode is key here. */ -typedef struct error_map_key{ - uint32 message_hash; /* Hash of error message */ - int sqlerrcode; /* encoded ERRSTATE of error code */ -}error_map_key; +typedef struct error_map_key +{ + uint32 message_hash; /* Hash of error message */ + int sqlerrcode; /* encoded ERRSTATE of error code */ +} error_map_key; /* * This linked list will be used during second level of lookup. - * i.e., when given PG error code and error message_id (untranslated error message) is not enough + * i.e., when given PG error code and error message_id (untranslated error message) is not enough * to uniquely identify the correct tsql error details. */ -typedef struct error_map_node{ - char *error_msg_keywords; /* Unique keywords from error message to identify the correct tsql error. */ - int tsql_error_code; /* TSQL error code */ - int tsql_error_severity; /* TSQL error severity */ +typedef struct error_map_node +{ + char *error_msg_keywords; /* Unique keywords from error message to + * identify the correct tsql error. */ + int tsql_error_code; /* TSQL error code */ + int tsql_error_severity; /* TSQL error severity */ struct error_map_node *next; -}error_map_node; +} error_map_node; /* * Structure to store list of tsql error details for given key. */ -typedef struct error_map{ +typedef struct error_map +{ error_map_key key; error_map_node *head; -}error_map; +} error_map; typedef error_map *error_map_info; diff --git a/contrib/babelfishpg_tds/src/include/faultinjection.h b/contrib/babelfishpg_tds/src/include/faultinjection.h index 6aef51ac4e..0212c4a444 100644 --- a/contrib/babelfishpg_tds/src/include/faultinjection.h +++ b/contrib/babelfishpg_tds/src/include/faultinjection.h @@ -17,33 +17,36 @@ #define FAULT_NAME_MAX_LENGTH 100 #define INVALID_TAMPER_BYTE -1 -typedef enum FaultInjectorType_e { +typedef enum FaultInjectorType_e +{ TestType = 0, ParseHeaderType, PreParsingType, - ParseRpcType, + ParseRpcType, PostParsingType, InvalidType } FaultInjectorType_e; -typedef struct FaultInjectionType { +typedef struct FaultInjectionType +{ FaultInjectorType_e type; - char faultTypeName[FAULT_NAME_MAX_LENGTH]; - List *injected_entries; + char faultTypeName[FAULT_NAME_MAX_LENGTH]; + List *injected_entries; } FaultInjectionType; extern FaultInjectionType FaultInjectionTypes[]; -typedef struct FaultInjectorEntry_s { - char faultName[FAULT_NAME_MAX_LENGTH]; /* name of the fault */ - FaultInjectorType_e type; - int num_occurrences; /* 0 when diabled */ - void (*fault_callback) (void *arg, int *num_occurrences); +typedef struct FaultInjectorEntry_s +{ + char faultName[FAULT_NAME_MAX_LENGTH]; /* name of the fault */ + FaultInjectorType_e type; + int num_occurrences; /* 0 when diabled */ + void (*fault_callback) (void *arg, int *num_occurrences); } FaultInjectorEntry_s; extern const FaultInjectorEntry_s Faults[]; -extern int tamperByte; +extern int tamperByte; #define TEST_LIST const FaultInjectorEntry_s Faults[] #define TEST_TYPE_LIST FaultInjectionType FaultInjectionTypes[] diff --git a/contrib/babelfishpg_tds/src/include/guc.h b/contrib/babelfishpg_tds/src/include/guc.h index ab0fbc81c5..9ab0d0a80a 100644 --- a/contrib/babelfishpg_tds/src/include/guc.h +++ b/contrib/babelfishpg_tds/src/include/guc.h @@ -13,17 +13,17 @@ *------------------------------------------------------------------------- */ -extern int pe_port; +extern int pe_port; extern char *pe_listen_addrs; extern char *pe_unix_socket_directories; extern char *product_version; -extern int pe_unix_socket_permissions; +extern int pe_unix_socket_permissions; extern char *pe_unix_socket_group; extern bool tds_ssl_encrypt; -extern int tds_default_numeric_precision; -extern int tds_default_numeric_scale; +extern int tds_default_numeric_precision; +extern int tds_default_numeric_scale; extern int32_t tds_default_protocol_version; extern int32_t tds_default_packet_size; -extern int tds_debug_log_level; +extern int tds_debug_log_level; extern char *default_server_name; -extern bool enable_drop_babelfish_role; \ No newline at end of file +extern bool enable_drop_babelfish_role; diff --git a/contrib/babelfishpg_tds/src/include/tds.h b/contrib/babelfishpg_tds/src/include/tds.h index 4ba140287c..9d2a15ebdc 100644 --- a/contrib/babelfishpg_tds/src/include/tds.h +++ b/contrib/babelfishpg_tds/src/include/tds.h @@ -16,13 +16,13 @@ * the engine even before the extension is loaded. If you call * find_rendezvous_variable("TdsInstrPlugin") and find that *result * is NULL, then the extension has not been loaded. If you find - * that *result is non-NULL, it points to an instance of the + * that *result is non-NULL, it points to an instance of the * TdsInstrPlugin struct shown here. */ typedef struct TdsInstrPlugin { /* Function pointers set up by the plugin */ - void (*tds_instr_increment_metric) (int metric); + void (*tds_instr_increment_metric) (int metric); } TdsInstrPlugin; extern TdsInstrPlugin **tds_instr_plugin_ptr; @@ -31,4 +31,3 @@ extern TdsInstrPlugin **tds_instr_plugin_ptr; ({ if ((tds_instr_plugin_ptr && (*tds_instr_plugin_ptr) && (*tds_instr_plugin_ptr)->tds_instr_increment_metric)) \ (*tds_instr_plugin_ptr)->tds_instr_increment_metric(metric); \ }) - diff --git a/contrib/babelfishpg_tds/src/include/tds_debug.h b/contrib/babelfishpg_tds/src/include/tds_debug.h index 363a9bc059..dc155902da 100644 --- a/contrib/babelfishpg_tds/src/include/tds_debug.h +++ b/contrib/babelfishpg_tds/src/include/tds_debug.h @@ -108,6 +108,4 @@ do \ pfree(s.data); \ } while(0) -#endif /* TDS_DEBUG_H */ - - +#endif /* TDS_DEBUG_H */ diff --git a/contrib/babelfishpg_tds/src/include/tds_instr.h b/contrib/babelfishpg_tds/src/include/tds_instr.h index b6c389b6dc..6c755e80fc 100644 --- a/contrib/babelfishpg_tds/src/include/tds_instr.h +++ b/contrib/babelfishpg_tds/src/include/tds_instr.h @@ -10,7 +10,8 @@ #include "src/pltsql_instr.h" #include "tds.h" -typedef enum BabelFishTdsInstrMetricType { +typedef enum BabelFishTdsInstrMetricType +{ INSTR_TDS_LOGIN_SSL = INSTR_TSQL_COUNT, INSTR_TDS_LOGIN_END_TO_END_ENCRYPT, INSTR_TDS_LOGIN_ACTIVE_DIRECTORY, @@ -93,4 +94,4 @@ typedef enum BabelFishTdsInstrMetricType { INSTR_TDS_UNMAPPED_ERROR, INSTR_TDS_COUNT -} BabelFishTdsInstrMetricType; +} BabelFishTdsInstrMetricType; diff --git a/contrib/babelfishpg_tds/src/include/tds_int.h b/contrib/babelfishpg_tds/src/include/tds_int.h index 2187d443ef..436da7b5f7 100644 --- a/contrib/babelfishpg_tds/src/include/tds_int.h +++ b/contrib/babelfishpg_tds/src/include/tds_int.h @@ -78,7 +78,8 @@ #define TDS_PACKET_HEADER_STATUS_IGNORE 0x02 /* ignore event */ #define TDS_PACKET_HEADER_STATUS_RESETCON 0x08 /* reset connection */ #define TDS_PACKET_HEADER_STATUS_RESETCONSKIPTRAN 0x10 /* reset connection but - keep transaction context */ + * keep transaction + * context */ /* TDS prelogin option types */ #define TDS_PRELOGIN_VERSION 0x00 @@ -114,7 +115,7 @@ /* * Macros for TDS Versions - * + * * If tds_default_protocol_version is set to TDS_DEFAULT_VERSION value * then we shall use the TDS Version that the client specifies during login. */ @@ -166,11 +167,11 @@ extern PLtsql_protocol_plugin *pltsql_plugin_handler_ptr; extern collation_callbacks *collation_callbacks_ptr; /* Globals in backend/tds/tdscomm.c */ -extern MemoryContext TdsMemoryContext; +extern MemoryContext TdsMemoryContext; /* Global to store default collation info */ -extern int TdsDefaultLcid; -extern int TdsDefaultCollationFlags; +extern int TdsDefaultLcid; +extern int TdsDefaultCollationFlags; extern uint8_t TdsDefaultSortid; extern pg_enc TdsDefaultClientEncoding; @@ -194,17 +195,18 @@ if (TDS_DEBUG_ENABLED(level)) \ /* Structures in backend/tds/tdsprotocol.c */ typedef struct TdsParamNameData { - char *name; /* name of the parameter (If there is an upperlimit, - we can use fixed size array) */ - uint8 type; /* 0: IN parameter 1: OUT parameter (TODO: INOUT parameters?) */ -} TdsParamNameData; + char *name; /* name of the parameter (If there is an + * upperlimit, we can use fixed size array) */ + uint8 type; /* 0: IN parameter 1: OUT parameter (TODO: + * INOUT parameters?) */ +} TdsParamNameData; typedef TdsParamNameData *TdsParamName; extern PGDLLIMPORT uint32_t MyTdsClientVersion; -extern PGDLLIMPORT char* MyTdsLibraryName; -extern PGDLLIMPORT char* MyTdsHostName; -extern PGDLLIMPORT char* MyTdsContextInfo; +extern PGDLLIMPORT char *MyTdsLibraryName; +extern PGDLLIMPORT char *MyTdsHostName; +extern PGDLLIMPORT char *MyTdsContextInfo; extern PGDLLIMPORT uint32_t MyTdsClientPid; extern PGDLLIMPORT uint32_t MyTdsProtocolVersion; extern PGDLLIMPORT uint32_t MyTdsPacketSize; @@ -227,11 +229,11 @@ typedef struct TdsMessageWrapper */ typedef struct { - uint8_t reqType; /* current Tds Request Type*/ - char *phase; /* current TDS_REQUEST_PHASE_* (see above) */ - char *spType; - char *txnType; - char *err_text; /* additional errorstate info */ + uint8_t reqType; /* current Tds Request Type */ + char *phase; /* current TDS_REQUEST_PHASE_* (see above) */ + char *spType; + char *txnType; + char *err_text; /* additional errorstate info */ } TdsErrorContextData; @@ -239,7 +241,7 @@ extern TdsErrorContextData *TdsErrorContext; /* Socket functions */ -typedef ssize_t (*TdsSecureSocketApi)(Port *port, void *ptr, size_t len); +typedef ssize_t (*TdsSecureSocketApi) (Port *port, void *ptr, size_t len); /* Globals in backend/tds/tdsutils.c */ extern object_access_hook_type next_object_access_hook; @@ -252,37 +254,37 @@ extern ProcessUtility_hook_type next_ProcessUtility; /* Functions in backend/tds/tdscomm.c */ extern void TdsSetMessageType(uint8_t msgType); extern void TdsCommInit(uint32_t bufferSize, - TdsSecureSocketApi secure_read, - TdsSecureSocketApi secure_write); + TdsSecureSocketApi secure_read, + TdsSecureSocketApi secure_write); extern void TdsSetMessageType(uint8_t msgType); extern void TdsCommReset(void); extern void TdsCommShutdown(void); -extern int TdsPeekbyte(void); -extern int TdsReadNextBuffer(void); -extern int TdsSocketFlush(void); -extern int TdsGetbytes(char *s, size_t len); -extern int TdsDiscardbytes(size_t len); -extern int TdsPutbytes(void *s, size_t len); -extern int TdsPutInt8(int8_t value); -extern int TdsPutUInt8(uint8_t value); -extern int TdsPutInt16LE(int16_t value); -extern int TdsPutUInt16LE(uint16_t value); -extern int TdsPutInt32LE(int32_t value); -extern int TdsPutUInt32LE(uint32_t value); -extern int TdsPutInt64LE(int64_t value); -extern int TdsPutFloat4LE(float4 value); -extern int TdsPutFloat8LE(float8 value); +extern int TdsPeekbyte(void); +extern int TdsReadNextBuffer(void); +extern int TdsSocketFlush(void); +extern int TdsGetbytes(char *s, size_t len); +extern int TdsDiscardbytes(size_t len); +extern int TdsPutbytes(void *s, size_t len); +extern int TdsPutInt8(int8_t value); +extern int TdsPutUInt8(uint8_t value); +extern int TdsPutInt16LE(int16_t value); +extern int TdsPutUInt16LE(uint16_t value); +extern int TdsPutInt32LE(int32_t value); +extern int TdsPutUInt32LE(uint32_t value); +extern int TdsPutInt64LE(int64_t value); +extern int TdsPutFloat4LE(float4 value); +extern int TdsPutFloat8LE(float8 value); extern bool TdsCheckMessageType(uint8_t messageType); -extern int TdsReadNextRequest(StringInfo message, uint8_t *status, uint8_t *messageType); -extern int TdsReadMessage(StringInfo message, uint8_t messageType); -extern int TdsReadNextPendingBcpRequest(StringInfo message); -extern int TdsDiscardAllPendingBcpRequest(void); -extern int TdsWriteMessage(StringInfo message, uint8_t messageType); -extern int TdsHandleTestQuery(StringInfo message); -extern int TdsTestProtocol(void); -extern int TdsPutUInt16LE(uint16_t value); -extern int TdsPutUInt64LE(uint64_t value); -extern int TdsPutDate(uint32_t value); +extern int TdsReadNextRequest(StringInfo message, uint8_t *status, uint8_t *messageType); +extern int TdsReadMessage(StringInfo message, uint8_t messageType); +extern int TdsReadNextPendingBcpRequest(StringInfo message); +extern int TdsDiscardAllPendingBcpRequest(void); +extern int TdsWriteMessage(StringInfo message, uint8_t messageType); +extern int TdsHandleTestQuery(StringInfo message); +extern int TdsTestProtocol(void); +extern int TdsPutUInt16LE(uint16_t value); +extern int TdsPutUInt64LE(uint64_t value); +extern int TdsPutDate(uint32_t value); extern bool TdsGetRecvPacketEomStatus(void); /* Functions in backend/tds/tdslogin.c */ @@ -290,35 +292,35 @@ extern void TdsSetBufferSize(uint32_t newSize); extern void TdsClientAuthentication(Port *port); extern void TdsClientInit(void); extern void TdsSetBufferSize(uint32_t newSize); -extern int TdsProcessLogin(Port *port, bool LoadSsl); +extern int TdsProcessLogin(Port *port, bool LoadSsl); extern void TdsSendLoginAck(Port *port); extern uint32_t GetClientTDSVersion(void); -extern char* get_tds_login_domainname(void); +extern char *get_tds_login_domainname(void); /* Functions in backend/tds/tdsprotocol.c */ -extern int TdsSocketBackend(void); +extern int TdsSocketBackend(void); extern void TdsProtocolInit(void); extern void TdsProtocolFinish(void); -extern int TestGetTdsRequest(uint8_t reqType, const char* expectedStr); +extern int TestGetTdsRequest(uint8_t reqType, const char *expectedStr); /* Functions in backend/tds/tdsrpc.c */ extern bool TdsIsSPPrepare(void); extern void TdsFetchInParamValues(ParamListInfo params); extern bool TdsGetParamNames(List **); -extern int TdsGetAndSetParamIndex(const char *pname); +extern int TdsGetAndSetParamIndex(const char *pname); extern void TDSLogDuration(char *query); /* Functions in backend/tds/tdsutils.c */ -extern int TdsUTF8LengthInUTF16(const void *in, int len); +extern int TdsUTF8LengthInUTF16(const void *in, int len); extern void TdsUTF16toUTF8StringInfo(StringInfo out, void *in, int len); extern void TdsUTF8toUTF16StringInfo(StringInfo out, - const void *in, - size_t len); + const void *in, + size_t len); extern int32_t ProcessStreamHeaders(const StringInfo message); -extern Node * TdsFindParam(ParseState *pstate, ColumnRef *cref); +extern Node *TdsFindParam(ParseState *pstate, ColumnRef *cref); extern void TdsErrorContextCallback(void *arg); extern void babelfish_object_access(ObjectAccessType access, Oid classId, Oid objectId, int subId, void *arg); -extern void tdsutils_ProcessUtility (PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *completionTag); +extern void tdsutils_ProcessUtility(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *completionTag); /* Functions in backend/tds/guc.c */ extern void TdsDefineGucs(void); @@ -330,9 +332,9 @@ extern void TdsSetAtAtStatVariable(const char *at_at_var, int intVal, uint64 big extern void TdsSetDatabaseStatVariable(int16 db_id); extern bool tds_stat_get_activity(Datum *values, bool *nulls, int len, int pid, int curr_backend); extern void invalidate_stat_table(void); -extern char* get_tds_host_name(void); +extern char *get_tds_host_name(void); extern Datum get_tds_context_info(void); -extern void set_tds_context_info(bytea* context_info); +extern void set_tds_context_info(bytea *context_info); /* Functions in backend/tds/tdspostgres.c */ extern void TDSPostgresMain(int argc, char *argv[], @@ -360,14 +362,14 @@ extern void *tds_varchar_input(const char *s, size_t len, int32 atttypmod); /* Functions in backend/utils/adt/xml.c */ extern void tds_xmlFreeDoc(void *doc); extern void *tds_xml_parse(text *data, int xmloption_arg, bool preserve_whitespace, - int encoding); -extern int tds_parse_xml_decl(const xmlChar *str, size_t *lenp, - xmlChar **version, xmlChar **encoding, int *standalone); + int encoding); +extern int tds_parse_xml_decl(const xmlChar *str, size_t *lenp, + xmlChar **version, xmlChar **encoding, int *standalone); /* Functions in tdstypeio.c */ -extern char * TdsEncodingConversion(const char *s, int len, pg_enc src_encoding, pg_enc dest_encoding, int *encodedByteLen); +extern char *TdsEncodingConversion(const char *s, int len, pg_enc src_encoding, pg_enc dest_encoding, int *encodedByteLen); extern coll_info_t TdsLookupCollationTableCallback(Oid oid); extern Datum TdsBytePtrToDatum(StringInfo buf, int datatype, int scale); -extern Datum TdsDateTimeTypeToDatum (uint64 time, int32 date, int datatype, int scale); +extern Datum TdsDateTimeTypeToDatum(uint64 time, int32 date, int datatype, int scale); -#endif /* TDS_INT_H */ \ No newline at end of file +#endif /* TDS_INT_H */ diff --git a/contrib/babelfishpg_tds/src/include/tds_iofuncmap.h b/contrib/babelfishpg_tds/src/include/tds_iofuncmap.h index 4b88937492..c0b5617e44 100644 --- a/contrib/babelfishpg_tds/src/include/tds_iofuncmap.h +++ b/contrib/babelfishpg_tds/src/include/tds_iofuncmap.h @@ -87,32 +87,32 @@ * Caution: these must be specified in decimal to be processed by * contrib/babelfishpg_tsql/sql/datatype.sql */ -#define TDS_TYPE_TEXT 35 /* 0x23 */ -#define TDS_TYPE_UNIQUEIDENTIFIER 36 /* 0x24 */ -#define TDS_TYPE_INTEGER 38 /* 0x26 */ -#define TDS_TYPE_NTEXT 99 /* 0x63 */ -#define TDS_TYPE_BIT 104 /* 0x68 */ -#define TDS_TYPE_FLOAT 109 /* 0x6D */ -#define TDS_TYPE_VARCHAR 167 /* 0xA7 */ -#define TDS_TYPE_NVARCHAR 231 /* 0xE7 */ -#define TDS_TYPE_NCHAR 239 /* 0xEF */ -#define TDS_TYPE_MONEYN 110 /* 0x6E */ -#define TDS_TYPE_SMALLMONEY 122 /* 0x7A */ -#define TDS_TYPE_CHAR 175 /* 0xAF */ -#define TDS_TYPE_DATE 40 /* 0x28 */ -#define TDS_TYPE_DATETIMEN 111 /* 0x6F */ -#define TDS_TYPE_NUMERICN 108 /* 0x6C */ -#define TDS_TYPE_XML 241 /* 0xf1 */ -#define TDS_TYPE_DECIMALN 106 /* 0x6A */ -#define TDS_TYPE_VARBINARY 165 /* 0xA5 */ -#define TDS_TYPE_BINARY 173 /* 0xAD */ -#define TDS_TYPE_IMAGE 34 /* 0x22 */ -#define TDS_TYPE_TIME 41 /* 0x29 */ -#define TDS_TYPE_DATETIME2 42 /* 0x2A */ -#define TDS_TYPE_TABLE 243 /* 0xF3 */ -#define TDS_TYPE_SQLVARIANT 98 /* 0x62 */ -#define TDS_TYPE_DATETIMEOFFSET 43 /* 0x2B */ -#define TDS_TYPE_SMALLDATETIME 58 /* 0x3A */ +#define TDS_TYPE_TEXT 35 /* 0x23 */ +#define TDS_TYPE_UNIQUEIDENTIFIER 36 /* 0x24 */ +#define TDS_TYPE_INTEGER 38 /* 0x26 */ +#define TDS_TYPE_NTEXT 99 /* 0x63 */ +#define TDS_TYPE_BIT 104 /* 0x68 */ +#define TDS_TYPE_FLOAT 109 /* 0x6D */ +#define TDS_TYPE_VARCHAR 167 /* 0xA7 */ +#define TDS_TYPE_NVARCHAR 231 /* 0xE7 */ +#define TDS_TYPE_NCHAR 239 /* 0xEF */ +#define TDS_TYPE_MONEYN 110 /* 0x6E */ +#define TDS_TYPE_SMALLMONEY 122 /* 0x7A */ +#define TDS_TYPE_CHAR 175 /* 0xAF */ +#define TDS_TYPE_DATE 40 /* 0x28 */ +#define TDS_TYPE_DATETIMEN 111 /* 0x6F */ +#define TDS_TYPE_NUMERICN 108 /* 0x6C */ +#define TDS_TYPE_XML 241 /* 0xf1 */ +#define TDS_TYPE_DECIMALN 106 /* 0x6A */ +#define TDS_TYPE_VARBINARY 165 /* 0xA5 */ +#define TDS_TYPE_BINARY 173 /* 0xAD */ +#define TDS_TYPE_IMAGE 34 /* 0x22 */ +#define TDS_TYPE_TIME 41 /* 0x29 */ +#define TDS_TYPE_DATETIME2 42 /* 0x2A */ +#define TDS_TYPE_TABLE 243 /* 0xF3 */ +#define TDS_TYPE_SQLVARIANT 98 /* 0x62 */ +#define TDS_TYPE_DATETIMEOFFSET 43 /* 0x2B */ +#define TDS_TYPE_SMALLDATETIME 58 /* 0x3A */ /* * macros for supporting sqlvariant datatype on TDS side @@ -138,7 +138,7 @@ #define VARIANT_TYPE_VARBINARY 165 #define VARIANT_TYPE_UNIQUEIDENTIFIER 36 #define VARIANT_TYPE_TIME 41 -#define VARIANT_TYPE_SMALLDATETIME 58 +#define VARIANT_TYPE_SMALLDATETIME 58 #define VARIANT_TYPE_DATETIME 61 #define VARIANT_TYPE_DATETIME2 42 #define VARIANT_TYPE_DATETIMEOFFSET 43 @@ -159,4 +159,4 @@ #define TDS_MAXLEN_DATETIME 8 #define TDS_MAXLEN_SMALLMONEY 4 #define TDS_MAXLEN_MONEY 8 -#endif /* TDS_IOFUNCMAP_H */ +#endif /* TDS_IOFUNCMAP_H */ diff --git a/contrib/babelfishpg_tds/src/include/tds_protocol.h b/contrib/babelfishpg_tds/src/include/tds_protocol.h index 96f7c74b98..a661cc181f 100644 --- a/contrib/babelfishpg_tds/src/include/tds_protocol.h +++ b/contrib/babelfishpg_tds/src/include/tds_protocol.h @@ -66,10 +66,10 @@ */ typedef struct { - MemoryContext requestContext; /* temporary request context */ - TDSRequest request; /* current request in-progress */ - uint8_t phase; /* current TDS_REQUEST_PHASE_* (see above) */ - uint8_t status; /* current status of the request */ + MemoryContext requestContext; /* temporary request context */ + TDSRequest request; /* current request in-progress */ + uint8_t phase; /* current TDS_REQUEST_PHASE_* (see above) */ + uint8_t status; /* current status of the request */ /* denotes whether we've sent at least one done token */ bool isEmptyResponse; @@ -78,4 +78,4 @@ typedef struct extern TdsRequestCtrlData *TdsRequestCtrl; -#endif /* TDS_PROTOCOL_H */ +#endif /* TDS_PROTOCOL_H */ diff --git a/contrib/babelfishpg_tds/src/include/tds_request.h b/contrib/babelfishpg_tds/src/include/tds_request.h index ed05bf06db..7b5726a675 100644 --- a/contrib/babelfishpg_tds/src/include/tds_request.h +++ b/contrib/babelfishpg_tds/src/include/tds_request.h @@ -29,16 +29,16 @@ typedef enum TDSRequestType { TDS_REQUEST_SQL_BATCH = 1, /* a simple SQL batch */ TDS_REQUEST_SP_NUMBER = 2, /* numbered SP like sp_execute */ - TDS_REQUEST_TXN_MGMT = 3, /* transaction management request */ - TDS_REQUEST_BULK_LOAD = 4, /* bulk load request */ + TDS_REQUEST_TXN_MGMT = 3, /* transaction management request */ + TDS_REQUEST_BULK_LOAD = 4, /* bulk load request */ TDS_REQUEST_ATTN /* attention request */ } TDSRequestType; /* Simple SQL batch */ typedef struct TDSRequestSQLBatchData { - TDSRequestType reqType; - StringInfoData query; + TDSRequestType reqType; + StringInfoData query; } TDSRequestSQLBatchData; typedef TDSRequestSQLBatchData *TDSRequestSQLBatch; @@ -79,58 +79,63 @@ do \ } \ } while(0) -int ReadPlp(ParameterToken temp, StringInfo message, uint64_t *mainOffset); +int ReadPlp(ParameterToken temp, StringInfo message, uint64_t *mainOffset); + /* Numbered Stored Procedure like sp_prepexec, sp_execute */ typedef struct TDSRequestSPData { - TDSRequestType reqType; + TDSRequestType reqType; uint16_t spType; uint16_t spFlags; StringInfoData name; uint32 handle; /* handle corresponding to this SP request */ - uint32 cursorHandle; /* cursor handle corresponding to this SP_CURSOR* request */ + uint32 cursorHandle; /* cursor handle corresponding to this + * SP_CURSOR* request */ - /* cursor prepared handle corresponding to SP_CURSOR[prepare/prepexec/exec] request */ - uint32_t cursorPreparedHandle; + /* + * cursor prepared handle corresponding to + * SP_CURSOR[prepare/prepexec/exec] request + */ + uint32_t cursorPreparedHandle; /* - * parameter points to the head of the ParameterToken linked List. - * Each ParameterToken contains all the data pertaining to the parameter. + * parameter points to the head of the ParameterToken linked List. Each + * ParameterToken contains all the data pertaining to the parameter. */ - ParameterToken parameter; + ParameterToken parameter; /* * Pointer to request data, while parsing we don't copy the actual data * but just store the dataOffset and len fields in the Parametertoken * structure */ - char *messageData; - uint64_t batchSeparatorOffset; - int messageLen; + char *messageData; + uint64_t batchSeparatorOffset; + int messageLen; /* - * Below three fields are just a place holder for keeping the addresses - * of Parameter query & data token separate, so that during processing - * this can be used directly + * Below three fields are just a place holder for keeping the addresses of + * Parameter query & data token separate, so that during processing this + * can be used directly */ - ParameterToken queryParameter; - ParameterToken dataParameter; - ParameterToken handleParameter; + ParameterToken queryParameter; + ParameterToken dataParameter; + ParameterToken handleParameter; - StringInfo metaDataParameterValue; + StringInfo metaDataParameterValue; /* - * cursor parameters - all parameters except cursorHandleParameter have different - * meanings w.r.t the type of the cursor request (check GetTDSRequest() for their - * respective meaning). + * cursor parameters - all parameters except cursorHandleParameter have + * different meanings w.r.t the type of the cursor request (check + * GetTDSRequest() for their respective meaning). */ - ParameterToken cursorPreparedHandleParameter; - ParameterToken cursorHandleParameter; - ParameterToken cursorExtraArg1; - ParameterToken cursorExtraArg2; - ParameterToken cursorExtraArg3; + ParameterToken cursorPreparedHandleParameter; + ParameterToken cursorHandleParameter; + ParameterToken cursorExtraArg1; + ParameterToken cursorExtraArg2; + ParameterToken cursorExtraArg3; /* number of total dataParameters */ uint16 nTotalParams; @@ -148,43 +153,45 @@ typedef struct TDSRequestSPData /* * TODO: Use as local variable rather than part of the structure */ - Datum *boundParamsData; - char *boundParamsNullList; - Oid *boundParamsOidList; + Datum *boundParamsData; + char *boundParamsNullList; + Oid *boundParamsOidList; - uint16 nTotalBindParams; + uint16 nTotalBindParams; /* True, if this is a stored procedure */ - bool isStoredProcedure; + bool isStoredProcedure; /* * we store the OUT dataParameter pointers in the following array so that * they can be accessed directly given their index. */ - ParameterToken *idxOutParams; + ParameterToken *idxOutParams; /* - * In case when parameter names aren't specified by the application, - * then use paramIndex for maintaining the paramIndex which is used - * by Engine + * In case when parameter names aren't specified by the application, then + * use paramIndex for maintaining the paramIndex which is used by Engine */ - int paramIndex; + int paramIndex; } TDSRequestSPData; typedef TDSRequestSPData *TDSRequestSP; typedef struct TDSRequestBulkLoadData { - TDSRequestType reqType; - int colCount; - int rowCount; + TDSRequestType reqType; + int colCount; + int rowCount; - /* Holds the First Message data to be transfered from TDS Fetch to TDS Process phase. */ - StringInfo firstMessage; + /* + * Holds the First Message data to be transfered from TDS Fetch to TDS + * Process phase. + */ + StringInfo firstMessage; - int currentBatchSize; /* Current Batch Size in byes */ + int currentBatchSize; /* Current Batch Size in byes */ - BulkLoadColMetaData *colMetaData; /* Array of each column's metadata. */ - List *rowData; /* List holding each row. */ + BulkLoadColMetaData *colMetaData; /* Array of each column's metadata. */ + List *rowData; /* List holding each row. */ } TDSRequestBulkLoadData; typedef TDSRequestBulkLoadData *TDSRequestBulkLoad; @@ -218,24 +225,24 @@ do { \ /* Transaction management request */ typedef struct TDSRequestTxnMgmtData { - TDSRequestType reqType; - uint16_t txnReqType; - StringInfoData txnName; - uint8_t isolationLevel; - StringInfoData query; + TDSRequestType reqType; + uint16_t txnReqType; + StringInfoData txnName; + uint8_t isolationLevel; + StringInfoData query; /* Commit/rollback requests can have optional begin transaction */ - struct TDSRequestTxnMgmtData *nextTxn; + struct TDSRequestTxnMgmtData *nextTxn; } TDSRequestTxnMgmtData; typedef TDSRequestTxnMgmtData *TDSRequestTxnMgmt; typedef union TDSRequestData { - TDSRequestType reqType; - TDSRequestSQLBatchData sqlBatch; - TDSRequestSPData sp; - TDSRequestTxnMgmtData txnMgmt; + TDSRequestType reqType; + TDSRequestSQLBatchData sqlBatch; + TDSRequestSPData sp; + TDSRequestTxnMgmtData txnMgmt; } TDSRequestData; typedef TDSRequestData *TDSRequest; @@ -267,14 +274,15 @@ SetTvpRowData(ParameterToken temp, const StringInfo message, uint64_t *offset) { TvpColMetaData *colmetadata = temp->tvpInfo->colMetaData; TvpRowData *rowData = NULL; - char *messageData = message->data; - int retStatus = 0; + char *messageData = message->data; + int retStatus = 0; + temp->tvpInfo->rowCount = 0; - while(messageData[*offset] == TVP_ROW_TOKEN) /* Loop over each row. */ + while (messageData[*offset] == TVP_ROW_TOKEN) /* Loop over each row. */ { - int i = 0; /* Current Column Number. */ + int i = 0; /* Current Column Number. */ - if (rowData == NULL) /* First Row. */ + if (rowData == NULL) /* First Row. */ { rowData = palloc0(sizeof(TvpRowData)); temp->tvpInfo->rowData = rowData; @@ -282,20 +290,21 @@ SetTvpRowData(ParameterToken temp, const StringInfo message, uint64_t *offset) else { TvpRowData *temp = palloc0(sizeof(TvpRowData)); + rowData->nextRow = temp; rowData = temp; } rowData->columnValues = palloc0(temp->tvpInfo->colCount * sizeof(StringInfoData)); - rowData->isNull = palloc0(temp->tvpInfo->colCount); + rowData->isNull = palloc0(temp->tvpInfo->colCount); (*offset)++; - while(i != temp->tvpInfo->colCount) /* Loop over each column. */ + while (i != temp->tvpInfo->colCount) /* Loop over each column. */ { initStringInfo(&rowData->columnValues[i]); rowData->isNull[i] = 'f'; temp->tvpInfo->rowCount += 1; - switch(colmetadata[i].columnTdsType) + switch (colmetadata[i].columnTdsType) { case TDS_TYPE_INTEGER: case TDS_TYPE_BIT: @@ -306,52 +315,52 @@ SetTvpRowData(ParameterToken temp, const StringInfo message, uint64_t *offset) case TDS_TYPE_DATETIMEN: case TDS_TYPE_MONEYN: case TDS_TYPE_UNIQUEIDENTIFIER: - { - rowData->columnValues[i].len = messageData[(*offset)++]; - if (rowData->columnValues[i].len == 0) /* null */ { - rowData->isNull[i] = 'n'; - i++; - continue; + rowData->columnValues[i].len = messageData[(*offset)++]; + if (rowData->columnValues[i].len == 0) /* null */ + { + rowData->isNull[i] = 'n'; + i++; + continue; + } + if (rowData->columnValues[i].len > colmetadata[i].maxLen) + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " + "Table-valued parameter %d (\"%s\"), row %d, column %d: Data type 0x%02X has an invalid data length or metadata length.", + temp->paramOrdinal + 1, temp->paramMeta.colName.data, temp->tvpInfo->rowCount, i + 1, colmetadata[i].columnTdsType))); + memcpy(rowData->columnValues[i].data, &messageData[*offset], rowData->columnValues[i].len); + *offset += rowData->columnValues[i].len; } - if (rowData->columnValues[i].len > colmetadata[i].maxLen) - ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " - "Table-valued parameter %d (\"%s\"), row %d, column %d: Data type 0x%02X has an invalid data length or metadata length.", - temp->paramOrdinal + 1, temp->paramMeta.colName.data, temp->tvpInfo->rowCount, i + 1, colmetadata[i].columnTdsType))); - memcpy(rowData->columnValues[i].data, &messageData[*offset], rowData->columnValues[i].len); - *offset += rowData->columnValues[i].len; - } - break; + break; case TDS_TYPE_NUMERICN: case TDS_TYPE_DECIMALN: - { - if (colmetadata[i].scale > colmetadata[i].precision) - ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " - "Table-valued parameter %d (\"%s\"): row %d, column %d: The supplied value is not a valid instance of data type Numeric/Decimal. " - "Check the source data for invalid values. An example of an invalid value is data of numeric type with scale greater than precision.", - temp->paramOrdinal + 1, temp->paramMeta.colName.data, temp->tvpInfo->rowCount, i + 1))); - rowData->columnValues[i].len = messageData[(*offset)++]; - if (rowData->columnValues[i].len == 0) /* null */ { - rowData->isNull[i] = 'n'; - i++; - continue; + if (colmetadata[i].scale > colmetadata[i].precision) + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " + "Table-valued parameter %d (\"%s\"): row %d, column %d: The supplied value is not a valid instance of data type Numeric/Decimal. " + "Check the source data for invalid values. An example of an invalid value is data of numeric type with scale greater than precision.", + temp->paramOrdinal + 1, temp->paramMeta.colName.data, temp->tvpInfo->rowCount, i + 1))); + rowData->columnValues[i].len = messageData[(*offset)++]; + if (rowData->columnValues[i].len == 0) /* null */ + { + rowData->isNull[i] = 'n'; + i++; + continue; + } + if (rowData->columnValues[i].len > colmetadata[i].maxLen) + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " + "Table-valued parameter %d (\"%s\"), row %d, column %d: Data type 0x%02X has an invalid data length or metadata length.", + temp->paramOrdinal + 1, temp->paramMeta.colName.data, temp->tvpInfo->rowCount, i + 1, colmetadata[i].columnTdsType))); + + memcpy(rowData->columnValues[i].data, &messageData[*offset], rowData->columnValues[i].len); + *offset += rowData->columnValues[i].len; } - if (rowData->columnValues[i].len > colmetadata[i].maxLen) - ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " - "Table-valued parameter %d (\"%s\"), row %d, column %d: Data type 0x%02X has an invalid data length or metadata length.", - temp->paramOrdinal + 1, temp->paramMeta.colName.data, temp->tvpInfo->rowCount, i + 1, colmetadata[i].columnTdsType))); - - memcpy(rowData->columnValues[i].data, &messageData[*offset], rowData->columnValues[i].len); - *offset += rowData->columnValues[i].len; - } - break; + break; case TDS_TYPE_CHAR: case TDS_TYPE_VARCHAR: @@ -359,101 +368,106 @@ SetTvpRowData(ParameterToken temp, const StringInfo message, uint64_t *offset) case TDS_TYPE_NVARCHAR: case TDS_TYPE_BINARY: case TDS_TYPE_VARBINARY: - { - if (colmetadata[i].maxLen != 0xffff) { - memcpy(&rowData->columnValues[i].len, &messageData[*offset], sizeof(short)); - *offset += sizeof(short); - rowData->columnValues[i].maxlen = colmetadata[i].maxLen; - if (rowData->columnValues[i].len != 0xffff) + if (colmetadata[i].maxLen != 0xffff) { - char * value; - - if (rowData->columnValues[i].len > rowData->columnValues[i].maxlen) - ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " - "Table-valued parameter %d (\"%s\"), row %d, column %d: Data type 0x%02X has an invalid data length or metadata length.", - temp->paramOrdinal + 1, temp->paramMeta.colName.data, temp->tvpInfo->rowCount, i + 1, colmetadata[i].columnTdsType))); - value = palloc(rowData->columnValues[i].len); - memcpy(value, &messageData[*offset], rowData->columnValues[i].len); - rowData->columnValues[i].data = value; - *offset += rowData->columnValues[i].len; - if (colmetadata[i].columnTdsType == TDS_TYPE_NVARCHAR) + memcpy(&rowData->columnValues[i].len, &messageData[*offset], sizeof(short)); + *offset += sizeof(short); + rowData->columnValues[i].maxlen = colmetadata[i].maxLen; + if (rowData->columnValues[i].len != 0xffff) { - StringInfo tempStringInfo = palloc( sizeof(StringInfoData)); - initStringInfo(tempStringInfo); - TdsUTF16toUTF8StringInfo(tempStringInfo, value,rowData->columnValues[i].len); - rowData->columnValues[i] = *tempStringInfo; + char *value; + + if (rowData->columnValues[i].len > rowData->columnValues[i].maxlen) + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " + "Table-valued parameter %d (\"%s\"), row %d, column %d: Data type 0x%02X has an invalid data length or metadata length.", + temp->paramOrdinal + 1, temp->paramMeta.colName.data, temp->tvpInfo->rowCount, i + 1, colmetadata[i].columnTdsType))); + value = palloc(rowData->columnValues[i].len); + memcpy(value, &messageData[*offset], rowData->columnValues[i].len); + rowData->columnValues[i].data = value; + *offset += rowData->columnValues[i].len; + if (colmetadata[i].columnTdsType == TDS_TYPE_NVARCHAR) + { + StringInfo tempStringInfo = palloc(sizeof(StringInfoData)); + + initStringInfo(tempStringInfo); + TdsUTF16toUTF8StringInfo(tempStringInfo, value, rowData->columnValues[i].len); + rowData->columnValues[i] = *tempStringInfo; + } + } + else + { + rowData->isNull[i] = 'n'; + i++; + continue; } } else { - rowData->isNull[i] = 'n'; - i++; - continue; + retStatus = ReadPlp(temp, message, offset); + CheckPLPStatusNotOKForTVP(temp, retStatus); + if (temp->isNull) + { + rowData->isNull[i] = 'n'; + } + rowData->columnValues[i] = *(TdsGetPlpStringInfoBufferFromToken(messageData, temp)); + if (colmetadata[i].columnTdsType == TDS_TYPE_NVARCHAR) + { + StringInfo tempStringInfo = palloc(sizeof(StringInfoData)); + + initStringInfo(tempStringInfo); + TdsUTF16toUTF8StringInfo(tempStringInfo, rowData->columnValues[i].data, rowData->columnValues[i].len); + rowData->columnValues[i] = *tempStringInfo; + } + temp->isNull = false; } } - else + break; + case TDS_TYPE_XML: { retStatus = ReadPlp(temp, message, offset); CheckPLPStatusNotOKForTVP(temp, retStatus); if (temp->isNull) { rowData->isNull[i] = 'n'; + i++; + temp->isNull = false; + continue; } rowData->columnValues[i] = *(TdsGetPlpStringInfoBufferFromToken(messageData, temp)); - if (colmetadata[i].columnTdsType == TDS_TYPE_NVARCHAR) - { - StringInfo tempStringInfo = palloc(sizeof(StringInfoData)); - initStringInfo(tempStringInfo); - TdsUTF16toUTF8StringInfo(tempStringInfo, rowData->columnValues[i].data,rowData->columnValues[i].len); - rowData->columnValues[i] = *tempStringInfo; - } - temp->isNull = false; - } - } - break; - case TDS_TYPE_XML: - { - retStatus = ReadPlp(temp, message, offset); - CheckPLPStatusNotOKForTVP(temp, retStatus); - if (temp->isNull) - { - rowData->isNull[i] = 'n'; - i++; - temp->isNull = false; - continue; } - rowData->columnValues[i] = *(TdsGetPlpStringInfoBufferFromToken(messageData, temp)); - } - break; + break; case TDS_TYPE_SQLVARIANT: - { - memcpy(&rowData->columnValues[i].len, &messageData[*offset], sizeof(uint32_t)); - *offset += sizeof(uint32_t); - - if (rowData->columnValues[i].len == 0) { - rowData->isNull[i] = 'n'; - i++; - continue; + memcpy(&rowData->columnValues[i].len, &messageData[*offset], sizeof(uint32_t)); + *offset += sizeof(uint32_t); + + if (rowData->columnValues[i].len == 0) + { + rowData->isNull[i] = 'n'; + i++; + continue; + } + if (rowData->columnValues[i].len > colmetadata[i].maxLen) + ereport(ERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " + "Table-valued parameter %d (\"%s\"), row %d, column %d: Data type 0x%02X has an invalid data length or metadata length.", + temp->paramOrdinal + 1, temp->paramMeta.colName.data, temp->tvpInfo->rowCount, i + 1, colmetadata[i].columnTdsType))); + + /* + * Check if rowData->columnValues[i].data has enough + * length allocated. + */ + if (rowData->columnValues[i].len > rowData->columnValues[i].maxlen) + enlargeStringInfo(&rowData->columnValues[i], rowData->columnValues[i].len); + + memcpy(rowData->columnValues[i].data, &messageData[*offset], rowData->columnValues[i].len); + *offset += rowData->columnValues[i].len; } - if (rowData->columnValues[i].len > colmetadata[i].maxLen) - ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " - "Table-valued parameter %d (\"%s\"), row %d, column %d: Data type 0x%02X has an invalid data length or metadata length.", - temp->paramOrdinal + 1, temp->paramMeta.colName.data, temp->tvpInfo->rowCount, i + 1, colmetadata[i].columnTdsType))); - - /* Check if rowData->columnValues[i].data has enough length allocated. */ - if (rowData->columnValues[i].len > rowData->columnValues[i].maxlen) - enlargeStringInfo(&rowData->columnValues[i], rowData->columnValues[i].len); - - memcpy(rowData->columnValues[i].data, &messageData[*offset], rowData->columnValues[i].len); - *offset += rowData->columnValues[i].len; - } - break; + break; } i++; } @@ -462,49 +476,49 @@ SetTvpRowData(ParameterToken temp, const StringInfo message, uint64_t *offset) ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " - "Table-valued parameter %d (\"%s\"), row %d, column %d: Data type 0x%02X (user-defined table type) " - "unexpected token encountered processing a table-valued parameter.", - temp->paramOrdinal + 1, temp->paramMeta.colName.data, temp->tvpInfo->rowCount, temp->tvpInfo->colCount, temp->type))); + "Table-valued parameter %d (\"%s\"), row %d, column %d: Data type 0x%02X (user-defined table type) " + "unexpected token encountered processing a table-valued parameter.", + temp->paramOrdinal + 1, temp->paramMeta.colName.data, temp->tvpInfo->rowCount, temp->tvpInfo->colCount, temp->type))); (*offset)++; } static inline void -SetColMetadataForTvp(ParameterToken temp,const StringInfo message, uint64_t *offset) +SetColMetadataForTvp(ParameterToken temp, const StringInfo message, uint64_t *offset) { - uint8_t len; - uint16 colCount; - uint16 isTvpNull; - char *tempString; - int i = 0; - char *messageData = message->data; - StringInfo tempStringInfo = palloc( sizeof(StringInfoData)); - uint32_t collation; + uint8_t len; + uint16 colCount; + uint16 isTvpNull; + char *tempString; + int i = 0; + char *messageData = message->data; + StringInfo tempStringInfo = palloc(sizeof(StringInfoData)); + uint32_t collation; /* Database-Name.Schema-Name.TableType-Name */ - for(; i < 3; i++) + for (; i < 3; i++) { len = messageData[(*offset)++]; if (len != 0) { /* Database name not allowed in a TVP */ - if (i ==0) + if (i == 0) ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " - "Table-valued parameter %d (\"%s\"), row %d, column %d: Data type 0x%02X (user-defined table type) " - "has a non-zero length database name specified. Database name is not allowed with a table-valued parameter, " - "only schema name and type name are valid.", - temp->paramOrdinal + 1, temp->paramMeta.colName.data, 1, 1, temp->type))); + "Table-valued parameter %d (\"%s\"), row %d, column %d: Data type 0x%02X (user-defined table type) " + "has a non-zero length database name specified. Database name is not allowed with a table-valued parameter, " + "only schema name and type name are valid.", + temp->paramOrdinal + 1, temp->paramMeta.colName.data, 1, 1, temp->type))); initStringInfo(tempStringInfo); tempString = palloc0(len * 2); memcpy(tempString, &messageData[*offset], len * 2); - TdsUTF16toUTF8StringInfo(tempStringInfo, tempString,len * 2); + TdsUTF16toUTF8StringInfo(tempStringInfo, tempString, len * 2); - *offset += len * 2; + *offset += len * 2; temp->len += len; - if(i == 1) + if (i == 1) temp->tvpInfo->tvpTypeSchemaName = tempStringInfo->data; else temp->tvpInfo->tvpTypeName = tempStringInfo->data; @@ -516,8 +530,8 @@ SetColMetadataForTvp(ParameterToken temp,const StringInfo message, uint64_t *off ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " - "Table-valued parameter %d, to a parameterized string has no table type defined.", - temp->paramOrdinal + 1))); + "Table-valued parameter %d, to a parameterized string has no table type defined.", + temp->paramOrdinal + 1))); } } @@ -531,6 +545,7 @@ SetColMetadataForTvp(ParameterToken temp,const StringInfo message, uint64_t *off * TypeColumnMetaData = UserType Flags TYPE_INFO ColName ; */ TvpColMetaData *colmetadata; + memcpy(&colCount, &messageData[*offset], sizeof(uint16)); colmetadata = palloc0(colCount * sizeof(TvpColMetaData)); temp->tvpInfo->colCount = colCount; @@ -538,16 +553,16 @@ SetColMetadataForTvp(ParameterToken temp,const StringInfo message, uint64_t *off temp->isNull = false; - while(i != colCount) + while (i != colCount) { if (((*offset) + sizeof(uint32_t) > message->len)) ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " - "Table-valued parameter %d (\"%s\"), row %d, column %d: Data type 0x%02X " - "(user-defined table type) has an invalid column count specified.", - temp->paramOrdinal + 1, temp->paramMeta.colName.data, 1, i + 1, temp->type))); - + "Table-valued parameter %d (\"%s\"), row %d, column %d: Data type 0x%02X " + "(user-defined table type) has an invalid column count specified.", + temp->paramOrdinal + 1, temp->paramMeta.colName.data, 1, i + 1, temp->type))); + /* UserType */ memcpy(&colmetadata[i].userType, &messageData[*offset], sizeof(uint32_t)); *offset += sizeof(uint32_t); @@ -557,7 +572,7 @@ SetColMetadataForTvp(ParameterToken temp,const StringInfo message, uint64_t *off /* TYPE_INFO */ colmetadata[i].columnTdsType = messageData[(*offset)++]; - switch(colmetadata[i].columnTdsType) + switch (colmetadata[i].columnTdsType) { case TDS_TYPE_INTEGER: case TDS_TYPE_BIT: @@ -566,87 +581,89 @@ SetColMetadataForTvp(ParameterToken temp,const StringInfo message, uint64_t *off case TDS_TYPE_DATETIMEN: case TDS_TYPE_UNIQUEIDENTIFIER: colmetadata[i].maxLen = messageData[(*offset)++]; - break; + break; case TDS_TYPE_DECIMALN: case TDS_TYPE_NUMERICN: - colmetadata[i].maxLen = messageData[(*offset)++]; + colmetadata[i].maxLen = messageData[(*offset)++]; colmetadata[i].precision = messageData[(*offset)++]; - colmetadata[i].scale = messageData[(*offset)++]; - break; + colmetadata[i].scale = messageData[(*offset)++]; + break; case TDS_TYPE_CHAR: case TDS_TYPE_VARCHAR: case TDS_TYPE_NCHAR: case TDS_TYPE_NVARCHAR: - { - memcpy(&colmetadata[i].maxLen, &messageData[*offset], sizeof(uint16)); - *offset += sizeof(uint16); + { + memcpy(&colmetadata[i].maxLen, &messageData[*offset], sizeof(uint16)); + *offset += sizeof(uint16); - memcpy(&collation, &messageData[*offset], sizeof(uint32_t)); - *offset += sizeof(uint32_t); - colmetadata[i].sortId = messageData[(*offset)++]; - colmetadata[i].encoding = TdsGetEncoding(collation); - } - break; + memcpy(&collation, &messageData[*offset], sizeof(uint32_t)); + *offset += sizeof(uint32_t); + colmetadata[i].sortId = messageData[(*offset)++]; + colmetadata[i].encoding = TdsGetEncoding(collation); + } + break; case TDS_TYPE_XML: - { - colmetadata[i].maxLen = messageData[(*offset)++]; - } - break; + { + colmetadata[i].maxLen = messageData[(*offset)++]; + } + break; case TDS_TYPE_DATETIME2: - { - colmetadata[i].scale = messageData[(*offset)++]; - colmetadata[i].maxLen = 8; - } - break; + { + colmetadata[i].scale = messageData[(*offset)++]; + colmetadata[i].maxLen = 8; + } + break; case TDS_TYPE_TIME: - { - colmetadata[i].scale = messageData[(*offset)++]; - colmetadata[i].maxLen = 5; - } - break; + { + colmetadata[i].scale = messageData[(*offset)++]; + colmetadata[i].maxLen = 5; + } + break; case TDS_TYPE_BINARY: case TDS_TYPE_VARBINARY: - { - uint16 plp; - memcpy(&plp, &messageData[*offset], sizeof(uint16)); - *offset += sizeof(uint16); - colmetadata[i].maxLen = plp; - } - break; + { + uint16 plp; + + memcpy(&plp, &messageData[*offset], sizeof(uint16)); + *offset += sizeof(uint16); + colmetadata[i].maxLen = plp; + } + break; case TDS_TYPE_DATE: colmetadata[i].maxLen = 3; - break; + break; case TDS_TYPE_SQLVARIANT: memcpy(&colmetadata[i].maxLen, &messageData[*offset], sizeof(uint32_t)); *offset += sizeof(uint32_t); - break; + break; default: - ereport(ERROR, + ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " - "Table-valued parameter %d (\"%s\"), row %d, column %d: Data type 0x%02X is unknown.", - temp->paramOrdinal + 1, temp->paramMeta.colName.data, 1, i + 1, colmetadata[i].columnTdsType))); + "Table-valued parameter %d (\"%s\"), row %d, column %d: Data type 0x%02X is unknown.", + temp->paramOrdinal + 1, temp->paramMeta.colName.data, 1, i + 1, colmetadata[i].columnTdsType))); } if ((colmetadata[i].flags & TDS_COLMETA_COMPUTED) && ((messageData[*offset] == TVP_ORDER_UNIQUE_TOKEN) || - (messageData[*offset] == TVP_COLUMN_ORDERING_TOKEN))) + (messageData[*offset] == TVP_COLUMN_ORDERING_TOKEN))) ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("Table-valued parameter %d (\"%s\"), row %d, column %d: Data type 0x%02X (user-defined table type). " - "The specified column is computed or default and has ordering or uniqueness set. Ordering and uniqueness " - "can only be set on columns that have client supplied data.", - temp->paramOrdinal + 1, temp->paramMeta.colName.data, 1, i + 1, colmetadata[i].columnTdsType))); + "The specified column is computed or default and has ordering or uniqueness set. Ordering and uniqueness " + "can only be set on columns that have client supplied data.", + temp->paramOrdinal + 1, temp->paramMeta.colName.data, 1, i + 1, colmetadata[i].columnTdsType))); if (messageData[*offset] != TVP_END_TOKEN) ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " - "Table-valued parameter %d (\"%s\"), row %d, column %d: Data type 0x%02X (user-defined table type) " - "unexpected token encountered processing a table-valued parameter.", - temp->paramOrdinal + 1, temp->paramMeta.colName.data, 1, i + 1, colmetadata[i].columnTdsType))); + "Table-valued parameter %d (\"%s\"), row %d, column %d: Data type 0x%02X (user-defined table type) " + "unexpected token encountered processing a table-valued parameter.", + temp->paramOrdinal + 1, temp->paramMeta.colName.data, 1, i + 1, colmetadata[i].columnTdsType))); i++; (*offset)++; } - temp->tvpInfo->colMetaData = colmetadata; /* Setting the column metadata in paramtoken. */ + temp->tvpInfo->colMetaData = colmetadata; /* Setting the column + * metadata in paramtoken. */ /* TODO Optional Metadata token:- [TVP_ORDER_UNIQUE] */ if (messageData[*offset] == TVP_ORDER_UNIQUE_TOKEN) @@ -664,14 +681,14 @@ SetColMetadataForTvp(ParameterToken temp,const StringInfo message, uint64_t *off ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. " - "Table-valued parameter %d (\"%s\"), row %d, column %d: Data type 0x%02X (user-defined table type) " - "unexpected token encountered processing a table-valued parameter.", - temp->paramOrdinal + 1, temp->paramMeta.colName.data, 1, i + 1, colmetadata[i].columnTdsType))); + "Table-valued parameter %d (\"%s\"), row %d, column %d: Data type 0x%02X (user-defined table type) " + "unexpected token encountered processing a table-valued parameter.", + temp->paramOrdinal + 1, temp->paramMeta.colName.data, 1, i + 1, colmetadata[i].columnTdsType))); (*offset)++; } else { - temp->isNull = true; /* If TVP is NULL. */ + temp->isNull = true; /* If TVP is NULL. */ (*offset) += 2; } SetTvpRowData(temp, message, offset); @@ -683,9 +700,9 @@ SetColMetadataForFixedType(TdsColumnMetaData *col, uint8_t tdsType, uint8_t maxS col->sizeLen = 1; /* - * If column is Not NULL constrained then we don't want to send - * maxSize except for uniqueidentifier and xml. - * This needs to be done for identity contraints as well. + * If column is Not NULL constrained then we don't want to send maxSize + * except for uniqueidentifier and xml. This needs to be done for identity + * contraints as well. */ if (col->attNotNull && tdsType != TDS_TYPE_UNIQUEIDENTIFIER && tdsType != TDS_TYPE_XML) { @@ -753,13 +770,14 @@ SetColMetadataForImageType(TdsColumnMetaData *col, uint8_t tdsType) else if (tdsType == TDS_TYPE_SQLVARIANT) { col->sendTableName = false; + /* - * varchar(max), nvarchar(max), varbinary(max) can not be supported - * by sql_variant, this is a datatype restriction, hence, maxLen supported - * for varchar, nvarchar, varbinary would be <= 8K + * varchar(max), nvarchar(max), varbinary(max) can not be supported by + * sql_variant, this is a datatype restriction, hence, maxLen + * supported for varchar, nvarchar, varbinary would be <= 8K */ col->metaEntry.type8.maxSize = 0x00001f49; - } + } col->metaLen = sizeof(col->metaEntry.type8); col->metaEntry.type8.flags = TDS_COL_METADATA_DEFAULT_FLAGS; col->metaEntry.type8.tdsTypeId = tdsType; @@ -776,7 +794,7 @@ SetColMetadataForDateType(TdsColumnMetaData *col, uint8_t tdsType) static inline void SetColMetadataForNumericType(TdsColumnMetaData *col, uint8_t tdsType, - uint8_t maxSize, uint8_t precision, uint8_t scale) + uint8_t maxSize, uint8_t precision, uint8_t scale) { col->sizeLen = 1; col->metaLen = sizeof(col->metaEntry.type5); @@ -817,21 +835,21 @@ static inline void SetColMetadataForCharTypeHelper(TdsColumnMetaData *col, uint8_t tdsType, Oid collation, int32 atttypmod) { - coll_info_t cinfo; + coll_info_t cinfo; cinfo = TdsLookupCollationTableCallback(collation); /* - * TODO: Remove the NULL condition once all the Postgres collations are mapped - * to TSQL + * TODO: Remove the NULL condition once all the Postgres collations are + * mapped to TSQL */ if (cinfo.oid == InvalidOid) { SetColMetadataForCharType(col, tdsType, - TdsDefaultLcid, /* collation lcid */ + TdsDefaultLcid, /* collation lcid */ TdsDefaultClientEncoding, - TdsDefaultCollationFlags, /* collation flags */ - TdsDefaultSortid, /* sort id */ + TdsDefaultCollationFlags, /* collation flags */ + TdsDefaultSortid, /* sort id */ atttypmod); } else @@ -860,16 +878,16 @@ SetColMetadataForTextTypeHelper(TdsColumnMetaData *col, uint8_t tdsType, cinfo = TdsLookupCollationTableCallback(collation); /* - * TODO: Remove the NULL condition once all the Postgres collations are mapped - * to TSQL + * TODO: Remove the NULL condition once all the Postgres collations are + * mapped to TSQL */ if (cinfo.oid == InvalidOid) { SetColMetadataForTextType(col, tdsType, - TdsDefaultLcid, /* collation lcid */ + TdsDefaultLcid, /* collation lcid */ TdsDefaultClientEncoding, - TdsDefaultCollationFlags, /* collation flags */ - TdsDefaultSortid, /* sort id */ + TdsDefaultCollationFlags, /* collation flags */ + TdsDefaultSortid, /* sort id */ atttypmod); } else @@ -896,10 +914,10 @@ extern void ProcessRPCRequest(TDSRequest request); /* Functions in tdsxact.c */ extern TDSRequest GetTxnMgmtRequest(const StringInfo message); extern void ProcessTxnMgmtRequest(TDSRequest request); -extern int TestTxnMgmtRequest(TDSRequest request, const char *expectedStr); +extern int TestTxnMgmtRequest(TDSRequest request, const char *expectedStr); /* Functions in tdsbulkload.c */ extern TDSRequest GetBulkLoadRequest(StringInfo message); extern void ProcessBCPRequest(TDSRequest request); -#endif /* TDS_REQUEST_H */ +#endif /* TDS_REQUEST_H */ diff --git a/contrib/babelfishpg_tds/src/include/tds_response.h b/contrib/babelfishpg_tds/src/include/tds_response.h index 9d698dfb13..92504287dc 100644 --- a/contrib/babelfishpg_tds/src/include/tds_response.h +++ b/contrib/babelfishpg_tds/src/include/tds_response.h @@ -64,34 +64,34 @@ extern ParameterToken MakeEmptyParameterToken(char *name, int atttypid, int32 atttypmod, int attcollation); extern int32 GetTypModForToken(ParameterToken token); extern void TdsSendInfo(int number, int state, int class, - char *message, int line_no); + char *message, int line_no); extern void TdsSendDone(int tag, int status, - int curcmd, uint64_t nprocessed); + int curcmd, uint64_t nprocessed); extern void SendColumnMetadataToken(int natts, bool sendRowStat); extern void SendTabNameToken(void); extern void SendColInfoToken(int natts, bool sendRowStat); extern void PrepareRowDescription(TupleDesc typeinfo, List *targetlist, int16 *formats, - bool extendedInfo, bool fetchPkeys); + bool extendedInfo, bool fetchPkeys); extern void SendReturnValueTokenInternal(ParameterToken token, uint8 status, - FmgrInfo *finfo, Datum datum, bool isNull, - bool forceCoercion); + FmgrInfo *finfo, Datum datum, bool isNull, + bool forceCoercion); extern void TdsSendEnvChange(int envid, const char *new_val, const char *old_val); extern void TdsSendInfoOrError(int token, int number, int state, int class, - char *message, char *server_name, - char *proc_name, int line_no); + char *message, char *server_name, + char *proc_name, int line_no); extern void TdsPrepareReturnValueMetaData(TupleDesc typeinfo); extern void TdsSendEnvChangeBinary(int envid, - void *new, int new_nbytes, - void *old, int old_nbytes); + void *new, int new_nbytes, + void *old, int old_nbytes); extern void TdsSendReturnStatus(int status); extern void TdsSendHandle(void); extern void TdsSendRowDescription(TupleDesc typeinfo, - List *targetlist, int16 *formats); + List *targetlist, int16 *formats); extern bool TdsPrintTup(TupleTableSlot *slot, DestReceiver *self); extern void TdsPrintTupShutdown(void); extern void TdsSendError(int number, int state, int class, - char *message, int lineNo); -extern int TdsFlush(void); + char *message, int lineNo); +extern int TdsFlush(void); extern void TDSStatementBeginCallback(PLtsql_execstate *estate, PLtsql_stmt *stmt); extern void TDSStatementEndCallback(PLtsql_execstate *estate, PLtsql_stmt *stmt); extern void TDSStatementExceptionCallback(PLtsql_execstate *estate, PLtsql_stmt *stmt, @@ -99,4 +99,4 @@ extern void TDSStatementExceptionCallback(PLtsql_execstate *estate, PLtsql_stmt extern void SendColumnMetadata(TupleDesc typeinfo, List *targetlist, int16 *formats); extern bool GetTdsEstateErrorData(int *number, int *severity, int *state); -#endif /* TDS_H */ +#endif /* TDS_H */ diff --git a/contrib/babelfishpg_tds/src/include/tds_secure.h b/contrib/babelfishpg_tds/src/include/tds_secure.h index cfd9bcf616..0ec721b57c 100644 --- a/contrib/babelfishpg_tds/src/include/tds_secure.h +++ b/contrib/babelfishpg_tds/src/include/tds_secure.h @@ -38,24 +38,25 @@ #endif #endif -BIO_METHOD *TdsBioSecureSocket(BIO_METHOD *my_bio_methods); +BIO_METHOD *TdsBioSecureSocket(BIO_METHOD * my_bio_methods); extern int tds_ssl_min_protocol_version; extern int tds_ssl_max_protocol_version; /* TDS specific function defined in tds-secure-openssl.c (modified copy of be-secure-openssl.c) */ -int Tds_be_tls_init(bool isServerStart); -void Tds_be_tls_destroy(void); /* TODO: call through our signal handler(SIGHUP_handler)/PG_TDS_fin */ -int Tds_be_tls_open_server(Port *port); +int Tds_be_tls_init(bool isServerStart); +void Tds_be_tls_destroy(void); /* TODO: call through our signal + * handler(SIGHUP_handler)/PG_TDS_fin */ +int Tds_be_tls_open_server(Port *port); extern void Tds_be_tls_close(Port *port); -ssize_t Tds_be_tls_read(Port *port, void *ptr, size_t len, int *waitfor); -ssize_t Tds_be_tls_write(Port *port, void *ptr, size_t len, int *waitfor); +ssize_t Tds_be_tls_read(Port *port, void *ptr, size_t len, int *waitfor); +ssize_t Tds_be_tls_write(Port *port, void *ptr, size_t len, int *waitfor); /* function defined in tdssecure.c and called from tdscomm.c */ ssize_t -tds_secure_read(Port *port, void *ptr, size_t len); + tds_secure_read(Port *port, void *ptr, size_t len); ssize_t -tds_secure_write(Port *port, void *ptr, size_t len); + tds_secure_write(Port *port, void *ptr, size_t len); /* function defined in tdssecure.c and called from tdslogin.c */ -void TdsFreeSslStruct(Port *port); +void TdsFreeSslStruct(Port *port); diff --git a/contrib/babelfishpg_tds/src/include/tds_timestamp.h b/contrib/babelfishpg_tds/src/include/tds_timestamp.h index 043097d24c..1508e58ae2 100644 --- a/contrib/babelfishpg_tds/src/include/tds_timestamp.h +++ b/contrib/babelfishpg_tds/src/include/tds_timestamp.h @@ -17,21 +17,21 @@ #define DATETIMEOFFSETMAXSCALE 7 extern void TdsGetTimestampFromDayTime(uint32 numDays, uint64 numMicro, int tz, - Timestamp *timestamp, int scale); + Timestamp *timestamp, int scale); extern void TdsGetDayTimeFromTimestamp(Timestamp value, uint32 *numDays, - uint64 *numSec, int scale); + uint64 *numSec, int scale); extern void TdsTimeDifferenceSmalldatetime(Datum value, uint16 *numDays, - uint16 *numMins); + uint16 *numMins); extern void TdsTimeGetDatumFromSmalldatetime(uint16 numDays, uint16 numMins, - Timestamp *timestamp); + Timestamp *timestamp); extern uint32 TdsDayDifference(Datum value); extern void TdsTimeDifferenceDatetime(Datum value, uint32 *numDays, - uint32 *numTicks); + uint32 *numTicks); extern void TdsCheckDateValidity(DateADT result); extern void TdsTimeGetDatumFromDays(uint32 numDays, uint64 *val); extern void TdsTimeGetDatumFromDatetime(uint32 numDays, uint32 numTicks, - Timestamp *timestamp); + Timestamp *timestamp); extern uint32 TdsGetDayDifferenceHelper(int day, int mon, int year, bool isDateType); /* @@ -39,8 +39,8 @@ extern uint32 TdsGetDayDifferenceHelper(int day, int mon, int year, bool isDateT */ typedef struct tsql_datetimeoffset { - int64 tsql_ts; - int16 tsql_tz; + int64 tsql_ts; + int16 tsql_tz; } tsql_datetimeoffset; /* datetimeoffset macros */ diff --git a/contrib/babelfishpg_tds/src/include/tds_typecode.h b/contrib/babelfishpg_tds/src/include/tds_typecode.h index 427d374920..dbd092b957 100644 --- a/contrib/babelfishpg_tds/src/include/tds_typecode.h +++ b/contrib/babelfishpg_tds/src/include/tds_typecode.h @@ -12,7 +12,7 @@ #define DATE_T 5 #define TIME_T 6 #define FLOAT_T 7 -#define REAL_T 8 +#define REAL_T 8 #define NUMERIC_T 9 #define MONEY_T 10 #define SMALLMONEY_T 11 diff --git a/contrib/babelfishpg_tds/src/include/tds_typeio.h b/contrib/babelfishpg_tds/src/include/tds_typeio.h index 1a25e2487d..7eb1d48873 100644 --- a/contrib/babelfishpg_tds/src/include/tds_typeio.h +++ b/contrib/babelfishpg_tds/src/include/tds_typeio.h @@ -36,97 +36,107 @@ * Circular dependency for parameter token needs to be handled * in a similar way as that of column meta data */ -typedef int (*TdsSendTypeFunction)(FmgrInfo *finfo, Datum value, - void *vMetaData); +typedef int (*TdsSendTypeFunction) (FmgrInfo *finfo, Datum value, + void *vMetaData); /* COLMETADATA entry for types like INTEGER and SMALLINT */ -typedef struct __attribute__((packed)) ColMetaEntry1 +typedef struct __attribute__ ((packed)) +ColMetaEntry1 { - uint16_t flags; - uint8_t tdsTypeId; - uint8_t maxSize; + uint16_t flags; + uint8_t tdsTypeId; + uint8_t maxSize; } ColMetaEntry1; /* COLMETADATA entry for types like NVARCHAR */ -typedef struct __attribute__((packed)) ColMetaEntry2 +typedef struct __attribute__ ((packed)) +ColMetaEntry2 { - uint16_t flags; - uint8_t tdsTypeId; - uint16_t maxSize; + uint16_t flags; + uint8_t tdsTypeId; + uint16_t maxSize; + /* - * collationInfo(32 bits): LCID/CodePage (20 bits) + - * collationFlags(8 bits) + version (4 bits) + * collationInfo(32 bits): LCID/CodePage (20 bits) + collationFlags(8 + * bits) + version (4 bits) */ - uint32_t collationInfo; - uint8_t charSet; /* sortID */ + uint32_t collationInfo; + uint8_t charSet; /* sortID */ } ColMetaEntry2; /* COLMETADATA entry for types like TEXT */ -typedef struct __attribute__((packed)) ColMetaEntry3 +typedef struct __attribute__ ((packed)) +ColMetaEntry3 { - uint16_t flags; - uint8_t tdsTypeId; - uint32_t maxSize; + uint16_t flags; + uint8_t tdsTypeId; + uint32_t maxSize; + /* - * collationInfo(32 bits): LCID/CodePage (20 bits) + - * collationFlags(8 bits) + version (4 bits) + * collationInfo(32 bits): LCID/CodePage (20 bits) + collationFlags(8 + * bits) + version (4 bits) */ - uint32_t collationInfo; - uint8_t charSet; /* sortID */ + uint32_t collationInfo; + uint8_t charSet; /* sortID */ } ColMetaEntry3; /* COLMETADATA entry for type like DATE */ -typedef struct __attribute__((packed)) ColMetaEntry4 +typedef struct __attribute__ ((packed)) +ColMetaEntry4 { - uint16_t flags; - uint8_t tdsTypeId; + uint16_t flags; + uint8_t tdsTypeId; } ColMetaEntry4; /* COLMETADATA entry for type NUMERIC */ -typedef struct __attribute__((packed)) ColMetaEntry5 +typedef struct __attribute__ ((packed)) +ColMetaEntry5 { - uint16_t flags; - uint8_t tdsTypeId; - uint8_t maxSize; - uint8_t precision; - uint8_t scale; + uint16_t flags; + uint8_t tdsTypeId; + uint8_t maxSize; + uint8_t precision; + uint8_t scale; } ColMetaEntry5; /* COLMETADATA entry for type like TIME, DATETIME2, DATETIMEOFFSET */ -typedef struct __attribute__((packed)) ColMetaEntry6 +typedef struct __attribute__ ((packed)) +ColMetaEntry6 { - uint16_t flags; - uint8_t tdsTypeId; - uint8_t scale; + uint16_t flags; + uint8_t tdsTypeId; + uint8_t scale; } ColMetaEntry6; /* COLMETADATA entry for types like BINARY VARBINARY */ -typedef struct __attribute__((packed)) ColMetaEntry7 +typedef struct __attribute__ ((packed)) +ColMetaEntry7 { - uint16_t flags; - uint8_t tdsTypeId; - uint16_t maxSize; + uint16_t flags; + uint8_t tdsTypeId; + uint16_t maxSize; } ColMetaEntry7; /* COLMETADATA entry for type like IMAGE */ -typedef struct __attribute__((packed)) ColMetaEntry8 +typedef struct __attribute__ ((packed)) +ColMetaEntry8 { - uint16_t flags; - uint8_t tdsTypeId; - uint32_t maxSize; + uint16_t flags; + uint8_t tdsTypeId; + uint32_t maxSize; } ColMetaEntry8; typedef union ColMetaEntry { - ColMetaEntry1 type1; - ColMetaEntry2 type2; - ColMetaEntry3 type3; - ColMetaEntry4 type4; - ColMetaEntry5 type5; - ColMetaEntry6 type6; - ColMetaEntry7 type7; - ColMetaEntry8 type8; + ColMetaEntry1 type1; + ColMetaEntry2 type2; + ColMetaEntry3 type3; + ColMetaEntry4 type4; + ColMetaEntry5 type5; + ColMetaEntry6 type6; + ColMetaEntry7 type7; + ColMetaEntry8 type8; } ColMetaEntry; /* @@ -136,53 +146,51 @@ typedef union ColMetaEntry */ typedef struct TdsRelationMetaData { - Oid relOid; /* relation oid */ - AttrNumber *keyattrs; /* primary keys for this relation */ - int16 numkeyattrs; /* number of attributes in pk */ + Oid relOid; /* relation oid */ + AttrNumber *keyattrs; /* primary keys for this relation */ + int16 numkeyattrs; /* number of attributes in pk */ /* * We store the fully qualified name of the relation. This information is * needed on TABNAME token. * - * partName[0] - relation name - * partName[1] - schema name - * partName[2] - database name - * partName[3] - object name + * partName[0] - relation name partName[1] - schema name partName[2] - + * database name partName[3] - object name */ - char *partName[4]; + char *partName[4]; /* * A 1-based index for this relation which is used while sending the * COLINFO token. */ - uint8 tableNum; + uint8 tableNum; } TdsRelationMetaDataInfoData; typedef TdsRelationMetaDataInfoData *TdsRelationMetaDataInfo; typedef struct TdsColumnMetaData { - Oid pgTypeOid; /* type identifier in PostgreSQL */ - StringInfoData colName; /* column name */ - int sizeLen; /* size of the type's data length */ - int metaLen; /* size of ColMetaEntry used */ - TdsSendTypeFunction sendFunc; - ColMetaEntry metaEntry; - bool sendTableName; - pg_enc encoding; + Oid pgTypeOid; /* type identifier in PostgreSQL */ + StringInfoData colName; /* column name */ + int sizeLen; /* size of the type's data length */ + int metaLen; /* size of ColMetaEntry used */ + TdsSendTypeFunction sendFunc; + ColMetaEntry metaEntry; + bool sendTableName; + pg_enc encoding; /* - * Following information are only needed if we need to send TABNAME and COLINFO - * tokens. + * Following information are only needed if we need to send TABNAME and + * COLINFO tokens. */ - char *baseColName; /* actual column name if any alias is used */ - Oid relOid; /* relation that this column belongs to (0 if - an expression column */ - AttrNumber attrNum; /* attribute number in the relation */ - TdsRelationMetaDataInfo relinfo; - bool attNotNull; /* true if the column has not null constraint */ - bool attidentity; /* true if it is an identity column */ - bool attgenerated; /* true if it is a computed column */ + char *baseColName; /* actual column name if any alias is used */ + Oid relOid; /* relation that this column belongs to (0 if + * an expression column */ + AttrNumber attrNum; /* attribute number in the relation */ + TdsRelationMetaDataInfo relinfo; + bool attNotNull; /* true if the column has not null constraint */ + bool attidentity; /* true if it is an identity column */ + bool attgenerated; /* true if it is a computed column */ } TdsColumnMetaData; /* Partial Length Prefixed-bytes */ @@ -196,131 +204,129 @@ typedef PlpData *Plp; typedef struct TvpColMetaData { - int userType; - uint16 flags; - uint8_t columnTdsType; + int userType; + uint16 flags; + uint8_t columnTdsType; /* For numeric and decimal. */ - uint8_t scale; - uint8_t precision; + uint8_t scale; + uint8_t precision; - uint8_t sortId; - pg_enc encoding; + uint8_t sortId; + pg_enc encoding; - uint32_t maxLen; + uint32_t maxLen; } TvpColMetaData; typedef struct TvpRowData { /* Array of length col count, holds value of each column in that row. */ - StringInfo columnValues; + StringInfo columnValues; - char *isNull; + char *isNull; struct TvpRowData *nextRow; } TvpRowData; typedef struct TvpData { - char *tvpTypeName; - char *tvpTypeSchemaName; - char *tableName; - int colCount; - int rowCount; - - TvpColMetaData *colMetaData; /* Array of each column's metadata. */ - TvpRowData *rowData; /* Linked List holding each row. */ + char *tvpTypeName; + char *tvpTypeSchemaName; + char *tableName; + int colCount; + int rowCount; + + TvpColMetaData *colMetaData; /* Array of each column's metadata. */ + TvpRowData *rowData; /* Linked List holding each row. */ } TvpData; typedef struct BulkLoadColMetaData { - int userType; - uint16 flags; - uint8_t columnTdsType; + int userType; + uint16 flags; + uint8_t columnTdsType; /* For numeric and decimal. */ - uint8_t scale; - uint8_t precision; + uint8_t scale; + uint8_t precision; /* For String Datatpes. */ - uint8_t sortId; + uint8_t sortId; pg_enc encoding; - uint32_t maxLen; + uint32_t maxLen; - uint32_t colNameLen; - char *colName; + uint32_t colNameLen; + char *colName; - bool variantType; + bool variantType; } BulkLoadColMetaData; typedef struct BulkLoadRowData { /* Array of length col count, holds value of each column in that row. */ - Datum *columnValues; + Datum *columnValues; - bool *isNull; + bool *isNull; } BulkLoadRowData; /* Map TVP to its underlying table, either by relid or by table name. */ typedef struct TvpLookupItem { - char *name; - Oid tableRelid; - char *tableName; + char *name; + Oid tableRelid; + char *tableName; } TvpLookupItem; /* parameter token in RPC */ typedef struct ParameterTokenData { - uint8_t type; - uint8_t flags; + uint8_t type; + uint8_t flags; /* - * maxlen and len fields are 4 bytes for some - * datatypes(text, ntext) while 2 bytes for - * (nvarchar, others?) and 1 byte for others. + * maxlen and len fields are 4 bytes for some datatypes(text, ntext) while + * 2 bytes for (nvarchar, others?) and 1 byte for others. */ - uint32_t maxLen; - uint32_t len; - bool isNull; + uint32_t maxLen; + uint32_t len; + bool isNull; - Plp plp; + Plp plp; /* - * dataOffset points to the offset in the request message - * from where the data bytes actually start. - * Using, dataOffset + len we can fetch the entire data - * from the request message, when we want to use it. + * dataOffset points to the offset in the request message from where the + * data bytes actually start. Using, dataOffset + len we can fetch the + * entire data from the request message, when we want to use it. */ - int dataOffset; + int dataOffset; - uint16 paramOrdinal; + uint16 paramOrdinal; /* * Upon receiving a parameter for a RPC packet, we fill the following * structure with the meta information about that parameter. We also * store the corresponding PG type OID, receiver function and sender - * function. For IN parameters, we use the receiver functions to - * convert the parameter from TDS wire format to Datum. For OUT - * parameters, we use the sender functions to convert the Datums to - * TDS wire format and include them in the return value tokens. + * function. For IN parameters, we use the receiver functions to convert + * the parameter from TDS wire format to Datum. For OUT parameters, we + * use the sender functions to convert the Datums to TDS wire format and + * include them in the return value tokens. */ - TdsColumnMetaData paramMeta; + TdsColumnMetaData paramMeta; /* * If this is an OUT parameter, it points to the column number in the * result set. */ - int outAttNo; + int outAttNo; - TvpData *tvpInfo; + TvpData *tvpInfo; struct ParameterTokenData *next; } ParameterTokenData; typedef ParameterTokenData *ParameterToken; -typedef Datum (*TdsRecvTypeFunction)(const char *, const ParameterToken); +typedef Datum (*TdsRecvTypeFunction) (const char *, const ParameterToken); /* * TdsCollationData - hash table structure for @@ -328,13 +334,13 @@ typedef Datum (*TdsRecvTypeFunction)(const char *, const ParameterToken); */ typedef struct TdsCollationData { - Oid collationOid; - int32_t codePage; - int32_t collateFlags; - int32_t sortId; -} TdsCollationData; + Oid collationOid; + int32_t codePage; + int32_t collateFlags; + int32_t sortId; +} TdsCollationData; -typedef TdsCollationData *TdsCollationInfo; +typedef TdsCollationData * TdsCollationInfo; /* * TdsLCIDToEncodingMap - hash table structure to @@ -342,11 +348,12 @@ typedef TdsCollationData *TdsCollationInfo; */ typedef struct TdsLCIDToEncodingMap { - int lcid; - int enc; + int lcid; + int enc; } TdsLCIDToEncodingMap; typedef TdsLCIDToEncodingMap *TdsLCIDToEncodingMapInfo; + /* * TdsIoFunctionData - hash table entry for IO function cache * TdsIoFunctionRawData - Raw Table data entry for TdsIoFunctionData @@ -356,24 +363,24 @@ typedef struct TdsIoFunctionRawData { const char *typnsp; const char *typname; - int32_t ttmtdstypeid; - int32_t ttmtdstypelen; - int32_t ttmtdslenbytes; - int32_t ttmsendfunc; - int32_t ttmrecvfunc; + int32_t ttmtdstypeid; + int32_t ttmtdstypelen; + int32_t ttmtdslenbytes; + int32_t ttmsendfunc; + int32_t ttmrecvfunc; } TdsIoFunctionRawData; typedef struct TdsIoFunctionData { - Oid ttmtypeid; - Oid ttmbasetypeid; - int32_t ttmtdstypeid; - int32_t ttmtdstypelen; - int32_t ttmtdslenbytes; - int32_t sendFuncId; - int32_t recvFuncId; - TdsSendTypeFunction sendFuncPtr; - TdsRecvTypeFunction recvFuncPtr; + Oid ttmtypeid; + Oid ttmbasetypeid; + int32_t ttmtdstypeid; + int32_t ttmtdstypelen; + int32_t ttmtdslenbytes; + int32_t sendFuncId; + int32_t recvFuncId; + TdsSendTypeFunction sendFuncPtr; + TdsRecvTypeFunction recvFuncPtr; } TdsIoFunctionData; typedef struct TdsIoFunctionData *TdsIoFunctionInfo; @@ -381,49 +388,49 @@ typedef struct TdsIoFunctionData *TdsIoFunctionInfo; /* Functions in tdstypeio.c */ extern void TdsResetCache(void); extern void TdsLoadTypeFunctionCache(void); -extern TdsIoFunctionInfo TdsLookupTypeFunctionsByOid(Oid typeId, int32* typmod); -extern TdsIoFunctionInfo TdsLookupTypeFunctionsByTdsId(int32_t typeId, - int32_t typeLen); +extern TdsIoFunctionInfo TdsLookupTypeFunctionsByOid(Oid typeId, int32 *typmod); +extern TdsIoFunctionInfo TdsLookupTypeFunctionsByTdsId(int32_t typeId, + int32_t typeLen); extern StringInfo TdsGetStringInfoBufferFromToken(const char *message, - const ParameterToken token); + const ParameterToken token); extern StringInfo TdsGetPlpStringInfoBufferFromToken(const char *message, - const ParameterToken token); + const ParameterToken token); extern void TdsReadUnicodeDataFromTokenCommon(const char *message, - const ParameterToken token, - StringInfo temp); + const ParameterToken token, + StringInfo temp); TdsCollationInfo TdsLookupCollationByOid(Oid cId); extern void TdsLoadEncodingLCIDCache(void); -extern int TdsLookupEncodingByLCID(int LCID); -extern int TdsSendTypeBit(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeTinyint(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeSmallint(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeInteger(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeBigint(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeFloat4(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeFloat8(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeVarchar(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeNVarchar(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeMoney(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeSmallmoney(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeChar(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeNChar(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeSmalldatetime(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeText(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeNText(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeDate(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeDatetime(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeNumeric(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeSmalldatetime(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeImage(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeBinary(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeVarbinary(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeUniqueIdentifier(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeTime(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeDatetime2(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeXml(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeSqlvariant(FmgrInfo *finfo, Datum value, void *vMetaData); -extern int TdsSendTypeDatetimeoffset(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsLookupEncodingByLCID(int LCID); +extern int TdsSendTypeBit(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeTinyint(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeSmallint(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeInteger(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeBigint(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeFloat4(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeFloat8(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeVarchar(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeNVarchar(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeMoney(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeSmallmoney(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeChar(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeNChar(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeSmalldatetime(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeText(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeNText(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeDate(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeDatetime(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeNumeric(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeSmalldatetime(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeImage(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeBinary(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeVarbinary(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeUniqueIdentifier(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeTime(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeDatetime2(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeXml(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeSqlvariant(FmgrInfo *finfo, Datum value, void *vMetaData); +extern int TdsSendTypeDatetimeoffset(FmgrInfo *finfo, Datum value, void *vMetaData); extern Datum TdsRecvTypeBit(const char *, const ParameterToken); extern Datum TdsRecvTypeTinyInt(const char *, const ParameterToken); @@ -474,4 +481,4 @@ extern Datum TdsTypeXMLToDatum(StringInfo buf); extern Datum TdsTypeUIDToDatum(StringInfo buf); extern Datum TdsTypeSqlVariantToDatum(StringInfo buf); -#endif /* TDS_TYPEIO_H */ +#endif /* TDS_TYPEIO_H */ diff --git a/contrib/babelfishpg_tds/src/include/tdsprinttup.h b/contrib/babelfishpg_tds/src/include/tdsprinttup.h index 78fdf82d9d..d3504ffd42 100644 --- a/contrib/babelfishpg_tds/src/include/tdsprinttup.h +++ b/contrib/babelfishpg_tds/src/include/tdsprinttup.h @@ -11,5 +11,3 @@ * *------------------------------------------------------------------------- */ - - diff --git a/contrib/babelfishpg_tsql/runtime/functions.c b/contrib/babelfishpg_tsql/runtime/functions.c index 6917591a12..ca28e8229c 100644 --- a/contrib/babelfishpg_tsql/runtime/functions.c +++ b/contrib/babelfishpg_tsql/runtime/functions.c @@ -103,13 +103,13 @@ PG_FUNCTION_INFO_V1(numeric_radians); PG_FUNCTION_INFO_V1(object_schema_name); PG_FUNCTION_INFO_V1(pg_extension_config_remove); -void* string_to_tsql_varchar(const char *input_str); -void* get_servername_internal(void); -void* get_servicename_internal(void); -void* get_language(void); +void *string_to_tsql_varchar(const char *input_str); +void *get_servername_internal(void); +void *get_servicename_internal(void); +void *get_language(void); extern bool canCommitTransaction(void); -extern int pltsql_datefirst; +extern int pltsql_datefirst; extern bool pltsql_implicit_transactions; extern bool pltsql_cursor_close_on_commit; extern bool pltsql_ansi_warnings; @@ -128,9 +128,9 @@ extern bool pltsql_case_insensitive_identifiers; extern bool inited_ht_tsql_cast_info; extern bool inited_ht_tsql_datatype_precedence_info; -char *bbf_servername = "BABELFISH"; +char *bbf_servername = "BABELFISH"; const char *bbf_servicename = "MSSQLSERVER"; -char *bbf_language = "us_english"; +char *bbf_language = "us_english"; #define MD5_HASH_LEN 32 Datum @@ -155,22 +155,23 @@ procid(PG_FUNCTION_ARGS) Datum version(PG_FUNCTION_ARGS) { - StringInfoData temp; - void *info; - const char *product_version; + StringInfoData temp; + void *info; + const char *product_version; + initStringInfo(&temp); if (pg_strcasecmp(pltsql_version, "default") == 0) { - char *pg_version = pstrdup(PG_VERSION_STR); - char *temp_str = pg_version; + char *pg_version = pstrdup(PG_VERSION_STR); + char *temp_str = pg_version; temp_str = strstr(temp_str, ", compiled by"); *temp_str = '\0'; product_version = GetConfigOption("babelfishpg_tds.product_version", true, false); - + Assert(product_version != NULL); - if(pg_strcasecmp(product_version,"default") == 0) + if (pg_strcasecmp(product_version, "default") == 0) product_version = BABEL_COMPATIBILITY_VERSION; appendStringInfo(&temp, "Babelfish for PostgreSQL with SQL Server Compatibility - %s" @@ -185,37 +186,41 @@ version(PG_FUNCTION_ARGS) * TODO: Return Build number with version string as well. */ - info = (*common_utility_plugin_ptr->tsql_varchar_input)(temp.data, temp.len, -1); + info = (*common_utility_plugin_ptr->tsql_varchar_input) (temp.data, temp.len, -1); pfree(temp.data); PG_RETURN_VARCHAR_P(info); } -void* string_to_tsql_varchar(const char *input_str) +void * +string_to_tsql_varchar(const char *input_str) { StringInfoData temp; - void* info; + void *info; initStringInfo(&temp); appendStringInfoString(&temp, input_str); - info = (*common_utility_plugin_ptr->tsql_varchar_input)(temp.data, temp.len, -1); + info = (*common_utility_plugin_ptr->tsql_varchar_input) (temp.data, temp.len, -1); pfree(temp.data); return info; } -void* get_servername_internal() +void * +get_servername_internal() { return string_to_tsql_varchar(bbf_servername); } -void* get_servicename_internal() +void * +get_servicename_internal() { return string_to_tsql_varchar(bbf_servicename); } -void* get_language() +void * +get_language() { - return string_to_tsql_varchar(bbf_language); + return string_to_tsql_varchar(bbf_language); } /* @@ -239,14 +244,15 @@ servicename(PG_FUNCTION_ARGS) Datum error(PG_FUNCTION_ARGS) { - PG_RETURN_INT32(latest_error_code); + PG_RETURN_INT32(latest_error_code); } Datum pgerror(PG_FUNCTION_ARGS) { - char *error_sqlstate = unpack_sql_state(latest_pg_error_code); - PG_RETURN_VARCHAR_P((*common_utility_plugin_ptr->tsql_varchar_input)((error_sqlstate), strlen(error_sqlstate), -1)); + char *error_sqlstate = unpack_sql_state(latest_pg_error_code); + + PG_RETURN_VARCHAR_P((*common_utility_plugin_ptr->tsql_varchar_input) ((error_sqlstate), strlen(error_sqlstate), -1)); } @@ -257,7 +263,7 @@ Datum datalength(PG_FUNCTION_ARGS) { Datum value = PG_GETARG_DATUM(0); - int32 result; + int32 result; int typlen; /* On first call, get the input type's typlen, and save at *fn_extra */ @@ -279,7 +285,7 @@ datalength(PG_FUNCTION_ARGS) if (typlen == -1) { - /* varlena type, untoasted and without header*/ + /* varlena type, untoasted and without header */ result = toast_raw_datum_size(value) - VARHDRSZ; } else if (typlen == -2) @@ -296,17 +302,18 @@ datalength(PG_FUNCTION_ARGS) PG_RETURN_INT32(result); } -/* +/* * The int_floor() and int_ceiling() functions are made to just return the * original argument because floor(int) and ceiling(int) are always equal to int * itself. This can only be done for int types and we are sure that these -* functions only have int arguments because these functions are ONLY invoked +* functions only have int arguments because these functions are ONLY invoked * from wrapper functions that accept bigint, int, smallint and tinyint arguments. */ Datum int_floor(PG_FUNCTION_ARGS) { int64 arg1 = PG_GETARG_INT64(0); + /* Floor of an integer is the integer itself */ PG_RETURN_INT64(arg1); } @@ -315,6 +322,7 @@ Datum int_ceiling(PG_FUNCTION_ARGS) { int64 arg1 = PG_GETARG_INT64(0); + /* Ceiling of an integer is the integer itself */ PG_RETURN_INT64(arg1); } @@ -322,12 +330,13 @@ int_ceiling(PG_FUNCTION_ARGS) /* * Floor/ceiling of bit type returns FLOATNTYPE in tsql. By default, we * return numeric for floor/ceiling of bit. This function is to return a double -* precision output for a bit input. +* precision output for a bit input. */ Datum bit_floor(PG_FUNCTION_ARGS) { int16 arg1 = PG_GETARG_INT16(0); + /* Floor of a bit is the bit itself */ PG_RETURN_FLOAT8((float8) arg1); } @@ -336,11 +345,13 @@ Datum bit_ceiling(PG_FUNCTION_ARGS) { int16 arg1 = PG_GETARG_INT16(0); + /* Ceiling of a bit is the bit itself */ PG_RETURN_FLOAT8((float8) arg1); } -Datum xact_state(PG_FUNCTION_ARGS) +Datum +xact_state(PG_FUNCTION_ARGS) { if (NestedTranCount == 0) { @@ -359,71 +370,71 @@ Datum xact_state(PG_FUNCTION_ARGS) Datum get_enr_list(PG_FUNCTION_ARGS) { - ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; - Tuplestorestate *tupstore; - MemoryContext per_query_ctx; - MemoryContext oldcontext; - List *enr_list = get_namedRelList(); - ListCell *lc; - - /* check to see if caller supports us returning a tuplestore */ - if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("set-valued function called in context that cannot accept a set"))); - if (!(rsinfo->allowedModes & SFRM_Materialize)) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("materialize mode required, but it is not " \ - "allowed in this context"))); - - /* need to build tuplestore in query context */ - per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; - oldcontext = MemoryContextSwitchTo(per_query_ctx); - - /* build tupdesc for result tuples. */ - tupdesc = CreateTemplateTupleDesc(2); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "reloid", - INT4OID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "relname", - TEXTOID, -1, 0); - - tupstore = - tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random, - false, 1024); - /* generate junk in short-term context */ - MemoryContextSwitchTo(oldcontext); - - /* scan all the variables in top estate */ + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + TupleDesc tupdesc; + Tuplestorestate *tupstore; + MemoryContext per_query_ctx; + MemoryContext oldcontext; + List *enr_list = get_namedRelList(); + ListCell *lc; + + /* check to see if caller supports us returning a tuplestore */ + if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("set-valued function called in context that cannot accept a set"))); + if (!(rsinfo->allowedModes & SFRM_Materialize)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("materialize mode required, but it is not " \ + "allowed in this context"))); + + /* need to build tuplestore in query context */ + per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; + oldcontext = MemoryContextSwitchTo(per_query_ctx); + + /* build tupdesc for result tuples. */ + tupdesc = CreateTemplateTupleDesc(2); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "reloid", + INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "relname", + TEXTOID, -1, 0); + + tupstore = + tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random, + false, 1024); + /* generate junk in short-term context */ + MemoryContextSwitchTo(oldcontext); + + /* scan all the variables in top estate */ foreach(lc, enr_list) - { - Datum values[2]; - bool nulls[2]; + { + Datum values[2]; + bool nulls[2]; - MemSet(nulls, 0, sizeof(nulls)); + MemSet(nulls, 0, sizeof(nulls)); - values[0] = ((EphemeralNamedRelationMetadata)lfirst(lc))->reliddesc; - values[1] = CStringGetTextDatum(((EphemeralNamedRelationMetadata)lfirst(lc))->name); + values[0] = ((EphemeralNamedRelationMetadata) lfirst(lc))->reliddesc; + values[1] = CStringGetTextDatum(((EphemeralNamedRelationMetadata) lfirst(lc))->name); - tuplestore_putvalues(tupstore, tupdesc, values, nulls); - } + tuplestore_putvalues(tupstore, tupdesc, values, nulls); + } - /* clean up and return the tuplestore */ - tuplestore_donestoring(tupstore); + /* clean up and return the tuplestore */ + tuplestore_donestoring(tupstore); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; + rsinfo->returnMode = SFRM_Materialize; + rsinfo->setResult = tupstore; + rsinfo->setDesc = tupdesc; - PG_RETURN_NULL(); + PG_RETURN_NULL(); } Datum tsql_random(PG_FUNCTION_ARGS) { LOCAL_FCINFO(fcinfo1, 0); - int seed = PG_GETARG_INT32(0); + int seed = PG_GETARG_INT32(0); Datum result; /* set the seed first */ @@ -440,7 +451,7 @@ Datum is_member(PG_FUNCTION_ARGS) { const char *role = text_to_cstring(PG_GETARG_TEXT_P(0)); - Oid role_oid = get_role_oid(role, true); + Oid role_oid = get_role_oid(role, true); if (!OidIsValid(role_oid)) { @@ -460,34 +471,35 @@ is_member(PG_FUNCTION_ARGS) Datum schema_name(PG_FUNCTION_ARGS) { - Oid oid = PG_GETARG_OID(0); - HeapTuple tup; + Oid oid = PG_GETARG_OID(0); + HeapTuple tup; Form_pg_namespace nspform; - NameData name; + NameData name; const char *logical_name; - VarChar *result; + VarChar *result; if (!OidIsValid(oid)) { PG_RETURN_NULL(); } - + tup = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(oid)); if (!HeapTupleIsValid(tup)) { PG_RETURN_NULL(); } - + nspform = (Form_pg_namespace) GETSTRUCT(tup); name = nspform->nspname; logical_name = get_logical_schema_name(name.data, true); if (logical_name) - result = (*common_utility_plugin_ptr->tsql_varchar_input)(logical_name, strlen(logical_name), -1); - else - result = (*common_utility_plugin_ptr->tsql_varchar_input)(name.data, strlen(name.data), -1); + result = (*common_utility_plugin_ptr->tsql_varchar_input) (logical_name, strlen(logical_name), -1); + + else + result = (*common_utility_plugin_ptr->tsql_varchar_input) (name.data, strlen(name.data), -1); ReleaseSysCache(tup); PG_RETURN_VARCHAR_P(result); @@ -496,37 +508,46 @@ schema_name(PG_FUNCTION_ARGS) Datum schema_id(PG_FUNCTION_ARGS) { - char *name; - char *input_name; - char *physical_name; - int id; + char *name; + char *input_name; + char *physical_name; + int id; /* when no argument is passed, then ID of default schema of the caller */ - if (PG_NARGS() == 0){ - char* db_name = get_cur_db_name(); + if (PG_NARGS() == 0) + { + char *db_name = get_cur_db_name(); const char *user = get_user_for_database(db_name); const char *guest_role_name = get_guest_role_name(db_name); - if (!user){ + if (!user) + { pfree(db_name); PG_RETURN_NULL(); } - else if ((guest_role_name && strcmp(user, guest_role_name) == 0)){ + else if ((guest_role_name && strcmp(user, guest_role_name) == 0)) + { physical_name = pstrdup(get_guest_schema_name(db_name)); } - else{ - name = get_authid_user_ext_schema_name((const char *) db_name, user); + else + { + name = get_authid_user_ext_schema_name((const char *) db_name, user); physical_name = get_physical_schema_name(db_name, name); } pfree(db_name); } - else{ + else + { if (PG_ARGISNULL(0)) PG_RETURN_NULL(); input_name = text_to_cstring(PG_GETARG_TEXT_P(0)); - if (pltsql_case_insensitive_identifiers){ - name = downcase_identifier(input_name, strlen(input_name), false, false); /* no truncation here. truncation will be handled inside get_physical_schema_name() */ + if (pltsql_case_insensitive_identifiers) + { + name = downcase_identifier(input_name, strlen(input_name), false, false); /* no truncation here. + * truncation will be + * handled inside + * get_physical_schema_name() */ pfree(input_name); } else @@ -536,7 +557,8 @@ schema_id(PG_FUNCTION_ARGS) } /* - * If physical schema name is empty or NULL for any reason then return NULL. + * If physical schema name is empty or NULL for any reason then return + * NULL. */ if (physical_name == NULL || strlen(physical_name) == 0) PG_RETURN_NULL(); @@ -545,8 +567,8 @@ schema_id(PG_FUNCTION_ARGS) pfree(name); pfree(physical_name); - - if(!OidIsValid(id)) + + if (!OidIsValid(id)) PG_RETURN_NULL(); PG_RETURN_INT32(id); @@ -562,80 +584,86 @@ datefirst(PG_FUNCTION_ARGS) Datum options(PG_FUNCTION_ARGS) { - int options = 0; + int options = 0; - /* 1st bit is for DISABLE_DEF_CNST_CHK, which is an obsolete setting and should always be 0 */ + /* + * 1st bit is for DISABLE_DEF_CNST_CHK, which is an obsolete setting and + * should always be 0 + */ - /* 2nd bit: IMPLICIT_TRANSACTIONS */ - if (pltsql_implicit_transactions) - options += 2; + /* 2nd bit: IMPLICIT_TRANSACTIONS */ + if (pltsql_implicit_transactions) + options += 2; - /* 3rd bit: CURSOR_CLOSE_ON_COMMIT */ - if (pltsql_cursor_close_on_commit) - options += 4; + /* 3rd bit: CURSOR_CLOSE_ON_COMMIT */ + if (pltsql_cursor_close_on_commit) + options += 4; - /* 4th bit: ANSI_WARNINGS */ - if (pltsql_ansi_warnings) - options += 8; + /* 4th bit: ANSI_WARNINGS */ + if (pltsql_ansi_warnings) + options += 8; - /* 5th bit: ANSI_PADDING, this setting is WIP. We only support the default ON setting atm */ - if (pltsql_ansi_padding) - options += 16; + /* + * 5th bit: ANSI_PADDING, this setting is WIP. We only support the default + * ON setting atm + */ + if (pltsql_ansi_padding) + options += 16; - /* 6th bit: ANSI_NULLS */ - if (pltsql_ansi_nulls) - options += 32; + /* 6th bit: ANSI_NULLS */ + if (pltsql_ansi_nulls) + options += 32; - /* 7th bit: ARITHABORT */ - if (pltsql_arithabort) - options += 64; + /* 7th bit: ARITHABORT */ + if (pltsql_arithabort) + options += 64; - /* 8th bit: ARITHIGNORE */ - if (pltsql_arithignore) - options += 128; + /* 8th bit: ARITHIGNORE */ + if (pltsql_arithignore) + options += 128; - /* 9th bit: QUOTED_IDENTIFIER */ - if (pltsql_quoted_identifier) - options += 256; + /* 9th bit: QUOTED_IDENTIFIER */ + if (pltsql_quoted_identifier) + options += 256; - /* 10th bit: NOCOUNT */ - if (pltsql_nocount) - options += 512; + /* 10th bit: NOCOUNT */ + if (pltsql_nocount) + options += 512; - /* 11th bit: ANSI_NULL_DFLT_ON */ - if (pltsql_ansi_null_dflt_on) - options += 1024; + /* 11th bit: ANSI_NULL_DFLT_ON */ + if (pltsql_ansi_null_dflt_on) + options += 1024; - /* 12th bit: ANSI_NULL_DFLT_OFF */ - if (pltsql_ansi_null_dflt_off) - options += 2048; + /* 12th bit: ANSI_NULL_DFLT_OFF */ + if (pltsql_ansi_null_dflt_off) + options += 2048; - /* 13th bit: CONCAT_NULL_YIELDS_NULL */ - if (pltsql_concat_null_yields_null) - options += 4096; + /* 13th bit: CONCAT_NULL_YIELDS_NULL */ + if (pltsql_concat_null_yields_null) + options += 4096; - /* 14th bit: NUMERIC_ROUNDABORT */ - if (pltsql_numeric_roundabort) - options += 8192; + /* 14th bit: NUMERIC_ROUNDABORT */ + if (pltsql_numeric_roundabort) + options += 8192; - /* 15th bit: XACT_ABORT */ - if (pltsql_xact_abort) - options += 16384; + /* 15th bit: XACT_ABORT */ + if (pltsql_xact_abort) + options += 16384; - PG_RETURN_UINT32(options); + PG_RETURN_UINT32(options); } /* This function will return the default AD domain name */ Datum default_domain(PG_FUNCTION_ARGS) { - char* login_domainname = NULL; + char *login_domainname = NULL; if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->get_login_domainname) login_domainname = (*pltsql_protocol_plugin_ptr)->get_login_domainname(); if (login_domainname) - PG_RETURN_VARCHAR_P((*common_utility_plugin_ptr->tsql_varchar_input)(login_domainname, strlen(login_domainname), -1)); + PG_RETURN_VARCHAR_P((*common_utility_plugin_ptr->tsql_varchar_input) (login_domainname, strlen(login_domainname), -1)); else PG_RETURN_NULL(); } @@ -647,11 +675,12 @@ Datum tsql_exp(PG_FUNCTION_ARGS) { float8 arg1 = PG_GETARG_FLOAT8(0); - float8 result; + float8 result; errno = 0; result = exp(arg1); - if (errno == ERANGE && result != 0 && !isinf(result)) + + if (errno == ERANGE && result !=0 && !isinf(result)) result = get_float8_infinity(); if (unlikely(isinf(result)) && !isinf(arg1)) @@ -662,8 +691,10 @@ tsql_exp(PG_FUNCTION_ARGS) Datum host_os(PG_FUNCTION_ARGS) { - char *host_os_res, *pg_version, host_str[256]; - void *info; + char *host_os_res, + *pg_version, + host_str[256]; + void *info; /* filter out host info */ pg_version = pstrdup(PG_VERSION_STR); @@ -684,7 +715,7 @@ host_os(PG_FUNCTION_ARGS) else host_os_res = pstrdup("UNKNOWN"); - info = (*common_utility_plugin_ptr->tsql_varchar_input)(host_os_res, strlen(host_os_res), -1); + info = (*common_utility_plugin_ptr->tsql_varchar_input) (host_os_res, strlen(host_os_res), -1); if (pg_version) pfree(pg_version); if (host_os_res) @@ -700,7 +731,7 @@ tsql_stat_get_activity_deprecated_in_2_2_0(PG_FUNCTION_ARGS) { int num_backends = pgstat_fetch_stat_numbackends(); int curr_backend; - char* view_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); + char *view_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); int pid = -1; ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; TupleDesc tupdesc; @@ -708,13 +739,13 @@ tsql_stat_get_activity_deprecated_in_2_2_0(PG_FUNCTION_ARGS) MemoryContext per_query_ctx; MemoryContext oldcontext; - /* For sys.dm_exec_sessions view: - * - If user is sysadmin, we show info of all the sessions - * - If user is not sysadmin, we only show info of current session - * For sys.dm_exec_connections view: - * - If user is sysadmin, we show info of all the connections - * - If user is not sysadmin, we throw an error since user does not - * have the required permissions to query this view + /* + * For sys.dm_exec_sessions view: - If user is sysadmin, we show info of + * all the sessions - If user is not sysadmin, we only show info of + * current session For sys.dm_exec_connections view: - If user is + * sysadmin, we show info of all the connections - If user is not + * sysadmin, we throw an error since user does not have the required + * permissions to query this view */ if (strcmp(view_name, "sessions") == 0) { @@ -729,8 +760,8 @@ tsql_stat_get_activity_deprecated_in_2_2_0(PG_FUNCTION_ARGS) pid = -1; else ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("The user does not have permission to perform this action"))); + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("The user does not have permission to perform this action"))); } /* check to see if caller supports us returning a tuplestore */ @@ -791,8 +822,9 @@ tsql_stat_get_activity_deprecated_in_2_2_0(PG_FUNCTION_ARGS) if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->get_stat_values && (*pltsql_protocol_plugin_ptr)->get_stat_values(values, nulls, TSQL_STAT_GET_ACTIVITY_COLS - 2, pid, curr_backend)) - tuplestore_putvalues(tupstore, tupdesc, values, nulls); - else continue; + tuplestore_putvalues(tupstore, tupdesc, values, nulls); + else + continue; /* If only a single backend was requested, and we found it, break. */ if (pid != -1) @@ -803,7 +835,7 @@ tsql_stat_get_activity_deprecated_in_2_2_0(PG_FUNCTION_ARGS) tuplestore_donestoring(tupstore); if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->invalidate_stat_view) - (*pltsql_protocol_plugin_ptr)->invalidate_stat_view(); + (*pltsql_protocol_plugin_ptr)->invalidate_stat_view(); return (Datum) 0; } @@ -814,7 +846,7 @@ tsql_stat_get_activity_deprecated_in_3_2_0(PG_FUNCTION_ARGS) Oid sysadmin_oid = get_role_oid("sysadmin", false); int num_backends = pgstat_fetch_stat_numbackends(); int curr_backend; - char* view_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); + char *view_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); int pid = -1; ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; TupleDesc tupdesc; @@ -822,13 +854,13 @@ tsql_stat_get_activity_deprecated_in_3_2_0(PG_FUNCTION_ARGS) MemoryContext per_query_ctx; MemoryContext oldcontext; - /* For sys.dm_exec_sessions view: - * - If user is sysadmin, we show info of all the sessions - * - If user is not sysadmin, we only show info of current session - * For sys.dm_exec_connections view: - * - If user is sysadmin, we show info of all the connections - * - If user is not sysadmin, we throw an error since user does not - * have the required permissions to query this view + /* + * For sys.dm_exec_sessions view: - If user is sysadmin, we show info of + * all the sessions - If user is not sysadmin, we only show info of + * current session For sys.dm_exec_connections view: - If user is + * sysadmin, we show info of all the connections - If user is not + * sysadmin, we throw an error since user does not have the required + * permissions to query this view */ if (strcmp(view_name, "sessions") == 0) { @@ -843,8 +875,8 @@ tsql_stat_get_activity_deprecated_in_3_2_0(PG_FUNCTION_ARGS) pid = -1; else ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("The user does not have permission to perform this action"))); + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("The user does not have permission to perform this action"))); } /* check to see if caller supports us returning a tuplestore */ @@ -906,8 +938,9 @@ tsql_stat_get_activity_deprecated_in_3_2_0(PG_FUNCTION_ARGS) if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->get_stat_values && (*pltsql_protocol_plugin_ptr)->get_stat_values(values, nulls, TSQL_STAT_GET_ACTIVITY_COLS - 1, pid, curr_backend)) - tuplestore_putvalues(tupstore, tupdesc, values, nulls); - else continue; + tuplestore_putvalues(tupstore, tupdesc, values, nulls); + else + continue; /* If only a single backend was requested, and we found it, break. */ if (pid != -1) @@ -918,7 +951,7 @@ tsql_stat_get_activity_deprecated_in_3_2_0(PG_FUNCTION_ARGS) tuplestore_donestoring(tupstore); if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->invalidate_stat_view) - (*pltsql_protocol_plugin_ptr)->invalidate_stat_view(); + (*pltsql_protocol_plugin_ptr)->invalidate_stat_view(); return (Datum) 0; } @@ -929,7 +962,7 @@ tsql_stat_get_activity(PG_FUNCTION_ARGS) Oid sysadmin_oid = get_role_oid("sysadmin", false); int num_backends = pgstat_fetch_stat_numbackends(); int curr_backend; - char* view_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); + char *view_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); int pid = -1; ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; TupleDesc tupdesc; @@ -937,13 +970,13 @@ tsql_stat_get_activity(PG_FUNCTION_ARGS) MemoryContext per_query_ctx; MemoryContext oldcontext; - /* For sys.dm_exec_sessions view: - * - If user is sysadmin, we show info of all the sessions - * - If user is not sysadmin, we only show info of current session - * For sys.dm_exec_connections view: - * - If user is sysadmin, we show info of all the connections - * - If user is not sysadmin, we throw an error since user does not - * have the required permissions to query this view + /* + * For sys.dm_exec_sessions view: - If user is sysadmin, we show info of + * all the sessions - If user is not sysadmin, we only show info of + * current session For sys.dm_exec_connections view: - If user is + * sysadmin, we show info of all the connections - If user is not + * sysadmin, we throw an error since user does not have the required + * permissions to query this view */ if (strcmp(view_name, "sessions") == 0) { @@ -958,8 +991,8 @@ tsql_stat_get_activity(PG_FUNCTION_ARGS) pid = -1; else ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("The user does not have permission to perform this action"))); + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("The user does not have permission to perform this action"))); } /* check to see if caller supports us returning a tuplestore */ @@ -1022,8 +1055,9 @@ tsql_stat_get_activity(PG_FUNCTION_ARGS) if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->get_stat_values && (*pltsql_protocol_plugin_ptr)->get_stat_values(values, nulls, TSQL_STAT_GET_ACTIVITY_COLS, pid, curr_backend)) - tuplestore_putvalues(tupstore, tupdesc, values, nulls); - else continue; + tuplestore_putvalues(tupstore, tupdesc, values, nulls); + else + continue; /* If only a single backend was requested, and we found it, break. */ if (pid != -1) @@ -1034,7 +1068,7 @@ tsql_stat_get_activity(PG_FUNCTION_ARGS) tuplestore_donestoring(tupstore); if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->invalidate_stat_view) - (*pltsql_protocol_plugin_ptr)->invalidate_stat_view(); + (*pltsql_protocol_plugin_ptr)->invalidate_stat_view(); return (Datum) 0; } @@ -1050,52 +1084,53 @@ get_current_full_xact_id(PG_FUNCTION_ARGS) Datum checksum(PG_FUNCTION_ARGS) { - int32 result = 0; - int nargs = PG_NARGS(); - StringInfoData buf; - char md5[MD5_HASH_LEN + 1]; - char *name; - const char *errstr = NULL; - bool success; - - initStringInfo(&buf); - if (nargs > 0) - { - ArrayType *arr; - Datum *values; - bool *nulls; - int nelems; - int i; - arr = PG_GETARG_ARRAYTYPE_P(0); - deconstruct_array(arr, TEXTOID, -1, false, TYPALIGN_INT, &values, &nulls, &nelems); - for (i=0; i 0) + { + ArrayType *arr; + Datum *values; + bool *nulls; + int nelems; + int i; + + arr = PG_GETARG_ARRAYTYPE_P(0); + deconstruct_array(arr, TEXTOID, -1, false, TYPALIGN_INT, &values, &nulls, &nelems); + for (i = 0; i < nelems; i++) + { + name = nulls[i] ? "" : TextDatumGetCString(values[i]); + if (strlen(name) == 0 && nelems == 1) + PG_RETURN_INT32(0); + else + appendStringInfoString(&buf, name); + } + } + + /* + * We get hash value for md5 which is in hexadecimal. We are taking the + * first 8 characters of the md5 hash and converting it to int32. + */ + success = pg_md5_hash(buf.data, buf.len, md5, &errstr); + if (success) + { + md5[8] = '\0'; + result = (int) strtol(md5, NULL, 16); + } + else + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("could not compute %s hash: %s", "MD5", errstr))); + + pfree(buf.data); + + PG_RETURN_INT32(result); } /* @@ -1109,25 +1144,28 @@ checksum(PG_FUNCTION_ARGS) */ Datum object_id(PG_FUNCTION_ARGS) -{ - char *db_name, *schema_name, *object_name; - char *physical_schema_name; - char *input; - char *object_type = NULL; - char **splited_object_name; +{ + char *db_name, + *schema_name, + *object_name; + char *physical_schema_name; + char *input; + char *object_type = NULL; + char **splited_object_name; Oid schema_oid; Oid user_id = GetUserId(); - Oid result = InvalidOid; - bool is_temp_object; + Oid result = InvalidOid; + bool is_temp_object; int i; - if(PG_ARGISNULL(0)) + if (PG_ARGISNULL(0)) PG_RETURN_NULL(); input = text_to_cstring(PG_GETARG_TEXT_P(0)); - if(!PG_ARGISNULL(1)) + if (!PG_ARGISNULL(1)) { - char *str = text_to_cstring(PG_GETARG_TEXT_P(1)); + char *str = text_to_cstring(PG_GETARG_TEXT_P(1)); + i = strlen(str); if (i > 2) { @@ -1146,12 +1184,12 @@ object_id(PG_FUNCTION_ARGS) i = strlen(input); while (i > 0 && isspace((unsigned char) input[i - 1])) input[--i] = '\0'; - + /* length should be restricted to 4000 */ if (i > 4000) ereport(ERROR, - (errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH), - errmsg("input value is too long for object name"))); + (errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH), + errmsg("input value is too long for object name"))); /* resolve the three part name */ splited_object_name = split_object_name(input); @@ -1161,7 +1199,7 @@ object_id(PG_FUNCTION_ARGS) /* downcase identifier if needed */ if (pltsql_case_insensitive_identifiers) - { + { db_name = downcase_identifier(db_name, strlen(db_name), false, false); schema_name = downcase_identifier(schema_name, strlen(schema_name), false, false); object_name = downcase_identifier(object_name, strlen(object_name), false, false); @@ -1184,7 +1222,8 @@ object_id(PG_FUNCTION_ARGS) else if (strcmp(db_name, get_cur_db_name()) && strcmp(db_name, "tempdb")) { /* cross database lookup */ - int db_id = get_db_id(db_name); + int db_id = get_db_id(db_name); + if (!DbidIsValid(db_id)) { pfree(db_name); @@ -1199,16 +1238,20 @@ object_id(PG_FUNCTION_ARGS) /* get physical schema name from logical schema name */ if (!strcmp(schema_name, "")) - { - /* find the default schema for current user and get physical schema name */ + { + /* + * find the default schema for current user and get physical schema + * name + */ const char *user = get_user_for_database(db_name); const char *guest_role_name = get_guest_role_name(db_name); + if (!user) - { + { pfree(db_name); pfree(schema_name); pfree(object_name); - if(object_type) + if (object_type) pfree(object_type); PG_RETURN_NULL(); } @@ -1219,7 +1262,7 @@ object_id(PG_FUNCTION_ARGS) else { pfree(schema_name); - schema_name = get_authid_user_ext_schema_name((const char *) db_name, user); + schema_name = get_authid_user_ext_schema_name((const char *) db_name, user); physical_schema_name = get_physical_schema_name(db_name, schema_name); } } @@ -1228,7 +1271,10 @@ object_id(PG_FUNCTION_ARGS) physical_schema_name = get_physical_schema_name(db_name, schema_name); } - /* get schema oid from physical schema name, it will return InvalidOid if user don't have lookup access */ + /* + * get schema oid from physical schema name, it will return InvalidOid if + * user don't have lookup access + */ schema_oid = get_namespace_oid(physical_schema_name, true); /* free unnecessary pointers */ @@ -1236,37 +1282,41 @@ object_id(PG_FUNCTION_ARGS) pfree(schema_name); pfree(physical_schema_name); - if(!OidIsValid(schema_oid) || pg_namespace_aclcheck(schema_oid, user_id, ACL_USAGE) != ACLCHECK_OK) + if (!OidIsValid(schema_oid) || pg_namespace_aclcheck(schema_oid, user_id, ACL_USAGE) != ACLCHECK_OK) { pfree(object_name); if (object_type) pfree(object_type); PG_RETURN_NULL(); } - + /* check if looking for temp object */ - is_temp_object = (object_name[0] == '#'? true: false); + is_temp_object = (object_name[0] == '#' ? true : false); - if (object_type) /* "object_type" is specified in-argument */ - { + if (object_type) /* "object_type" is specified in-argument */ + { if (is_temp_object) { if (!strcmp(object_type, "s") || !strcmp(object_type, "u") || !strcmp(object_type, "v") || !strcmp(object_type, "it") || !strcmp(object_type, "et") || !strcmp(object_type, "so")) { - /* search in list of ENRs registered in the current query environment by name */ + /* + * search in list of ENRs registered in the current query + * environment by name + */ EphemeralNamedRelation enr = get_ENR(currentQueryEnv, object_name); + if (enr != NULL && enr->md.enrtype == ENR_TSQL_TEMP) { result = enr->md.reliddesc; } } else if (!strcmp(object_type, "r") || !strcmp(object_type, "ec") || !strcmp(object_type, "pg") || - !strcmp(object_type, "sn") || !strcmp(object_type, "sq") || !strcmp(object_type, "tt")) + !strcmp(object_type, "sn") || !strcmp(object_type, "sq") || !strcmp(object_type, "tt")) { ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Object type currently unsupported in Babelfish."))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Object type currently unsupported in Babelfish."))); } } else @@ -1275,22 +1325,23 @@ object_id(PG_FUNCTION_ARGS) !strcmp(object_type, "it") || !strcmp(object_type, "et") || !strcmp(object_type, "so")) { /* search in pg_class by name and schema oid */ - Oid relid = get_relname_relid((const char *) object_name, schema_oid); + Oid relid = get_relname_relid((const char *) object_name, schema_oid); + if (OidIsValid(relid) && pg_class_aclcheck(relid, user_id, ACL_SELECT) == ACLCHECK_OK) { result = relid; - } + } } else if (!strcmp(object_type, "c") || !strcmp(object_type, "d") || !strcmp(object_type, "f") || - !strcmp(object_type, "pk") || !strcmp(object_type, "uq")) + !strcmp(object_type, "pk") || !strcmp(object_type, "uq")) { /* search in pg_constraint by name and schema oid */ result = tsql_get_constraint_oid(object_name, schema_oid, user_id); } else if (!strcmp(object_type, "af") || !strcmp(object_type, "fn") || !strcmp(object_type, "fs") || - !strcmp(object_type, "ft") || !strcmp(object_type, "if") || !strcmp(object_type, "p") || - !strcmp(object_type, "pc") || !strcmp(object_type, "tf") || !strcmp(object_type, "rf") || - !strcmp(object_type, "x")) + !strcmp(object_type, "ft") || !strcmp(object_type, "if") || !strcmp(object_type, "p") || + !strcmp(object_type, "pc") || !strcmp(object_type, "tf") || !strcmp(object_type, "rf") || + !strcmp(object_type, "x")) { /* search in pg_proc by name and schema oid */ result = tsql_get_proc_oid(object_name, schema_oid, user_id); @@ -1301,21 +1352,26 @@ object_id(PG_FUNCTION_ARGS) result = tsql_get_trigger_oid(object_name, schema_oid, user_id); } else if (!strcmp(object_type, "r") || !strcmp(object_type, "ec") || !strcmp(object_type, "pg") || - !strcmp(object_type, "sn") || !strcmp(object_type, "sq") || !strcmp(object_type, "tt")) + !strcmp(object_type, "sn") || !strcmp(object_type, "sq") || !strcmp(object_type, "tt")) { ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Object type currently unsupported in Babelfish."))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Object type currently unsupported in Babelfish."))); } } - + } else - { - if (is_temp_object) /* temp object without "object_type" in-argument */ + { + if (is_temp_object) /* temp object without "object_type" + * in-argument */ { - /* search in list of ENRs registered in the current query environment by name */ + /* + * search in list of ENRs registered in the current query + * environment by name + */ EphemeralNamedRelation enr = get_ENR(currentQueryEnv, object_name); + if (enr != NULL && enr->md.enrtype == ENR_TSQL_TEMP) { result = enr->md.reliddesc; @@ -1324,13 +1380,14 @@ object_id(PG_FUNCTION_ARGS) else { /* search in pg_class by name and schema oid */ - Oid relid = get_relname_relid((const char *) object_name, schema_oid); + Oid relid = get_relname_relid((const char *) object_name, schema_oid); + if (OidIsValid(relid) && pg_class_aclcheck(relid, user_id, ACL_SELECT) == ACLCHECK_OK) { result = relid; } - - if (!OidIsValid(result)) /* search only if not found earlier */ + + if (!OidIsValid(result)) /* search only if not found earlier */ { /* search in pg_trigger by name and schema oid */ result = tsql_get_trigger_oid(object_name, schema_oid, user_id); @@ -1344,7 +1401,7 @@ object_id(PG_FUNCTION_ARGS) if (!OidIsValid(result)) { - /* search in pg_constraint by name and schema oid */ + /* search in pg_constraint by name and schema oid */ result = tsql_get_constraint_oid(object_name, schema_oid, user_id); } } @@ -1369,45 +1426,51 @@ object_id(PG_FUNCTION_ARGS) Datum object_name(PG_FUNCTION_ARGS) { - int32 input1 = PG_GETARG_INT32(0); - Oid object_id; - Oid database_id; - Oid user_id = GetUserId(); - Oid schema_id = InvalidOid; - HeapTuple tuple; - Relation tgrel; - ScanKeyData key; - SysScanDesc tgscan; - EphemeralNamedRelation enr; - bool found = false; - char *result = NULL; - - if(input1 < 0) + int32 input1 = PG_GETARG_INT32(0); + Oid object_id; + Oid database_id; + Oid user_id = GetUserId(); + Oid schema_id = InvalidOid; + HeapTuple tuple; + Relation tgrel; + ScanKeyData key; + SysScanDesc tgscan; + EphemeralNamedRelation enr; + bool found = false; + char *result = NULL; + + if (input1 < 0) PG_RETURN_NULL(); object_id = (Oid) input1; - if (!PG_ARGISNULL(1)) /* if database id is provided */ + if (!PG_ARGISNULL(1)) /* if database id is provided */ { - int32 input2 = PG_GETARG_INT32(1); - if(input2 < 0) + int32 input2 = PG_GETARG_INT32(1); + + if (input2 < 0) PG_RETURN_NULL(); database_id = (Oid) input2; if (database_id != get_cur_db_id()) /* cross-db lookup */ - { - char *db_name = get_db_name(database_id); - if (db_name == NULL) /* database doesn't exist with given oid */ + { + char *db_name = get_db_name(database_id); + + if (db_name == NULL) /* database doesn't exist with given oid */ PG_RETURN_NULL(); user_id = GetSessionUserId(); pfree(db_name); } } - else /* by default lookup in current database */ + else /* by default lookup in current database */ database_id = get_cur_db_id(); - /* search in list of ENRs registered in the current query environment by object_id */ + /* + * search in list of ENRs registered in the current query environment by + * object_id + */ enr = get_ENR_withoid(currentQueryEnv, object_id); - if(enr != NULL && enr->md.enrtype == ENR_TSQL_TEMP) + if (enr != NULL && enr->md.enrtype == ENR_TSQL_TEMP) { result = enr->md.name; + PG_RETURN_VARCHAR_P((VarChar *) cstring_to_text(result)); } @@ -1417,9 +1480,10 @@ object_name(PG_FUNCTION_ARGS) { /* check if user have right permission on object */ if (pg_class_aclcheck(object_id, user_id, ACL_SELECT) == ACLCHECK_OK) - { + { Form_pg_class pg_class = (Form_pg_class) GETSTRUCT(tuple); result = NameStr(pg_class->relname); + schema_id = pg_class->relnamespace; } ReleaseSysCache(tuple); @@ -1437,6 +1501,7 @@ object_name(PG_FUNCTION_ARGS) { Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(tuple); result = NameStr(procform->proname); + schema_id = procform->pronamespace; } ReleaseSysCache(tuple); @@ -1452,7 +1517,7 @@ object_name(PG_FUNCTION_ARGS) { /* check if user have right permission on object */ if (pg_type_aclcheck(object_id, user_id, ACL_USAGE) == ACLCHECK_OK) - { + { Form_pg_type pg_type = (Form_pg_type) GETSTRUCT(tuple); result = NameStr(pg_type->typname); } @@ -1460,28 +1525,30 @@ object_name(PG_FUNCTION_ARGS) found = true; } } - - if(!found) + + if (!found) { /* search in pg_trigger by object_id */ tgrel = table_open(TriggerRelationId, AccessShareLock); ScanKeyInit(&key, - Anum_pg_trigger_oid, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(object_id)); + Anum_pg_trigger_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object_id)); tgscan = systable_beginscan(tgrel, TriggerOidIndexId, true, - NULL, 1, &key); + NULL, 1, &key); tuple = systable_getnext(tgscan); if (HeapTupleIsValid(tuple)) { Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple); + /* check if user have right permission on object */ - if(OidIsValid(pg_trigger->tgrelid) && + if (OidIsValid(pg_trigger->tgrelid) && pg_class_aclcheck(pg_trigger->tgrelid, user_id, ACL_SELECT) == ACLCHECK_OK) { result = NameStr(pg_trigger->tgname); + schema_id = get_rel_namespace(pg_trigger->tgrelid); } found = true; @@ -1490,17 +1557,19 @@ object_name(PG_FUNCTION_ARGS) table_close(tgrel, AccessShareLock); } - if(!found) + if (!found) { /* search in pg_constraint by object_id */ tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(object_id)); if (HeapTupleIsValid(tuple)) - { + { Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple); + /* check if user have right permission on object */ if (OidIsValid(con->conrelid) && (pg_class_aclcheck(con->conrelid, user_id, ACL_SELECT) == ACLCHECK_OK)) - { + { result = NameStr(con->conname); + schema_id = con->connamespace; } ReleaseSysCache(tuple); @@ -1508,15 +1577,16 @@ object_name(PG_FUNCTION_ARGS) } } - if(result) - { - /* - * Check if schema corresponding to found object belongs to specified database, - * schema also can be shared schema like "sys" or "information_schema_tsql". - * In case of pg_type schema_id will be invalid. + if (result) + { + /* + * Check if schema corresponding to found object belongs to specified + * database, schema also can be shared schema like "sys" or + * "information_schema_tsql". In case of pg_type schema_id will be + * invalid. */ - if(!OidIsValid(schema_id) || is_schema_from_db(schema_id, database_id) - || (schema_id == get_namespace_oid("sys", true)) || (schema_id == get_namespace_oid("information_schema_tsql", true))) + if (!OidIsValid(schema_id) || is_schema_from_db(schema_id, database_id) + || (schema_id == get_namespace_oid("sys", true)) || (schema_id == get_namespace_oid("information_schema_tsql", true))) PG_RETURN_VARCHAR_P((VarChar *) cstring_to_text(result)); } PG_RETURN_NULL(); @@ -1526,10 +1596,15 @@ Datum has_dbaccess(PG_FUNCTION_ARGS) { char *db_name = text_to_cstring(PG_GETARG_TEXT_P(0)); - /* Ensure the database name input argument is lower-case, as all Babel table names are lower-case */ + + /* + * Ensure the database name input argument is lower-case, as all Babel + * table names are lower-case + */ char *lowercase_db_name = lowerstr(db_name); + /* Also strip trailing whitespace to mimic SQL Server behaviour */ - int i; + int i; const char *user = NULL; const char *login; int16 db_id; @@ -1546,20 +1621,23 @@ has_dbaccess(PG_FUNCTION_ARGS) login = GetUserNameFromId(GetSessionUserId(), false); user = get_authid_user_ext_physical_name(lowercase_db_name, login); - /* Special cases: - Database Owner should always have access - If this DB has guest roles, the guests should always have access - */ + /* + * Special cases: Database Owner should always have access If this DB has + * guest roles, the guests should always have access + */ if (!user) { - Oid datdba; + Oid datdba; datdba = get_role_oid("sysadmin", false); if (is_member_of_role(GetSessionUserId(), datdba)) user = get_dbo_role_name(lowercase_db_name); else { - /* Get the guest role name only if the guest is enabled on the current db.*/ + /* + * Get the guest role name only if the guest is enabled on the + * current db. + */ if (guest_has_dbaccess(lowercase_db_name)) user = get_guest_role_name(lowercase_db_name); else @@ -1585,10 +1663,10 @@ sp_datatype_info_helper(PG_FUNCTION_ARGS) Tuplestorestate *tupstore; MemoryContext per_query_ctx; MemoryContext oldcontext; - int i; - Oid nspoid = get_namespace_oid("sys", false); - Oid sys_varcharoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, CStringGetDatum("varchar"), ObjectIdGetDatum(nspoid)); - Oid colloid = tsql_get_server_collation_oid_internal(false); + int i; + Oid nspoid = get_namespace_oid("sys", false); + Oid sys_varcharoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, CStringGetDatum("varchar"), ObjectIdGetDatum(nspoid)); + Oid colloid = tsql_get_server_collation_oid_internal(false); /* check to see if caller supports us returning a tuplestore */ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) @@ -1771,7 +1849,7 @@ host_name(PG_FUNCTION_ARGS) Datum context_info(PG_FUNCTION_ARGS) { - Datum context_info = (Datum) 0; + Datum context_info = (Datum) 0; if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->get_context_info) context_info = (*pltsql_protocol_plugin_ptr)->get_context_info(); @@ -1818,57 +1896,60 @@ babelfish_integrity_checker(PG_FUNCTION_ARGS) Datum bigint_degrees(PG_FUNCTION_ARGS) { - int64 arg1 = PG_GETARG_INT64(0); - float8 result; - + int64 arg1 = PG_GETARG_INT64(0); + float8 result; + result = DatumGetFloat8(DirectFunctionCall1(degrees, Float8GetDatum((float8) arg1))); - if (result < 0) + if (result <0) result = ceil(result); + else result = floor(result); - /* Range check */ + /* Range check */ if (unlikely(isnan(result) || !FLOAT8_FITS_IN_INT64(result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("Arithmetic overflow error converting expression to data type bigint"))); + errmsg("Arithmetic overflow error converting expression to data type bigint"))); - PG_RETURN_INT64((int64)result); + PG_RETURN_INT64((int64) result); } Datum int_degrees(PG_FUNCTION_ARGS) { - int32 arg1 = PG_GETARG_INT32(0); - float8 result; - + int32 arg1 = PG_GETARG_INT32(0); + float8 result; + result = DatumGetFloat8(DirectFunctionCall1(degrees, Float8GetDatum((float8) arg1))); - if (result < 0) + if (result <0) result = ceil(result); + else result = floor(result); - /* Range check */ + /* Range check */ if (unlikely(isnan(result) || !FLOAT8_FITS_IN_INT32(result))) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("Arithmetic overflow error converting expression to data type int"))); + errmsg("Arithmetic overflow error converting expression to data type int"))); - PG_RETURN_INT32((int32)result); + PG_RETURN_INT32((int32) result); } Datum smallint_degrees(PG_FUNCTION_ARGS) { - int16 arg1 = PG_GETARG_INT16(0); - float8 result; + int16 arg1 = PG_GETARG_INT16(0); + float8 result; result = DatumGetFloat8(DirectFunctionCall1(degrees, Float8GetDatum((float8) arg1))); - if (result < 0) + if (result <0) result = ceil(result); + else result = floor(result); @@ -1880,110 +1961,115 @@ smallint_degrees(PG_FUNCTION_ARGS) Datum bigint_radians(PG_FUNCTION_ARGS) { - int64 arg1 = PG_GETARG_INT64(0); - float8 result; + int64 arg1 = PG_GETARG_INT64(0); + float8 result; result = DatumGetFloat8(DirectFunctionCall1(radians, Float8GetDatum((float8) arg1))); /* skip range check, since it cannot overflow int64 */ - PG_RETURN_INT64((int64)result); + PG_RETURN_INT64((int64) result); } Datum int_radians(PG_FUNCTION_ARGS) { - int32 arg1 = PG_GETARG_INT32(0); - float8 result; + int32 arg1 = PG_GETARG_INT32(0); + float8 result; result = DatumGetFloat8(DirectFunctionCall1(radians, Float8GetDatum((float8) arg1))); /* skip range check, since it cannot overflow int32 */ - PG_RETURN_INT32((int32)result); + PG_RETURN_INT32((int32) result); } Datum smallint_radians(PG_FUNCTION_ARGS) { - int16 arg1 = PG_GETARG_INT16(0); - float8 result; + int16 arg1 = PG_GETARG_INT16(0); + float8 result; result = DatumGetFloat8(DirectFunctionCall1(radians, Float8GetDatum((float8) arg1))); /* skip range check, since it cannot overflow int32 */ - PG_RETURN_INT32((int32)result); + PG_RETURN_INT32((int32) result); } Datum bigint_power(PG_FUNCTION_ARGS) { - int64 arg1 = PG_GETARG_INT64(0); - Numeric arg2 = PG_GETARG_NUMERIC(1); - int64 result; - Numeric arg1_numeric, result_numeric; + int64 arg1 = PG_GETARG_INT64(0); + Numeric arg2 = PG_GETARG_NUMERIC(1); + int64 result; + Numeric arg1_numeric, + result_numeric; - arg1_numeric = DatumGetNumeric(DirectFunctionCall1(int8_numeric,arg1)); + arg1_numeric = DatumGetNumeric(DirectFunctionCall1(int8_numeric, arg1)); result_numeric = DatumGetNumeric(DirectFunctionCall2(numeric_power, NumericGetDatum(arg1_numeric), NumericGetDatum(arg2))); result = DatumGetInt64(DirectFunctionCall1(numeric_int8, NumericGetDatum(result_numeric))); - PG_RETURN_INT64(result); + PG_RETURN_INT64(result); } Datum int_power(PG_FUNCTION_ARGS) { - int32 arg1 = PG_GETARG_INT32(0); - Numeric arg2 = PG_GETARG_NUMERIC(1); - int32 result; - Numeric arg1_numeric, result_numeric; + int32 arg1 = PG_GETARG_INT32(0); + Numeric arg2 = PG_GETARG_NUMERIC(1); + int32 result; + Numeric arg1_numeric, + result_numeric; - arg1_numeric = DatumGetNumeric(DirectFunctionCall1(int4_numeric,arg1)); + arg1_numeric = DatumGetNumeric(DirectFunctionCall1(int4_numeric, arg1)); result_numeric = DatumGetNumeric(DirectFunctionCall2(numeric_power, NumericGetDatum(arg1_numeric), NumericGetDatum(arg2))); result = DatumGetInt32(DirectFunctionCall1(numeric_int4, NumericGetDatum(result_numeric))); - PG_RETURN_INT32(result); + PG_RETURN_INT32(result); } Datum smallint_power(PG_FUNCTION_ARGS) { - int16 arg1 = PG_GETARG_INT16(0); - Numeric arg2 = PG_GETARG_NUMERIC(1); - int32 result; - Numeric arg1_numeric, result_numeric; + int16 arg1 = PG_GETARG_INT16(0); + Numeric arg2 = PG_GETARG_NUMERIC(1); + int32 result; + Numeric arg1_numeric, + result_numeric; - arg1_numeric = DatumGetNumeric(DirectFunctionCall1(int2_numeric,arg1)); - result_numeric = DatumGetNumeric(DirectFunctionCall2(numeric_power, NumericGetDatum(arg1_numeric), Int16GetDatum (arg2))); + arg1_numeric = DatumGetNumeric(DirectFunctionCall1(int2_numeric, arg1)); + result_numeric = DatumGetNumeric(DirectFunctionCall2(numeric_power, NumericGetDatum(arg1_numeric), Int16GetDatum(arg2))); result = DatumGetInt32(DirectFunctionCall1(numeric_int2, NumericGetDatum(result_numeric))); - PG_RETURN_INT32(result); + PG_RETURN_INT32(result); } Datum numeric_degrees(PG_FUNCTION_ARGS) { - Numeric arg1 = PG_GETARG_NUMERIC(0); - Numeric radians_per_degree,result; + Numeric arg1 = PG_GETARG_NUMERIC(0); + Numeric radians_per_degree, + result; + + radians_per_degree = DatumGetNumeric(DirectFunctionCall1(float8_numeric, Float8GetDatum(RADIANS_PER_DEGREE))); - radians_per_degree = DatumGetNumeric(DirectFunctionCall1(float8_numeric,Float8GetDatum(RADIANS_PER_DEGREE))); - result = DatumGetNumeric(DirectFunctionCall2(numeric_div, NumericGetDatum(arg1), NumericGetDatum(radians_per_degree))); - + PG_RETURN_NUMERIC(result); } Datum numeric_radians(PG_FUNCTION_ARGS) { - Numeric arg1 = PG_GETARG_NUMERIC(0); - Numeric radians_per_degree,result; + Numeric arg1 = PG_GETARG_NUMERIC(0); + Numeric radians_per_degree, + result; - radians_per_degree = DatumGetNumeric(DirectFunctionCall1(float8_numeric,Float8GetDatum(RADIANS_PER_DEGREE))); + radians_per_degree = DatumGetNumeric(DirectFunctionCall1(float8_numeric, Float8GetDatum(RADIANS_PER_DEGREE))); result = DatumGetNumeric(DirectFunctionCall2(numeric_mul, NumericGetDatum(arg1), NumericGetDatum(radians_per_degree))); @@ -1994,53 +2080,58 @@ numeric_radians(PG_FUNCTION_ARGS) Datum object_schema_name(PG_FUNCTION_ARGS) { - Oid object_id; - Oid database_id; - Oid user_id = GetUserId(); - Oid namespace_oid = InvalidOid; - Oid temp_nspid = InvalidOid; - char* namespace_name; - const char* schema_name; - - if(PG_ARGISNULL(0)) + Oid object_id; + Oid database_id; + Oid user_id = GetUserId(); + Oid namespace_oid = InvalidOid; + Oid temp_nspid = InvalidOid; + char *namespace_name; + const char *schema_name; + + if (PG_ARGISNULL(0)) PG_RETURN_NULL(); else object_id = (Oid) PG_GETARG_INT32(0); - if(PG_ARGISNULL(1)) + if (PG_ARGISNULL(1)) database_id = get_cur_db_id(); - else { + else + { database_id = (Oid) PG_GETARG_INT32(1); user_id = GetSessionUserId(); } /* lookup namespace_oid in pg_class */ temp_nspid = get_rel_namespace(object_id); - if(OidIsValid(temp_nspid)){ - if(pg_class_aclcheck(object_id, user_id, ACL_SELECT) == ACLCHECK_OK) + if (OidIsValid(temp_nspid)) + { + if (pg_class_aclcheck(object_id, user_id, ACL_SELECT) == ACLCHECK_OK) namespace_oid = temp_nspid; else PG_RETURN_NULL(); } - if (!OidIsValid(namespace_oid)){ /* if not found earlier */ + if (!OidIsValid(namespace_oid)) + { /* if not found earlier */ /* Lookup namespace_oid in pg_proc */ temp_nspid = tsql_get_proc_nsp_oid(object_id); - if(OidIsValid(temp_nspid)){ + if (OidIsValid(temp_nspid)) + { if (pg_proc_aclcheck(object_id, user_id, ACL_EXECUTE) == ACLCHECK_OK) namespace_oid = temp_nspid; else PG_RETURN_NULL(); } } - if (!OidIsValid(namespace_oid)){ /* if not found earlier */ + if (!OidIsValid(namespace_oid)) + { /* if not found earlier */ /* Lookup namespace_oid in pg_trigger */ temp_nspid = tsql_get_trigger_rel_oid(object_id); - if(OidIsValid(temp_nspid)) + if (OidIsValid(temp_nspid)) { /* - * Since pg_trigger does not contain namespace oid, we use - * the fact that the schema name of the trigger should be same - * as that of the table the trigger is on + * Since pg_trigger does not contain namespace oid, we use the + * fact that the schema name of the trigger should be same as that + * of the table the trigger is on */ if (pg_class_aclcheck(temp_nspid, user_id, ACL_SELECT) == ACLCHECK_OK) namespace_oid = get_rel_namespace(temp_nspid); @@ -2048,18 +2139,20 @@ object_schema_name(PG_FUNCTION_ARGS) PG_RETURN_NULL(); } } - if (!OidIsValid(namespace_oid)){ /* if not found earlier */ + if (!OidIsValid(namespace_oid)) + { /* if not found earlier */ /* Lookup namespace_oid in pg_constraint */ namespace_oid = tsql_get_constraint_nsp_oid(object_id, user_id); } /* Find schema name from namespace_oid */ - if (OidIsValid(namespace_oid)){ + if (OidIsValid(namespace_oid)) + { namespace_name = get_namespace_name(namespace_oid); if (pg_namespace_aclcheck(namespace_oid, user_id, ACL_USAGE) != ACLCHECK_OK || - /* database_id should be same as that of db_id of physical schema name*/ + /* database_id should be same as that of db_id of physical schema name */ database_id != get_dbid_from_physical_schema_name(namespace_name, true)) - PG_RETURN_NULL(); + PG_RETURN_NULL(); schema_name = get_logical_schema_name(namespace_name, true); pfree(namespace_name); PG_RETURN_TEXT_P(cstring_to_text(schema_name)); @@ -2071,8 +2164,8 @@ object_schema_name(PG_FUNCTION_ARGS) Datum pg_extension_config_remove(PG_FUNCTION_ARGS) { - Oid tableoid = PG_GETARG_OID(0); - char *tablename = get_rel_name(tableoid); + Oid tableoid = PG_GETARG_OID(0); + char *tablename = get_rel_name(tableoid); /* * We only allow this to be called from an extension's SQL script. We @@ -2093,7 +2186,7 @@ pg_extension_config_remove(PG_FUNCTION_ARGS) (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("table \"%s\" is not a member of the extension being created", tablename))); - + extension_config_remove_wrapper(CurrentExtensionObject, tableoid); PG_RETURN_VOID(); diff --git a/contrib/babelfishpg_tsql/src/analyzer.c b/contrib/babelfishpg_tsql/src/analyzer.c index 340d774707..2e44a72b94 100644 --- a/contrib/babelfishpg_tsql/src/analyzer.c +++ b/contrib/babelfishpg_tsql/src/analyzer.c @@ -22,297 +22,318 @@ static Walker_context *make_analyzer_context(CompileContext *cmpl_ctx); static void destroy_analyzer_context(void *ctx); /* all items MUST be destoryed in destroy_template_context */ -typedef struct +typedef struct { - /* for invalid GOTO check */ - DynaVec *trycatch_info_stack; /* current nesting stmt_try_catch */ - DynaVec *loop_stack; /* current nesting loops */ - DynaVec *gotos; /* store all user input goto stmts */ + /* for invalid GOTO check */ + DynaVec *trycatch_info_stack; /* current nesting stmt_try_catch */ + DynaVec *loop_stack; /* current nesting loops */ + DynaVec *gotos; /* store all user input goto stmts */ - /* compile context */ - CompileContext *cmpl_ctx; + /* compile context */ + CompileContext *cmpl_ctx; } AnalyzerContext; -static Walker_context *make_analyzer_context(CompileContext *cmpl_ctx) +static Walker_context * +make_analyzer_context(CompileContext *cmpl_ctx) { - Walker_context *walker = make_template_context(); - AnalyzerContext *analyzer = palloc(sizeof(AnalyzerContext)); - - analyzer->trycatch_info_stack = create_stack2(sizeof(TryCatchInfo), ANALYZER_INITIAL_STACK_SIZE); - analyzer->loop_stack = create_stack2(sizeof(PLtsql_stmt_while *), ANALYZER_INITIAL_STACK_SIZE); - analyzer->gotos = create_stack2(sizeof(PLtsql_stmt_goto *), ANALYZER_INITIAL_STACK_SIZE); - - /* compile context */ - analyzer->cmpl_ctx = cmpl_ctx; - - /* Regster actions */ - walker->try_catch_act = &analyzer_try_catch_act; - walker->goto_act = &analyzer_goto_act; - walker->label_act = &analyzer_label_act; - walker->while_act = &analyzer_while_act; - walker->exit_act = &analyzer_exit_act; - walker->return_act = &analyzer_return_act; - - /* Extra context */ - walker->extra_ctx = (void *) analyzer; - walker->destroy_extra_ctx = &destroy_analyzer_context; - return walker; + Walker_context *walker = make_template_context(); + AnalyzerContext *analyzer = palloc(sizeof(AnalyzerContext)); + + analyzer->trycatch_info_stack = create_stack2(sizeof(TryCatchInfo), ANALYZER_INITIAL_STACK_SIZE); + analyzer->loop_stack = create_stack2(sizeof(PLtsql_stmt_while *), ANALYZER_INITIAL_STACK_SIZE); + analyzer->gotos = create_stack2(sizeof(PLtsql_stmt_goto *), ANALYZER_INITIAL_STACK_SIZE); + + /* compile context */ + analyzer->cmpl_ctx = cmpl_ctx; + + /* Regster actions */ + walker->try_catch_act = &analyzer_try_catch_act; + walker->goto_act = &analyzer_goto_act; + walker->label_act = &analyzer_label_act; + walker->while_act = &analyzer_while_act; + walker->exit_act = &analyzer_exit_act; + walker->return_act = &analyzer_return_act; + + /* Extra context */ + walker->extra_ctx = (void *) analyzer; + walker->destroy_extra_ctx = &destroy_analyzer_context; + return walker; } -static void destroy_analyzer_context(void *ctx) +static void +destroy_analyzer_context(void *ctx) { - AnalyzerContext *analyzer_ctx = (AnalyzerContext *) ctx; + AnalyzerContext *analyzer_ctx = (AnalyzerContext *) ctx; destroy_vector(analyzer_ctx->trycatch_info_stack); destroy_vector(analyzer_ctx->loop_stack); - destroy_vector(analyzer_ctx->gotos); + destroy_vector(analyzer_ctx->gotos); - pfree(analyzer_ctx); + pfree(analyzer_ctx); } /*********************************************************************************** * VISITOR ACTIONS IMPLEMENTATION **********************************************************************************/ -static void save_scope(PLtsql_stmt *stmt, AnalyzerContext *analyzer_ctx) +static void +save_scope(PLtsql_stmt *stmt, AnalyzerContext *analyzer_ctx) { - CompileContext *cmpl_ctx = analyzer_ctx->cmpl_ctx; - ScopeContext *scope_context = - hash_search(cmpl_ctx->stmt_scope_context, &stmt, HASH_ENTER, NULL); - - scope_context->nesting_trycatch_infos = - create_vector_copy(analyzer_ctx->trycatch_info_stack); - scope_context->nesting_loops = - create_vector_copy(analyzer_ctx->loop_stack); + CompileContext *cmpl_ctx = analyzer_ctx->cmpl_ctx; + ScopeContext *scope_context = + hash_search(cmpl_ctx->stmt_scope_context, &stmt, HASH_ENTER, NULL); + + scope_context->nesting_trycatch_infos = + create_vector_copy(analyzer_ctx->trycatch_info_stack); + scope_context->nesting_loops = + create_vector_copy(analyzer_ctx->loop_stack); } -static bool analyzer_try_catch_act(Walker_context *ctx, PLtsql_stmt_try_catch *stmt) +static bool +analyzer_try_catch_act(Walker_context *ctx, PLtsql_stmt_try_catch *stmt) { - AnalyzerContext *analyzer_ctx = (AnalyzerContext*) ctx->extra_ctx; - TryCatchInfo try_catch_info; - TryCatchInfo *try_catch_info_ptr; + AnalyzerContext *analyzer_ctx = (AnalyzerContext *) ctx->extra_ctx; + TryCatchInfo try_catch_info; + TryCatchInfo *try_catch_info_ptr; - try_catch_info.stmt = (PLtsql_stmt *) stmt; - try_catch_info.in_try_block = true; - vec_push_back(analyzer_ctx->trycatch_info_stack, &try_catch_info); + try_catch_info.stmt = (PLtsql_stmt *) stmt; + try_catch_info.in_try_block = true; + vec_push_back(analyzer_ctx->trycatch_info_stack, &try_catch_info); - general_walker_func(stmt->body, ctx); /* visit try block */ + general_walker_func(stmt->body, ctx); /* visit try block */ - try_catch_info_ptr = (TryCatchInfo *) vec_back(analyzer_ctx->trycatch_info_stack); - try_catch_info_ptr->in_try_block = false; + try_catch_info_ptr = (TryCatchInfo *) vec_back(analyzer_ctx->trycatch_info_stack); + try_catch_info_ptr->in_try_block = false; - general_walker_func(stmt->handler, ctx); /* visit right chid */ + general_walker_func(stmt->handler, ctx); /* visit right chid */ - vec_pop_back(analyzer_ctx->trycatch_info_stack); + vec_pop_back(analyzer_ctx->trycatch_info_stack); - return false; + return false; } -static bool analyzer_goto_act(Walker_context *ctx, PLtsql_stmt_goto *stmt) +static bool +analyzer_goto_act(Walker_context *ctx, PLtsql_stmt_goto *stmt) { - AnalyzerContext *analyzer_ctx = (AnalyzerContext*) ctx->extra_ctx; + AnalyzerContext *analyzer_ctx = (AnalyzerContext *) ctx->extra_ctx; - save_scope((PLtsql_stmt*) stmt, analyzer_ctx); - vec_push_back(analyzer_ctx->gotos, &stmt); - return stmt_walker((PLtsql_stmt*)stmt, &general_walker_func, ctx); + save_scope((PLtsql_stmt *) stmt, analyzer_ctx); + vec_push_back(analyzer_ctx->gotos, &stmt); + return stmt_walker((PLtsql_stmt *) stmt, &general_walker_func, ctx); } -static bool analyzer_label_act(Walker_context *ctx, PLtsql_stmt_label *stmt) +static bool +analyzer_label_act(Walker_context *ctx, PLtsql_stmt_label *stmt) { - AnalyzerContext *analyzer_ctx = (AnalyzerContext*) ctx->extra_ctx; - CompileContext *cmpl_ctx = analyzer_ctx->cmpl_ctx; - bool found = false; - LabelStmtEntry *label_entry = - hash_search(cmpl_ctx->label_stmt_map, stmt->label, HASH_ENTER, &found); - - if (found) - { - /* label not unique within one procedure */ - PLtsql_stmt_label *label = label_entry->stmt; - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Label %s not unique wihtin one procedure in line %d, previous defined in line %d", - stmt->label, stmt->lineno, label->lineno))); - } - label_entry->stmt = stmt; - - save_scope((PLtsql_stmt*) stmt, analyzer_ctx); - - return stmt_walker((PLtsql_stmt*)stmt, &general_walker_func, ctx); + AnalyzerContext *analyzer_ctx = (AnalyzerContext *) ctx->extra_ctx; + CompileContext *cmpl_ctx = analyzer_ctx->cmpl_ctx; + bool found = false; + LabelStmtEntry *label_entry = + hash_search(cmpl_ctx->label_stmt_map, stmt->label, HASH_ENTER, &found); + + if (found) + { + /* label not unique within one procedure */ + PLtsql_stmt_label *label = label_entry->stmt; + + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Label %s not unique wihtin one procedure in line %d, previous defined in line %d", + stmt->label, stmt->lineno, label->lineno))); + } + label_entry->stmt = stmt; + + save_scope((PLtsql_stmt *) stmt, analyzer_ctx); + + return stmt_walker((PLtsql_stmt *) stmt, &general_walker_func, ctx); } -static bool analyzer_while_act(Walker_context *ctx, PLtsql_stmt_while *stmt) +static bool +analyzer_while_act(Walker_context *ctx, PLtsql_stmt_while *stmt) { - AnalyzerContext *analyzer_ctx = (AnalyzerContext*) ctx->extra_ctx; - ListCell *s; + AnalyzerContext *analyzer_ctx = (AnalyzerContext *) ctx->extra_ctx; + ListCell *s; - vec_push_back(analyzer_ctx->loop_stack, &stmt); - save_scope((PLtsql_stmt*) stmt, analyzer_ctx); + vec_push_back(analyzer_ctx->loop_stack, &stmt); + save_scope((PLtsql_stmt *) stmt, analyzer_ctx); - /* visit all children */ - foreach(s, stmt->body) - general_walker_func((PLtsql_stmt *) lfirst(s), ctx); + /* visit all children */ + foreach(s, stmt->body) + general_walker_func((PLtsql_stmt *) lfirst(s), ctx); - vec_pop_back(analyzer_ctx->loop_stack); - return false; + vec_pop_back(analyzer_ctx->loop_stack); + return false; } -static bool analyzer_exit_act(Walker_context *ctx, PLtsql_stmt_exit *stmt) +static bool +analyzer_exit_act(Walker_context *ctx, PLtsql_stmt_exit *stmt) { - AnalyzerContext *analyzer_ctx = (AnalyzerContext*) ctx->extra_ctx; - - if (vec_size(analyzer_ctx->loop_stack) == 0) - { - if (stmt->is_exit) /* break */ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Do not support BREAK outside of a WHILE loop, line %d", stmt->lineno))); - else - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Do not support CONTINUE outside of a WHILE loop, line %d", stmt->lineno))); - } - save_scope((PLtsql_stmt*) stmt, analyzer_ctx); - - return stmt_walker((PLtsql_stmt*)stmt, &general_walker_func, ctx); + AnalyzerContext *analyzer_ctx = (AnalyzerContext *) ctx->extra_ctx; + + if (vec_size(analyzer_ctx->loop_stack) == 0) + { + if (stmt->is_exit) /* break */ + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Do not support BREAK outside of a WHILE loop, line %d", stmt->lineno))); + else + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Do not support CONTINUE outside of a WHILE loop, line %d", stmt->lineno))); + } + save_scope((PLtsql_stmt *) stmt, analyzer_ctx); + + return stmt_walker((PLtsql_stmt *) stmt, &general_walker_func, ctx); } -static bool analyzer_return_act(Walker_context *ctx, PLtsql_stmt_return *stmt) +static bool +analyzer_return_act(Walker_context *ctx, PLtsql_stmt_return *stmt) { - AnalyzerContext *analyzer_ctx = (AnalyzerContext*) ctx->extra_ctx; + AnalyzerContext *analyzer_ctx = (AnalyzerContext *) ctx->extra_ctx; - save_scope((PLtsql_stmt*) stmt, analyzer_ctx); - return stmt_walker((PLtsql_stmt*)stmt, &general_walker_func, ctx); + save_scope((PLtsql_stmt *) stmt, analyzer_ctx); + return stmt_walker((PLtsql_stmt *) stmt, &general_walker_func, ctx); } /*********************************************************************************** - * CHECKING FUNCTIONS + * CHECKING FUNCTIONS **********************************************************************************/ static bool check_goto_try_catch(DynaVec *src_stack, DynaVec *dest_stack); static bool check_goto_loop(DynaVec *src_stack, DynaVec *dest_stack); -static void check_unsupported_goto(AnalyzerContext *analyzer_ctx) +static void +check_unsupported_goto(AnalyzerContext *analyzer_ctx) { - CompileContext *cmpl_ctx = analyzer_ctx->cmpl_ctx; - size_t size = vec_size(analyzer_ctx->gotos); - PLtsql_stmt_label *label; - DynaVec *src_nesting_trycatch_infos, *dest_nesting_trycatch_infos; - DynaVec *src_nesting_loops, *dest_nesting_loops; - LabelStmtEntry *label_entry; - ScopeContext *scope_context; - size_t i; - - for (i = 0; i < size; i++) - { - PLtsql_stmt_goto *stmt_goto = - *(PLtsql_stmt_goto **) vec_at(analyzer_ctx->gotos, i); - - label_entry = - hash_search(cmpl_ctx->label_stmt_map, stmt_goto->target_label, - HASH_FIND, NULL); - - /* check existence of target label */ - if (!label_entry) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("GOTO target Label %s not defined", - stmt_goto->target_label))); - - /* source context */ - scope_context = - hash_search(cmpl_ctx->stmt_scope_context, &stmt_goto, HASH_FIND, NULL); - src_nesting_trycatch_infos = scope_context->nesting_trycatch_infos; - src_nesting_loops = scope_context->nesting_loops; - - /* destination context */ - label = label_entry->stmt; - scope_context = - hash_search(cmpl_ctx->stmt_scope_context, &label, HASH_FIND, NULL); - dest_nesting_trycatch_infos = scope_context->nesting_trycatch_infos; - dest_nesting_loops = scope_context->nesting_loops; - - /* check if goto a loop or try catch block */ - if (!check_goto_try_catch(src_nesting_trycatch_infos, dest_nesting_trycatch_infos)) - ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("GOTO into an try catch block not supported, label %s", - stmt_goto->target_label))); - - if (!check_goto_loop(src_nesting_loops, dest_nesting_loops)) - ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("GOTO into an while loop not supported, label %s", - stmt_goto->target_label))); - } + CompileContext *cmpl_ctx = analyzer_ctx->cmpl_ctx; + size_t size = vec_size(analyzer_ctx->gotos); + PLtsql_stmt_label *label; + DynaVec *src_nesting_trycatch_infos, + *dest_nesting_trycatch_infos; + DynaVec *src_nesting_loops, + *dest_nesting_loops; + LabelStmtEntry *label_entry; + ScopeContext *scope_context; + size_t i; + + for (i = 0; i < size; i++) + { + PLtsql_stmt_goto *stmt_goto = + *(PLtsql_stmt_goto **) vec_at(analyzer_ctx->gotos, i); + + label_entry = + hash_search(cmpl_ctx->label_stmt_map, stmt_goto->target_label, + HASH_FIND, NULL); + + /* check existence of target label */ + if (!label_entry) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("GOTO target Label %s not defined", + stmt_goto->target_label))); + + /* source context */ + scope_context = + hash_search(cmpl_ctx->stmt_scope_context, &stmt_goto, HASH_FIND, NULL); + src_nesting_trycatch_infos = scope_context->nesting_trycatch_infos; + src_nesting_loops = scope_context->nesting_loops; + + /* destination context */ + label = label_entry->stmt; + scope_context = + hash_search(cmpl_ctx->stmt_scope_context, &label, HASH_FIND, NULL); + dest_nesting_trycatch_infos = scope_context->nesting_trycatch_infos; + dest_nesting_loops = scope_context->nesting_loops; + + /* check if goto a loop or try catch block */ + if (!check_goto_try_catch(src_nesting_trycatch_infos, dest_nesting_trycatch_infos)) + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("GOTO into an try catch block not supported, label %s", + stmt_goto->target_label))); + + if (!check_goto_loop(src_nesting_loops, dest_nesting_loops)) + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("GOTO into an while loop not supported, label %s", + stmt_goto->target_label))); + } } -static bool check_goto_try_catch(DynaVec *src_stack, DynaVec *dest_stack) +static bool +check_goto_try_catch(DynaVec *src_stack, DynaVec *dest_stack) { - if (vec_size(src_stack) < vec_size(dest_stack)) - return false; /* goto deeper try-catch block */ - else - { - size_t goto_stack_size = vec_size(src_stack); - size_t label_stack_size = vec_size(dest_stack); - size_t i; - for (i = 0; i < goto_stack_size && i < label_stack_size; i++) - { - TryCatchInfo *info1 = (TryCatchInfo *) vec_at(src_stack, i); - TryCatchInfo *info2 = (TryCatchInfo *) vec_at(dest_stack, i); - if (info1->stmt != info2->stmt || info1->in_try_block != info2->in_try_block) - return false; /* goto differen upper / sibling try-catch block */ - } - } - return true; + if (vec_size(src_stack) < vec_size(dest_stack)) + return false; /* goto deeper try-catch block */ + else + { + size_t goto_stack_size = vec_size(src_stack); + size_t label_stack_size = vec_size(dest_stack); + size_t i; + + for (i = 0; i < goto_stack_size && i < label_stack_size; i++) + { + TryCatchInfo *info1 = (TryCatchInfo *) vec_at(src_stack, i); + TryCatchInfo *info2 = (TryCatchInfo *) vec_at(dest_stack, i); + + if (info1->stmt != info2->stmt || info1->in_try_block != info2->in_try_block) + return false; /* goto differen upper / sibling try-catch + * block */ + } + } + return true; } -static bool check_goto_loop(DynaVec *src_stack, DynaVec *dest_stack) +static bool +check_goto_loop(DynaVec *src_stack, DynaVec *dest_stack) { - if (vec_size(src_stack) < vec_size(dest_stack)) - return false; /* goto deeper loop */ - else - { - size_t goto_stack_size = vec_size(src_stack); - size_t label_stack_size = vec_size(dest_stack); - size_t i; - for (i = 0; i < goto_stack_size && i < label_stack_size; i++) - { - PLtsql_stmt *stmt1 = *(PLtsql_stmt **) vec_at(src_stack, i); - PLtsql_stmt *stmt2 = *(PLtsql_stmt **) vec_at(dest_stack, i); - if (stmt1 != stmt2) - return false; /* goto different upper / sibling loop block */ - } - } - return true; + if (vec_size(src_stack) < vec_size(dest_stack)) + return false; /* goto deeper loop */ + else + { + size_t goto_stack_size = vec_size(src_stack); + size_t label_stack_size = vec_size(dest_stack); + size_t i; + + for (i = 0; i < goto_stack_size && i < label_stack_size; i++) + { + PLtsql_stmt *stmt1 = *(PLtsql_stmt **) vec_at(src_stack, i); + PLtsql_stmt *stmt2 = *(PLtsql_stmt **) vec_at(dest_stack, i); + + if (stmt1 != stmt2) + return false; /* goto different upper / sibling loop block */ + } + } + return true; } /*********************************************************************************** * PLTSQL ANALYZER **********************************************************************************/ -void analyze(PLtsql_function *func, CompileContext *cmpl_ctx) +void +analyze(PLtsql_function *func, CompileContext *cmpl_ctx) { - Walker_context *walker; - AnalyzerContext *analyzer_ctx; - - if ((!func) || func->exec_codes) /* cached plan */ - return; - - walker = make_analyzer_context(cmpl_ctx); - analyzer_ctx = (AnalyzerContext *) walker->extra_ctx; - - PG_TRY(); - { - /* general checks through traversal */ - stmt_walker((PLtsql_stmt *) func->action, general_walker_func, walker); - - /* extra checks */ - check_unsupported_goto(analyzer_ctx); - } - PG_CATCH(); - { - destroy_template_context(walker); - PG_RE_THROW(); - } - PG_END_TRY(); - - destroy_template_context(walker); + Walker_context *walker; + AnalyzerContext *analyzer_ctx; + + if ((!func) || func->exec_codes) /* cached plan */ + return; + + walker = make_analyzer_context(cmpl_ctx); + analyzer_ctx = (AnalyzerContext *) walker->extra_ctx; + + PG_TRY(); + { + /* general checks through traversal */ + stmt_walker((PLtsql_stmt *) func->action, general_walker_func, walker); + + /* extra checks */ + check_unsupported_goto(analyzer_ctx); + } + PG_CATCH(); + { + destroy_template_context(walker); + PG_RE_THROW(); + } + PG_END_TRY(); + + destroy_template_context(walker); } diff --git a/contrib/babelfishpg_tsql/src/analyzer.h b/contrib/babelfishpg_tsql/src/analyzer.h index 0ba543a702..cac53352e0 100644 --- a/contrib/babelfishpg_tsql/src/analyzer.h +++ b/contrib/babelfishpg_tsql/src/analyzer.h @@ -3,6 +3,6 @@ #include "pltsql.h" #include "compile_context.h" -void analyze(PLtsql_function *func, CompileContext *cmpl_ctx); +void analyze(PLtsql_function *func, CompileContext *cmpl_ctx); -#endif /* ANALYZE_H */ +#endif /* ANALYZE_H */ diff --git a/contrib/babelfishpg_tsql/src/applock.c b/contrib/babelfishpg_tsql/src/applock.c index 89209c79de..36e47bbccb 100644 --- a/contrib/babelfishpg_tsql/src/applock.c +++ b/contrib/babelfishpg_tsql/src/applock.c @@ -24,14 +24,14 @@ PG_FUNCTION_INFO_V1(sp_releaseapplock_function); PG_FUNCTION_INFO_V1(APPLOCK_MODE); PG_FUNCTION_INFO_V1(APPLOCK_TEST); -/* - * Applock local and global hashmaps. The local one keeps track of applock +/* + * Applock local and global hashmaps. The local one keeps track of applock * that the current session owns. The global one resolves hash conflict if * two different lock resource name are hashed to the same integer key. * Both uses the same cache entry structure for convenience. */ -static HTAB * appLockCacheLocal = NULL; -static HTAB * appLockCacheGlobal = NULL; +static HTAB *appLockCacheLocal = NULL; +static HTAB *appLockCacheGlobal = NULL; /* Max length of applock resource name string (including the ending '\0') */ #define APPLOCK_MAX_RESOURCE_LENGTH 256 @@ -42,26 +42,28 @@ static HTAB * appLockCacheGlobal = NULL; #define APPLOCK_MAX_LOCKTIMEOUT_LENGTH 33 #define APPLOCK_MAX_DBPRINCIPAL_LENGTH 33 -/* +/* * Max number of retries to search for usable key when hash collision happens. * The chance of multiple strings being hashed to the same key is roughly * (1/2^63)*(#_of_strings-1). So a small APPLOCK_MAX_TRY_SEARCH_KEY should be - * enough. Also, because we have to scan all the possible candidate keys when - * looking for a usable key (see ApplockGetUsableKey()), a small + * enough. Also, because we have to scan all the possible candidate keys when + * looking for a usable key (see ApplockGetUsableKey()), a small * APPLOCK_MAX_TRY_SEARCH_KEY is preferred too. */ #define APPLOCK_MAX_TRY_SEARCH_KEY 5 typedef struct applockcacheent { - int64 key; /* (hashed) key integer of the lock */ - char resource[APPLOCK_MAX_RESOURCE_LENGTH + 1]; /* Resource name string of the lock */ - uint32_t refcount; /* Currently how many times this lock is being held. - Note the count may be different locally/globally.*/ - slist_head mode_head; /* lock mode list, keeping track of all lock modes - currently being held with this lock resource . - Only used in local cache. */ - bool is_session; /* If it's session lock or transaction lock */ + int64 key; /* (hashed) key integer of the lock */ + char resource[APPLOCK_MAX_RESOURCE_LENGTH + 1]; /* Resource name string + * of the lock */ + uint32_t refcount; /* Currently how many times this lock is being + * held. Note the count may be different + * locally/globally. */ + slist_head mode_head; /* lock mode list, keeping track of all lock + * modes currently being held with this lock + * resource . Only used in local cache. */ + bool is_session; /* If it's session lock or transaction lock */ } AppLockCacheEnt; /* Linked-list struct for keeping track of the lockmodes one owns */ @@ -73,7 +75,7 @@ typedef struct /* * Applock modes - * + * * Table of compatibility ('Yes' indicates compatible): * * mode IS S U IX X @@ -88,7 +90,8 @@ typedef struct * are NOT acquirable by sp_getapplock but can be returned by * APPLOCK_MODE(). See comments for APPLOCK_MODE(). */ -typedef enum { +typedef enum +{ APPLOCKMODE_NOLOCK, APPLOCKMODE_INTENTEXCLUSIVE, APPLOCKMODE_INTENTSHARED, @@ -97,7 +100,7 @@ typedef enum { APPLOCKMODE_EXCLUSIVE, APPLOCKMODE_SHAREDINTENTEXCLUSIVE, APPLOCKMODE_UPDATEINTENTEXCLUSIVE -} Applock_All_Lockmode; +} Applock_All_Lockmode; /* * Strings for Applock modes. The order MUST match the mode enum in @@ -118,21 +121,24 @@ static const char *AppLockModeStrings[] = /* * Added pg_attribute_printf() to silence compiler warning tunrned error [-Werror=suggest-attribute=format] */ -static pg_attribute_printf(1, 2) void ApplockPrintMessage(const char *fmt, ...) { +static pg_attribute_printf(1, 2) +void +ApplockPrintMessage(const char *fmt,...) +{ - int save_errno = errno; + int save_errno = errno; size_t len = 128; /* initial assumption about buffer size */ - char *msg; + char *msg; for (;;) { - char *buf; + char *buf; va_list args; size_t newlen; /* - * Allocate buffer. Note that in frontend this maps to malloc - * with exit-on-error. + * Allocate buffer. Note that in frontend this maps to malloc with + * exit-on-error. */ buf = (char *) palloc(len); @@ -143,8 +149,9 @@ static pg_attribute_printf(1, 2) void ApplockPrintMessage(const char *fmt, ...) va_end(args); if (newlen < len) - { msg = buf; - break; /* success */ + { + msg = buf; + break; /* success */ } /* Release buffer and loop around to try again with larger len. */ @@ -177,8 +184,8 @@ static pg_attribute_printf(1, 2) void ApplockPrintMessage(const char *fmt, ...) (locktag).locktag_type = LOCKTAG_ADVISORY, \ (locktag).locktag_lockmethodid = APPLOCK_LOCKMETHOD) -/* - * PG advisory lock uses 0 and 1 for field4 (see comments for SET_LOCKTAG_INT64). +/* + * PG advisory lock uses 0 and 1 for field4 (see comments for SET_LOCKTAG_INT64). * We use 2 to avoid conflict with it. */ #define ApplockSetLocktag(tag, key64) \ @@ -199,7 +206,7 @@ static pg_attribute_printf(1, 2) void ApplockPrintMessage(const char *fmt, ...) (ENTRY)->resource[0] = '\0'; \ slist_init(&(ENTRY)->mode_head); \ } \ -} while(0) +} while(0) #define AppLockCacheLookup(ID, ENTRY) \ do { \ @@ -269,7 +276,7 @@ static pg_attribute_printf(1, 2) void ApplockPrintMessage(const char *fmt, ...) } \ } while (0) -/* +/* * We accept any input of dbprincipal until we decide otherwise. * Also a placeholder to escape unused variable error for dbprincipal. */ @@ -281,7 +288,7 @@ static pg_attribute_printf(1, 2) void ApplockPrintMessage(const char *fmt, ...) static void ApplockRemoveCache(bool release_session); -/* +/* * Simple consistent hashing function to convert a string to an int. * We'll avoid return non-negative values because that will be used for errors. * The chance of 2 strings colliding with the same key is about 1/2^63. @@ -290,29 +297,31 @@ static void ApplockRemoveCache(bool release_session); static int64 applock_simple_hash(char *str) { - const int p = 31; + const int p = 31; const int64 m = INT64_MAX; - uint64 hash_value = 0; - int64 p_pow = 1; - char c; + uint64 hash_value = 0; + int64 p_pow = 1; + char c; c = *str; - while (c) { + while (c) + { hash_value = (hash_value + (c - 'a' + 1) * p_pow) % m; p_pow = (p_pow * p) % m; c = *++str; } - return hash_value; + return hash_value; } -/* - * Get PG Lock mode for corresponding Applock mode. +/* + * Get PG Lock mode for corresponding Applock mode. * See AppLockConflicts[] defined in backend/storage/lmgr/lock.c. */ -static short getPGLockMode(short applockmode) +static short +getPGLockMode(short applockmode) { - short mode = 0; - + short mode = 0; + if (applockmode == APPLOCKMODE_EXCLUSIVE) mode = ExclusiveLock; else if (applockmode == APPLOCKMODE_SHARED) @@ -330,48 +339,51 @@ static short getPGLockMode(short applockmode) } /* Initialize both local and global hashmaps */ -static void initApplockCache() +static void +initApplockCache() { - HASHCTL ctl; + HASHCTL ctl; /* Local cache */ MemSet(&ctl, 0, sizeof(ctl)); ctl.keysize = sizeof(int64); ctl.entrysize = sizeof(AppLockCacheEnt); - appLockCacheLocal = hash_create("Applock Cache", 16, - &ctl, HASH_ELEM | HASH_BLOBS); + appLockCacheLocal = hash_create("Applock Cache", 16, + &ctl, HASH_ELEM | HASH_BLOBS); /* Global cache */ LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE); MemSet(&ctl, 0, sizeof(ctl)); ctl.keysize = sizeof(int64); ctl.entrysize = sizeof(AppLockCacheEnt); - appLockCacheGlobal = (HTAB*)ShmemInitHash("Applock", - /*table size*/ 32, - /*max table size*/ 32, - &ctl, - HASH_ELEM | HASH_BLOBS); + appLockCacheGlobal = (HTAB *) ShmemInitHash("Applock", + /* table size */ 32, + /* max table size */ 32, + &ctl, + HASH_ELEM | HASH_BLOBS); LWLockRelease(AddinShmemInitLock); - /* - * Init this function handler to be called when PG implicitly - * release locks at the end of transaction/session. + /* + * Init this function handler to be called when PG implicitly release + * locks at the end of transaction/session. */ - applock_release_func_handler = (void*) ApplockRemoveCache; + applock_release_func_handler = (void *) ApplockRemoveCache; } /* Search a key corresponding to a resource name in local hashmap. */ -static int64 AppLockSearchKeyLocal(char *resource) +static int64 +AppLockSearchKeyLocal(char *resource) { AppLockCacheEnt *entry; - int64 key; - int try_search = 0; + int64 key; + int try_search = 0; key = applock_simple_hash(resource); - while (try_search++ < APPLOCK_MAX_TRY_SEARCH_KEY) { - entry = (AppLockCacheEnt*) hash_search(appLockCacheLocal, - (void *) &key, - HASH_FIND, NULL); + while (try_search++ < APPLOCK_MAX_TRY_SEARCH_KEY) + { + entry = (AppLockCacheEnt *) hash_search(appLockCacheLocal, + (void *) &key, + HASH_FIND, NULL); if (entry && strcmp(entry->resource, resource) == 0) return key; /* be mindful of overflow */ @@ -382,20 +394,23 @@ static int64 AppLockSearchKeyLocal(char *resource) } /* Search a key corresponding to a resource name in global hashmap. */ -static int64 AppLockSearchKeyGlobal(char *resource) +static int64 +AppLockSearchKeyGlobal(char *resource) { AppLockCacheEnt *entry; - int64 key; - int try_search = 0; + int64 key; + int try_search = 0; LWLockAcquire(TsqlApplockSyncLock, LW_SHARED); key = applock_simple_hash(resource); - while (try_search++ < APPLOCK_MAX_TRY_SEARCH_KEY) { - entry = (AppLockCacheEnt*) hash_search(appLockCacheGlobal, - (void *) &key, - HASH_FIND, NULL); - if (entry && strcmp(entry->resource, resource) == 0) { + while (try_search++ < APPLOCK_MAX_TRY_SEARCH_KEY) + { + entry = (AppLockCacheEnt *) hash_search(appLockCacheGlobal, + (void *) &key, + HASH_FIND, NULL); + if (entry && strcmp(entry->resource, resource) == 0) + { LWLockRelease(TsqlApplockSyncLock); return key; } @@ -407,47 +422,56 @@ static int64 AppLockSearchKeyGlobal(char *resource) return -1; } -/* - * Un-reference an entry in the appLockCacheGlobal. +/* + * Un-reference an entry in the appLockCacheGlobal. * Delete it if its refcount is reduced to 0. */ -static void ApplockUnrefGlobalCache(int64 key) +static void +ApplockUnrefGlobalCache(int64 key) { AppLockCacheEnt *entry; LWLockAcquire(TsqlApplockSyncLock, LW_EXCLUSIVE); - entry = (AppLockCacheEnt *) hash_search(appLockCacheGlobal, - (void *) &key, - HASH_FIND, NULL); - if (entry && --entry->refcount == 0) { - hash_search(appLockCacheGlobal, + entry = (AppLockCacheEnt *) hash_search(appLockCacheGlobal, (void *) &key, - HASH_REMOVE, NULL); + HASH_FIND, NULL); + if (entry && --entry->refcount == 0) + { + hash_search(appLockCacheGlobal, + (void *) &key, + HASH_REMOVE, NULL); entry->resource[0] = '\0'; } LWLockRelease(TsqlApplockSyncLock); } -/* - * Get a usable key from the resource string that doesn't collide - * with existing ones. +/* + * Get a usable key from the resource string that doesn't collide + * with existing ones. * Return a usable key (non-negative integer) if found, or -1 if couldn't. */ -static int64 ApplockGetUsableKey(char *resource) +static int64 +ApplockGetUsableKey(char *resource) { - int64 key, usable_key; - bool found; + int64 key, + usable_key; + bool found; AppLockCacheEnt *entry; - int try_search = 0; + int try_search = 0; - /* Firstly, try search in the global cache to see if it's available already*/ - if ((key = AppLockSearchKeyGlobal(resource)) != -1) { + /* + * Firstly, try search in the global cache to see if it's available + * already + */ + if ((key = AppLockSearchKeyGlobal(resource)) != -1) + { LWLockAcquire(TsqlApplockSyncLock, LW_EXCLUSIVE); - entry = (AppLockCacheEnt*) hash_search(appLockCacheGlobal, - (void *) &key, - HASH_ENTER, &found); - /* Someone might've just deleted it. So check it before modify.*/ - if (found) { + entry = (AppLockCacheEnt *) hash_search(appLockCacheGlobal, + (void *) &key, + HASH_ENTER, &found); + /* Someone might've just deleted it. So check it before modify. */ + if (found) + { ++entry->refcount; LWLockRelease(TsqlApplockSyncLock); return key; @@ -463,23 +487,25 @@ static int64 ApplockGetUsableKey(char *resource) LWLockAcquire(TsqlApplockSyncLock, LW_EXCLUSIVE); - /* - * Some different resource name may have been hashed to the same key. - * In that case, we keep incrementing key until we find a usable one. + /* + * Some different resource name may have been hashed to the same key. In + * that case, we keep incrementing key until we find a usable one. * - * NB: it's not very meaningful to try too many times because if it - * turns out that a couple of random keys have somehow all been used, - * we probably have a bug somewhere so it's better to error out. - * Also, we have to search all the possible candidate keys for the resource - * to make sure someone else did not just insert the same resource with - * some key unknown to the caller. + * NB: it's not very meaningful to try too many times because if it turns + * out that a couple of random keys have somehow all been used, we + * probably have a bug somewhere so it's better to error out. Also, we + * have to search all the possible candidate keys for the resource to make + * sure someone else did not just insert the same resource with some key + * unknown to the caller. */ - while (try_search++ < APPLOCK_MAX_TRY_SEARCH_KEY) { - entry = (AppLockCacheEnt*) hash_search(appLockCacheGlobal, - (void *) &key, - HASH_FIND, NULL); + while (try_search++ < APPLOCK_MAX_TRY_SEARCH_KEY) + { + entry = (AppLockCacheEnt *) hash_search(appLockCacheGlobal, + (void *) &key, + HASH_FIND, NULL); /* Someone might've just inserted an entry for this resource. */ - if (entry && strcmp(entry->resource, resource) == 0) { + if (entry && strcmp(entry->resource, resource) == 0) + { entry->refcount++; LWLockRelease(TsqlApplockSyncLock); return key; @@ -492,10 +518,11 @@ static int64 ApplockGetUsableKey(char *resource) key = (key % INT64_MAX) + 1; } - if (usable_key != -1) { - entry = (AppLockCacheEnt*) hash_search(appLockCacheGlobal, - (void *) &usable_key, - HASH_ENTER, &found); + if (usable_key != -1) + { + entry = (AppLockCacheEnt *) hash_search(appLockCacheGlobal, + (void *) &usable_key, + HASH_ENTER, &found); /* It must be non-existing at this point. */ Assert(!found); @@ -520,19 +547,20 @@ static int64 ApplockGetUsableKey(char *resource) * -2: lock request canceled. * -3: lock request was chosen as a deadlock victim. */ -static int _sp_getapplock_internal (char *resource, char *lockmode, - char *lockowner, int32_t timeout, - char *dbprincipal, bool suppress_warning) +static int +_sp_getapplock_internal(char *resource, char *lockmode, + char *lockowner, int32_t timeout, + char *dbprincipal, bool suppress_warning) { int32_t cur_timeout; - int64 key; - LOCKTAG tag; + int64 key; + LOCKTAG tag; short mode; bool is_session; bool lock_timeout_occurred = false; bool no_wait = false; - AppLockCacheEnt *entry; - volatile TimestampTz start_time; + AppLockCacheEnt *entry; + volatile TimestampTz start_time; AppLockModeNode *node; /* a few sanity checks */ @@ -550,42 +578,45 @@ static int _sp_getapplock_internal (char *resource, char *lockmode, if ((key = ApplockGetUsableKey(resource)) < 0) { if (!suppress_warning) - ApplockPrintMessage("could not find usable key for lock resource %s.",resource); + ApplockPrintMessage("could not find usable key for lock resource %s.", resource); return -999; } ApplockSetLocktag(tag, key); - /* + /* * Setting timeout if timeout is not the meaningless default value (-99). - * Note some special cases in timeout: in TSQL -1 means wait forever - * and 0 means do not wait at all. But in PG, 0 means wait forever and - * -1 is meaningless. To make PG not wait at all, we need to pass - * no_wait=true to LockAcquire(). + * Note some special cases in timeout: in TSQL -1 means wait forever and 0 + * means do not wait at all. But in PG, 0 means wait forever and -1 is + * meaningless. To make PG not wait at all, we need to pass no_wait=true + * to LockAcquire(). */ if (timeout == 0) no_wait = true; timeout = (timeout == -1 ? 0 : timeout); cur_timeout = atoi(GetConfigOption("lock_timeout", false, false)); ApplockSetLockTimeout(timeout); - + start_time = GetCurrentTimestamp(); - /* finally, attempt to acquire the lock.*/ + /* finally, attempt to acquire the lock. */ PG_TRY(); { - /* If lock is unavailable, throw an error to let the catch block deal with it */ + /* + * If lock is unavailable, throw an error to let the catch block deal + * with it + */ if (LockAcquire(&tag, getPGLockMode(mode), is_session, no_wait) == LOCKACQUIRE_NOT_AVAIL) ereport(ERROR, (errcode(ERRCODE_LOCK_NOT_AVAILABLE), - errmsg("Applock resource \'%s\' unavailable", resource))); + errmsg("Applock resource \'%s\' unavailable", resource))); } PG_CATCH(); { - /* + /* * Exceptions during lock acquiring. This could be timeout, deadlock * or other failures. Note that we have to return something here - * instead of throwing the errors out because otherwise the caller - * won't be able to get the return code as defined in TSQL standard. + * instead of throwing the errors out because otherwise the caller + * won't be able to get the return code as defined in TSQL standard. * Therefore, we unfortunately can't print PG's nice deadlock report. */ @@ -595,16 +626,16 @@ static int _sp_getapplock_internal (char *resource, char *lockmode, /* * Did timeout occur? * - * NB: ERRCODE_LOCK_NOT_AVAILABLE is not just for timeout, so we - * have to check the elapse time to really make sure. - * Also, although get_timeout_indicator(LOCK_TIMEOUT, if_reset) can - * check the same but when timeout happens, ProcessInterrupts() always - * reset the indicator, thus we have to use another way. + * NB: ERRCODE_LOCK_NOT_AVAILABLE is not just for timeout, so we have + * to check the elapse time to really make sure. Also, although + * get_timeout_indicator(LOCK_TIMEOUT, if_reset) can check the same + * but when timeout happens, ProcessInterrupts() always reset the + * indicator, thus we have to use another way. */ - lock_timeout_occurred = timeout >= 0 && - get_timeout_finish_time(LOCK_TIMEOUT) - - start_time > (int64)timeout * 1e3 && - geterrcode() == ERRCODE_LOCK_NOT_AVAILABLE; + lock_timeout_occurred = timeout >= 0 && + get_timeout_finish_time(LOCK_TIMEOUT) + - start_time > (int64) timeout * 1e3 && + geterrcode() == ERRCODE_LOCK_NOT_AVAILABLE; /* reset timeout back */ ApplockSetLockTimeout(cur_timeout); @@ -629,21 +660,22 @@ static int _sp_getapplock_internal (char *resource, char *lockmode, ApplockPrintMessage("Deadlock detected in applock request for \'%s\' ", resource); return -3; } - /* + + /* * Regard all other exceptions as lock request being canceled (e.g. * the calling query was interrupted and terminated.) */ else { if (!suppress_warning) - ApplockPrintMessage("Applock request for \'%s\' is canceled", resource); + ApplockPrintMessage("Applock request for \'%s\' is canceled", resource); return -2; } } PG_END_TRY(); ApplockSetLockTimeout(cur_timeout); - + /* lock aquired, we can insert or update the local cache entry now. */ AppLockCacheInsert(key, entry); entry->resource[0] = '\0'; @@ -664,14 +696,15 @@ static int _sp_getapplock_internal (char *resource, char *lockmode, * 0: lock released successfully. * -999: lock release attempt failed. */ -static int _sp_releaseapplock_internal(char *resource, char *lockowner, - char *dbprincipal, bool suppress_warning) +static int +_sp_releaseapplock_internal(char *resource, char *lockowner, + char *dbprincipal, bool suppress_warning) { - int64 key; - LOCKTAG tag; + int64 key; + LOCKTAG tag; short mode; bool is_session; - AppLockCacheEnt *entry; + AppLockCacheEnt *entry; AppLockModeNode *node; /* a few sanity checks */ @@ -680,7 +713,8 @@ static int _sp_releaseapplock_internal(char *resource, char *lockowner, ApplockCheckDbPrincipal(dbprincipal); /* Search in the global cache for the key. */ - if ((key = AppLockSearchKeyGlobal(resource)) == -1) { + if ((key = AppLockSearchKeyGlobal(resource)) == -1) + { if (!suppress_warning) ApplockPrintMessage("No lock resource \'%s\' acquired before.", resource); LWLockRelease(TsqlApplockSyncLock); @@ -689,15 +723,17 @@ static int _sp_releaseapplock_internal(char *resource, char *lockowner, /* verify the key in the local cache, and if the lock owner matches */ AppLockCacheLookup(key, entry); - if (entry == NULL) { + if (entry == NULL) + { if (!suppress_warning) ApplockPrintMessage("No lock resource \'%s\' acquired before.", resource); return -999; } - if (is_session != entry->is_session) { + if (is_session != entry->is_session) + { if (!suppress_warning) - ApplockPrintMessage("Wrong LockOwner for lock resource \'%s\', it is a %s lock.", - resource, entry->is_session ? "Session" : "Transaction"); + ApplockPrintMessage("Wrong LockOwner for lock resource \'%s\', it is a %s lock.", + resource, entry->is_session ? "Session" : "Transaction"); return -999; } @@ -705,13 +741,13 @@ static int _sp_releaseapplock_internal(char *resource, char *lockowner, ApplockSetLocktag(tag, key); /* get the same lock mode as recorded */ - mode = ((AppLockModeNode*)entry->mode_head.head.next)->mode; + mode = ((AppLockModeNode *) entry->mode_head.head.next)->mode; if (!LockRelease(&tag, getPGLockMode(mode), is_session)) return -999; /* Un-referencing the local cache entry and delete it if needed. */ - node = (AppLockModeNode*)slist_pop_head_node((slist_head*)&entry->mode_head); + node = (AppLockModeNode *) slist_pop_head_node((slist_head *) &entry->mode_head); free(node); if (--entry->refcount == 0) AppLockCacheDelete(key); @@ -728,8 +764,10 @@ static int _sp_releaseapplock_internal(char *resource, char *lockowner, Datum sp_getapplock_function(PG_FUNCTION_ARGS) { - char resource[APPLOCK_MAX_RESOURCE_LENGTH], lockmode[APPLOCK_MAX_LOCKMODE_LENGTH]; - char lockowner[APPLOCK_MAX_LOCKOWNER_LENGTH], dbprincipal[APPLOCK_MAX_DBPRINCIPAL_LENGTH]; + char resource[APPLOCK_MAX_RESOURCE_LENGTH], + lockmode[APPLOCK_MAX_LOCKMODE_LENGTH]; + char lockowner[APPLOCK_MAX_LOCKOWNER_LENGTH], + dbprincipal[APPLOCK_MAX_DBPRINCIPAL_LENGTH]; int32_t timeout; int ret; @@ -755,7 +793,8 @@ Datum sp_releaseapplock_function(PG_FUNCTION_ARGS) { char resource[APPLOCK_MAX_RESOURCE_LENGTH]; - char lockowner[APPLOCK_MAX_LOCKOWNER_LENGTH], dbprincipal[APPLOCK_MAX_DBPRINCIPAL_LENGTH]; + char lockowner[APPLOCK_MAX_LOCKOWNER_LENGTH], + dbprincipal[APPLOCK_MAX_DBPRINCIPAL_LENGTH]; int ret; /* Init applock hash table if we haven't done so. */ @@ -774,10 +813,10 @@ sp_releaseapplock_function(PG_FUNCTION_ARGS) /* * Get lockmode of the applock the caller holds and return the mode in string. * - * NB: when there are more than one lock modes, the mode to return is the 'highest' - * lockmode among them. The main order is: from lowest (most relaxed) to - * highest (most strict): IntentShared < Shared < Update < Exclusive. - * A special case is IntentExclusive which if is held, there could be 3 + * NB: when there are more than one lock modes, the mode to return is the 'highest' + * lockmode among them. The main order is: from lowest (most relaxed) to + * highest (most strict): IntentShared < Shared < Update < Exclusive. + * A special case is IntentExclusive which if is held, there could be 3 * different return modes depending on what's the other mode being held: * 1. IntentExclusive + IntentExclusive = IntentExclusive * 2. IntentExclusive + IntentShared = SharedIntentExclusive @@ -786,12 +825,13 @@ sp_releaseapplock_function(PG_FUNCTION_ARGS) Datum APPLOCK_MODE(PG_FUNCTION_ARGS) { - char resource[APPLOCK_MAX_RESOURCE_LENGTH]; - short high_mode, ret_mode; - AppLockCacheEnt *entry; - int64 key; - slist_iter iter; - bool has_intent_exc; + char resource[APPLOCK_MAX_RESOURCE_LENGTH]; + short high_mode, + ret_mode; + AppLockCacheEnt *entry; + int64 key; + slist_iter iter; + bool has_intent_exc; /* Init applock hash table if not yet done. */ if (!appLockCacheLocal) @@ -801,19 +841,21 @@ APPLOCK_MODE(PG_FUNCTION_ARGS) /* If we don't own the lock, just return NoLock */ if ((key = AppLockSearchKeyLocal(resource)) < 0) - PG_RETURN_VARCHAR_P((*common_utility_plugin_ptr->tsql_varchar_input)(AppLockModeStrings[APPLOCKMODE_NOLOCK], - strlen(AppLockModeStrings[APPLOCKMODE_NOLOCK]), - -1)); + PG_RETURN_VARCHAR_P((*common_utility_plugin_ptr->tsql_varchar_input) (AppLockModeStrings[APPLOCKMODE_NOLOCK], + strlen(AppLockModeStrings[APPLOCKMODE_NOLOCK]), + -1)); - /* - * Loop all the lock modes I've owned this resource with, and find the + /* + * Loop all the lock modes I've owned this resource with, and find the * correct string to return. */ AppLockCacheLookup(key, entry); high_mode = APPLOCKMODE_NOLOCK; has_intent_exc = false; - slist_foreach(iter, &entry->mode_head) { + slist_foreach(iter, &entry->mode_head) + { AppLockModeNode *node = slist_container(AppLockModeNode, sn, iter.cur); + if (node->mode == APPLOCKMODE_INTENTEXCLUSIVE) has_intent_exc = true; if (node->mode > high_mode) @@ -826,16 +868,16 @@ APPLOCK_MODE(PG_FUNCTION_ARGS) else ret_mode = high_mode; - PG_RETURN_VARCHAR_P((*common_utility_plugin_ptr->tsql_varchar_input)(AppLockModeStrings[ret_mode], - strlen(AppLockModeStrings[ret_mode]), - -1)); + PG_RETURN_VARCHAR_P((*common_utility_plugin_ptr->tsql_varchar_input) (AppLockModeStrings[ret_mode], + strlen(AppLockModeStrings[ret_mode]), + -1)); } /* - * Test if an applock can be acquired. We took a simple approach where we + * Test if an applock can be acquired. We took a simple approach where we * try aqcuiring the lock and releasing it immediately. - * The alternative is to remember all lockmodes and who owns them in the global - * hashmap, which entails too much of invasiveness and additional shared + * The alternative is to remember all lockmodes and who owns them in the global + * hashmap, which entails too much of invasiveness and additional shared * memory management. * * Returns: @@ -845,8 +887,10 @@ APPLOCK_MODE(PG_FUNCTION_ARGS) Datum APPLOCK_TEST(PG_FUNCTION_ARGS) { - char resource[APPLOCK_MAX_RESOURCE_LENGTH], lockmode[APPLOCK_MAX_LOCKMODE_LENGTH]; - char lockowner[APPLOCK_MAX_LOCKOWNER_LENGTH], dbprincipal[APPLOCK_MAX_DBPRINCIPAL_LENGTH]; + char resource[APPLOCK_MAX_RESOURCE_LENGTH], + lockmode[APPLOCK_MAX_LOCKMODE_LENGTH]; + char lockowner[APPLOCK_MAX_LOCKOWNER_LENGTH], + dbprincipal[APPLOCK_MAX_DBPRINCIPAL_LENGTH]; /* Init applock hash table if not yet done. */ if (!appLockCacheLocal) @@ -860,37 +904,37 @@ APPLOCK_TEST(PG_FUNCTION_ARGS) if (pg_strcasecmp(lockowner, "Transaction") == 0 && !IsTransactionBlockActive()) ereport(ERROR, (errcode(ERRCODE_LOCK_NOT_AVAILABLE), - errmsg("The statement or function must be executed in the context of a user transaction."))); + errmsg("The statement or function must be executed in the context of a user transaction."))); - /* - * Pass the arguments and a time out of 0 (no wait) to the internal + /* + * Pass the arguments and a time out of 0 (no wait) to the internal * getapplock function. Suppress the warning messages as they would be - * normal during testing a lock. If anything happened besides having + * normal during testing a lock. If anything happened besides having * acquired the lock successfully, just return 0. */ if (_sp_getapplock_internal(resource, lockmode, lockowner, 0, dbprincipal, true) != 0) PG_RETURN_INT32(0); - /* + /* * PANIC: we've acquired the lock but can't release it for some reason. - * Unlike previous case, we need to print messages clearly indicating + * Unlike previous case, we need to print messages clearly indicating * such, so user is aware of the dangling lock, and error out to prevent * any inconsistent state. */ if (_sp_releaseapplock_internal(resource, lockowner, dbprincipal, false) != 0) ereport(PANIC, (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("Lock acuiqred during APPLOCK_TEST for resource \'%s\'" - "but couldn't release it.", + errmsg("Lock acuiqred during APPLOCK_TEST for resource \'%s\'" + "but couldn't release it.", resource))); /* Lock can be acquired now. */ PG_RETURN_INT32(1); } -/* +/* * Function to be called by a hook in the backend. - * Remove all hash entries for application locks of either transaction-only + * Remove all hash entries for application locks of either transaction-only * or transaction+session too. * * @release_session: if we remove session locks as well as transaction locks. @@ -901,7 +945,7 @@ ApplockRemoveCache(bool release_session) HASH_SEQ_STATUS hash_seq; AppLockCacheEnt *entry; - /* + /* * If we are not using TSQL dialect or applock cache is not initialized, * don't bother. */ @@ -909,15 +953,16 @@ ApplockRemoveCache(bool release_session) return; hash_seq_init(&hash_seq, appLockCacheLocal); - + while ((entry = hash_seq_search(&hash_seq)) != NULL) { - int i; + int i; + if (!release_session && entry->is_session) continue; /* unreferencing my entries in global hashmap */ - for (i = 0; i < entry->refcount; i++) + for (i = 0; i < entry->refcount; i++) ApplockUnrefGlobalCache(entry->key); /* free allocated space, and the entry itself. */ diff --git a/contrib/babelfishpg_tsql/src/babelfish_version.h b/contrib/babelfishpg_tsql/src/babelfish_version.h index 47e8a69c4d..bbeb7221d0 100644 --- a/contrib/babelfishpg_tsql/src/babelfish_version.h +++ b/contrib/babelfishpg_tsql/src/babelfish_version.h @@ -12,4 +12,3 @@ #define BABELFISH_INTERNAL_VERSION_STR "Babelfish 15.3.0.0" #define BABEL_COMPATIBILITY_VERSION "12.0.2000.8" #define BABEL_COMPATIBILITY_MAJOR_VERSION "12" - diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c index c5c0b5a578..858191bdce 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c @@ -5,7 +5,7 @@ pgtsql_parser_init(base_yy_extra_type *yyext) } static void -pgtsql_base_yyerror(YYLTYPE *yylloc, core_yyscan_t yyscanner, const char *msg) +pgtsql_base_yyerror(YYLTYPE * yylloc, core_yyscan_t yyscanner, const char *msg) { base_yyerror(yylloc, yyscanner, msg); } @@ -13,13 +13,13 @@ pgtsql_base_yyerror(YYLTYPE *yylloc, core_yyscan_t yyscanner, const char *msg) static Node * makeTSQLHexStringConst(char *str, int location) { - A_Const *n = makeNode(A_Const); + A_Const *n = makeNode(A_Const); n->val.sval.type = T_TSQL_HexString; n->val.hsval.hsval = str; n->location = location; - return (Node *)n; + return (Node *) n; } /* TsqlSystemFuncName() @@ -41,54 +41,57 @@ TsqlSystemFuncName2(char *name) } char * -construct_unique_index_name(char *index_name, char *relation_name) { - char md5[MD5_HASH_LEN + 1]; - char buf[2 * NAMEDATALEN + MD5_HASH_LEN + 1]; - char* name; - bool success; - int full_len; - int new_len; - int index_len; - int relation_len; - const char *errstr = NULL; - - if (index_name == NULL || relation_name == NULL) { - return index_name; - } - index_len = strlen(index_name); - relation_len = strlen(relation_name); - - success = pg_md5_hash(index_name, index_len, md5, &errstr); - if (unlikely(!success)) { /* OOM */ - ereport( - ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg( - "constructing unique index name failed: index = \"%s\", relation = \"%s\": %s", - index_name, - relation_name, - errstr - ) - ) - ); - } - - memcpy(buf, index_name, index_len); - memcpy(buf + index_len, relation_name, relation_len); - memcpy(buf + index_len + relation_len, md5, MD5_HASH_LEN + 1); - - full_len = index_len + relation_len + MD5_HASH_LEN; - buf[full_len] = '\0'; - - truncate_identifier(buf, full_len, false); - - new_len = strlen(buf); - Assert(new_len < NAMEDATALEN); /* result new_len is below max */ - - name = palloc(new_len + 1); - memcpy(name, buf, new_len + 1); - - return name; +construct_unique_index_name(char *index_name, char *relation_name) +{ + char md5[MD5_HASH_LEN + 1]; + char buf[2 * NAMEDATALEN + MD5_HASH_LEN + 1]; + char *name; + bool success; + int full_len; + int new_len; + int index_len; + int relation_len; + const char *errstr = NULL; + + if (index_name == NULL || relation_name == NULL) + { + return index_name; + } + index_len = strlen(index_name); + relation_len = strlen(relation_name); + + success = pg_md5_hash(index_name, index_len, md5, &errstr); + if (unlikely(!success)) + { /* OOM */ + ereport( + ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg( + "constructing unique index name failed: index = \"%s\", relation = \"%s\": %s", + index_name, + relation_name, + errstr + ) + ) + ); + } + + memcpy(buf, index_name, index_len); + memcpy(buf + index_len, relation_name, relation_len); + memcpy(buf + index_len + relation_len, md5, MD5_HASH_LEN + 1); + + full_len = index_len + relation_len + MD5_HASH_LEN; + buf[full_len] = '\0'; + + truncate_identifier(buf, full_len, false); + + new_len = strlen(buf); + Assert(new_len < NAMEDATALEN); /* result new_len is below max */ + + name = palloc(new_len + 1); + memcpy(name, buf, new_len + 1); + + return name; } /* @@ -99,7 +102,7 @@ construct_unique_index_name(char *index_name, char *relation_name) { static RangeVar * makeRangeVarFromAnyNameForTableType(List *names, int position, core_yyscan_t yyscanner) { - RangeVar *r = makeNode(RangeVar); + RangeVar *r = makeNode(RangeVar); switch (list_length(names)) { @@ -129,21 +132,23 @@ makeRangeVarFromAnyNameForTableType(List *names, int position, core_yyscan_t yys } Node -*TsqlFunctionChoose(Node *int_expr, List *choosable, int location) + * +TsqlFunctionChoose(Node *int_expr, List *choosable, int location) { - CaseExpr *c = makeNode(CaseExpr); - ListCell *lc; - int i = 1; + CaseExpr *c = makeNode(CaseExpr); + ListCell *lc; + int i = 1; TSQLInstrumentation(INSTR_TSQL_FUNCTION_CHOOSE); if (choosable == NIL) elog(ERROR, - "Function 'choose' requires at least 2 argument(s)"); + "Function 'choose' requires at least 2 argument(s)"); foreach(lc, choosable) { - CaseWhen *w = makeNode(CaseWhen); + CaseWhen *w = makeNode(CaseWhen); + w->expr = (Expr *) makeIntConst(i, location); w->result = (Expr *) lfirst(lc); w->location = location; @@ -168,18 +173,19 @@ Node Node * TsqlFunctionConvert(TypeName *typename, Node *arg, Node *style, bool try, int location) { - Node *result; - List *args; - int32 typmod; - Oid type_oid; - char *typename_string; - - /* For handling try boolean logic on babelfishpg_tsql side */ - Node *try_const = makeBoolAConst(try, location); - if (style) + Node *result; + List *args; + int32 typmod; + Oid type_oid; + char *typename_string; + + /* For handling try boolean logic on babelfishpg_tsql side */ + Node *try_const = makeBoolAConst(try, location); + + if (style) args = list_make3(arg, try_const, style); - else - args = list_make2(arg, try_const); + else + args = list_make2(arg, try_const); typenameTypeIdAndMod(NULL, typename, &type_oid, &typmod); typename_string = TypeNameToString(typename); @@ -187,32 +193,39 @@ TsqlFunctionConvert(TypeName *typename, Node *arg, Node *style, bool try, int lo TSQLInstrumentation(INSTR_TSQL_FUNCTION_CONVERT); if (type_oid == DATEOID) - result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_conv_helper_to_date"), args, COERCE_EXPLICIT_CALL, location); + result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_conv_helper_to_date"), args, COERCE_EXPLICIT_CALL, location); + else if (type_oid == TIMEOID) - result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_conv_helper_to_time"), args, COERCE_EXPLICIT_CALL, location); + result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_conv_helper_to_time"), args, COERCE_EXPLICIT_CALL, location); + else if (type_oid == typenameTypeId(NULL, makeTypeName("datetime"))) - result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_conv_helper_to_datetime"), args, COERCE_EXPLICIT_CALL, location); + result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_conv_helper_to_datetime"), args, COERCE_EXPLICIT_CALL, location); + else if (strcmp(typename_string, "varchar") == 0) { - Node *helperFuncCall; + Node *helperFuncCall; - typename_string = format_type_extended(VARCHAROID, typmod, FORMAT_TYPE_TYPEMOD_GIVEN); - args = lcons(makeStringConst(typename_string, typename->location), args); - helperFuncCall = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_conv_helper_to_varchar"), args, COERCE_EXPLICIT_CALL, location); - /* BABEL-1661, add a type cast on top of the CONVERT helper function so typmod can be applied */ + typename_string = format_type_extended(VARCHAROID, typmod, FORMAT_TYPE_TYPEMOD_GIVEN); + args = lcons(makeStringConst(typename_string, typename->location), args); + helperFuncCall = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_conv_helper_to_varchar"), args, COERCE_EXPLICIT_CALL, location); + + /* + * BABEL-1661, add a type cast on top of the CONVERT helper function + * so typmod can be applied + */ result = makeTypeCast(helperFuncCall, typename, location); - } + } else - { - if (try) - { + { + if (try) + { result = TsqlFunctionTryCast(arg, typename, location); - } - else - { + } + else + { result = makeTypeCast(arg, typename, location); - } - } + } + } return result; } @@ -226,39 +239,45 @@ TsqlFunctionConvert(TypeName *typename, Node *arg, Node *style, bool try, int lo Node * TsqlFunctionParse(Node *arg, TypeName *typename, Node *culture, bool try, int location) { - Node *result; - List *args; - int32 typmod; - Oid type_oid; - - /* So far only date, time, and datetime need try_const and culture if not null since - * only they have specialized functions implemented in PG TSQL. - */ - Node *try_const = makeBoolAConst(try, location); - if (culture) - args = list_make3(arg, try_const, culture); - else - args = list_make2(arg, try_const); - - typenameTypeIdAndMod(NULL, typename, &type_oid, &typmod); - - TSQLInstrumentation(INSTR_TSQL_FUNCTION_PARSE); - - if (type_oid == DATEOID) - result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_parse_helper_to_date"), args, COERCE_EXPLICIT_CALL, location); - else if (type_oid == TIMEOID) - result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_parse_helper_to_time"), args, COERCE_EXPLICIT_CALL, location); - else if (type_oid == typenameTypeId(NULL, makeTypeName("datetime"))) - result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_parse_helper_to_datetime"), args, COERCE_EXPLICIT_CALL, location); - else - { - if (try) - result = TsqlFunctionTryCast(arg, typename, location); - else - result = makeTypeCast(arg, typename, location); - } - - return result; + Node *result; + List *args; + int32 typmod; + Oid type_oid; + + /* + * So far only date, time, and datetime need try_const and culture if not + * null since only they have specialized functions implemented in PG TSQL. + */ + Node *try_const = makeBoolAConst(try, location); + + if (culture) + args = list_make3(arg, try_const, culture); + else + args = list_make2(arg, try_const); + + typenameTypeIdAndMod(NULL, typename, &type_oid, &typmod); + + TSQLInstrumentation(INSTR_TSQL_FUNCTION_PARSE); + + if (type_oid == DATEOID) + result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_parse_helper_to_date"), args, COERCE_EXPLICIT_CALL, location); + + else if (type_oid == TIMEOID) + result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_parse_helper_to_time"), args, COERCE_EXPLICIT_CALL, location); + + else if (type_oid == typenameTypeId(NULL, makeTypeName("datetime"))) + result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_parse_helper_to_datetime"), args, COERCE_EXPLICIT_CALL, location); + + else + { + if (try) + result = TsqlFunctionTryCast(arg, typename, location); + + else + result = makeTypeCast(arg, typename, location); + } + + return result; } /* TsqlFunctionTryCast -- Implements the TRY_CAST function. @@ -269,65 +288,72 @@ TsqlFunctionParse(Node *arg, TypeName *typename, Node *culture, bool try, int lo Node * TsqlFunctionTryCast(Node *arg, TypeName *typename, int location) { - Node *result; - int32 typmod; - Oid type_oid; - - typenameTypeIdAndMod(NULL, typename, &type_oid, &typmod); - - TSQLInstrumentation(INSTR_TSQL_FUNCTION_TRY_CAST); - - /* Going case-by-case since it seems we cannot define a wrapper try_cast function that takes in an - * arg of any type and returns any type. Can reduce cases to handle by having a generic cast at the end - * that casts the arg to TEXT then casts to the target type. Works for most cases but not all such as casting - * float to int. - */ - if (type_oid == INT2OID) - result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_try_cast_floor_smallint"), list_make1(arg), COERCE_EXPLICIT_CALL, location); - else if (type_oid == INT4OID) - result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_try_cast_floor_int"), list_make1(arg), COERCE_EXPLICIT_CALL, location); - else if (type_oid == INT8OID) - result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_try_cast_floor_bigint"), list_make1(arg), COERCE_EXPLICIT_CALL, location); - else if (type_oid == typenameTypeId(NULL, makeTypeName("datetime2"))) - { + Node *result; + int32 typmod; + Oid type_oid; + + typenameTypeIdAndMod(NULL, typename, &type_oid, &typmod); + + TSQLInstrumentation(INSTR_TSQL_FUNCTION_TRY_CAST); + + /* + * Going case-by-case since it seems we cannot define a wrapper try_cast + * function that takes in an arg of any type and returns any type. Can + * reduce cases to handle by having a generic cast at the end that casts + * the arg to TEXT then casts to the target type. Works for most cases but + * not all such as casting float to int. + */ + if (type_oid == INT2OID) + result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_try_cast_floor_smallint"), list_make1(arg), COERCE_EXPLICIT_CALL, location); + + else if (type_oid == INT4OID) + result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_try_cast_floor_int"), list_make1(arg), COERCE_EXPLICIT_CALL, location); + + else if (type_oid == INT8OID) + result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_try_cast_floor_bigint"), list_make1(arg), COERCE_EXPLICIT_CALL, location); + + else if (type_oid == typenameTypeId(NULL, makeTypeName("datetime2"))) + { /* - * Handles null typmod case. typmod is set to 6 because that is the current max precision for datetime2 - * Update to 7 when BABEL-2934 is reolved + * Handles null typmod case. typmod is set to 6 because that is the + * current max precision for datetime2 Update to 7 when BABEL-2934 is + * reolved */ - if(typmod < 0) - typmod = 6; - - result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_try_cast_to_datetime2"), list_make2(arg, makeIntConst(typmod, location)), COERCE_EXPLICIT_CALL, location); - } - else - { - Node *targetType = makeTypeCast(makeNullAConst(location), typename, location); - List *args; - switch(arg->type) - { - case T_A_Const: - case T_TypeCast: - case T_FuncCall: - case T_A_Expr: - args = list_make3(arg, targetType, makeIntConst(typmod, location)); - break; - default: - args = list_make3(makeTypeCast(arg, makeTypeName("text"), location), targetType, makeIntConst(typmod, location)); - } - - result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_try_cast_to_any"), args, COERCE_EXPLICIT_CALL, location); - } - - return result; + if (typmod < 0) + typmod = 6; + + result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_try_cast_to_datetime2"), list_make2(arg, makeIntConst(typmod, location)), COERCE_EXPLICIT_CALL, location); + } + else + { + Node *targetType = makeTypeCast(makeNullAConst(location), typename, location); + List *args; + + switch (arg->type) + { + case T_A_Const: + case T_TypeCast: + case T_FuncCall: + case T_A_Expr: + args = list_make3(arg, targetType, makeIntConst(typmod, location)); + break; + default: + args = list_make3(makeTypeCast(arg, makeTypeName("text"), location), targetType, makeIntConst(typmod, location)); + } + + result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_try_cast_to_any"), args, COERCE_EXPLICIT_CALL, location); + } + + return result; } Node * TsqlFunctionIIF(Node *bool_expr, Node *arg1, Node *arg2, int location) { - CaseExpr *c = makeNode(CaseExpr); - CaseWhen *w = makeNode(CaseWhen); + CaseExpr *c = makeNode(CaseExpr); + CaseWhen *w = makeNode(CaseWhen); - TSQLInstrumentation(INSTR_TSQL_FUNCTION_IIF); + TSQLInstrumentation(INSTR_TSQL_FUNCTION_IIF); w->expr = (Expr *) bool_expr; w->result = (Expr *) arg1; @@ -355,7 +381,7 @@ TsqlFunctionIIF(Node *bool_expr, Node *arg1, Node *arg2, int location) static void tsql_check_param_readonly(const char *paramname, TypeName *typename, bool readonly) { - TypeName *typeclone = copyObjectImpl(typename); + TypeName *typeclone = copyObjectImpl(typename); /* work on the cloned object to avoid double rewriting */ rewrite_plain_name(typeclone->names); @@ -382,18 +408,19 @@ tsql_check_param_readonly(const char *paramname, TypeName *typename, bool readon * calls the openjson_simple function */ Node * -TsqlOpenJSONSimpleMakeFuncCall(Node* jsonExpr, Node* path) +TsqlOpenJSONSimpleMakeFuncCall(Node *jsonExpr, Node *path) { - FuncCall *fc; - if(path) - { - fc = makeFuncCall(TsqlSystemFuncName("openjson_simple"), list_make2(jsonExpr, path), COERCE_EXPLICIT_CALL, -1); - } - else - { - fc = makeFuncCall(TsqlSystemFuncName("openjson_simple"), list_make1(jsonExpr), COERCE_EXPLICIT_CALL, -1); - } - return (Node*) fc; + FuncCall *fc; + + if (path) + { + fc = makeFuncCall(TsqlSystemFuncName("openjson_simple"), list_make2(jsonExpr, path), COERCE_EXPLICIT_CALL, -1); + } + else + { + fc = makeFuncCall(TsqlSystemFuncName("openjson_simple"), list_make1(jsonExpr), COERCE_EXPLICIT_CALL, -1); + } + return (Node *) fc; } /* @@ -402,67 +429,72 @@ TsqlOpenJSONSimpleMakeFuncCall(Node* jsonExpr, Node* path) * assembling the function arguments, column definitions list, and alias */ Node * -TsqlOpenJSONWithMakeFuncCall(Node* jsonExpr, Node* path, List* cols, Alias* alias) +TsqlOpenJSONWithMakeFuncCall(Node *jsonExpr, Node *path, List *cols, Alias *alias) { - FuncCall *fc; - List *jsonWithParams = list_make2(jsonExpr, path); - ListCell *lc; - RangeFunction *rf = makeNode(RangeFunction); - Alias *a = makeNode(Alias); - a->aliasname = alias != NULL ? alias->aliasname : "f"; - - foreach(lc, cols) - { - OpenJson_Col_Def *cd = (OpenJson_Col_Def*) lfirst(lc); - int initialTmod = getElemTypMod(cd->elemType); - char* typeNameString = TypeNameToString(cd->elemType); - ColumnDef *n = (ColumnDef *) createOpenJsonWithColDef(cd->elemName, cd->elemType); - StringInfo format_cols = makeStringInfo(); - - if(strcmp(cd->elemPath, "") == 0) - { - // If not path is provided with use the standard path [$.columnName] - appendStringInfo(format_cols, "$.%s ", cd->elemName); - } - else - { - appendStringInfo(format_cols, "%s ", cd->elemPath); - } - - // character types need to have the typmod appended to them - if(isCharType(typeNameString)) - { - int newTypMod = getElemTypMod(n->typeName); - appendStringInfo(format_cols, "%s(%d)", typeNameString, newTypMod); - } - else - { - appendStringInfoString(format_cols, typeNameString); - } - - if(cd->asJson) - { - if(isNVarCharType(typeNameString) && initialTmod == TSQLMaxTypmod) - { - appendStringInfoString(format_cols, " AS JSON"); - } - else - { - // AS JSON can only be used with nvarchar(max) - ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("AS JSON in WITH clause can only be specified for column of type nvarchar(max)"))); - } - - } - - jsonWithParams = lappend(jsonWithParams, makeStringConst(format_cols->data, -1)); - rf->coldeflist = lappend(rf->coldeflist, n); - } - - fc = makeFuncCall(TsqlSystemFuncName("openjson_with"), jsonWithParams, COERCE_EXPLICIT_CALL, -1); - rf->functions = list_make1(list_make2(fc, NULL)); - rf->alias = alias; - return (Node*) rf; + FuncCall *fc; + List *jsonWithParams = list_make2(jsonExpr, path); + ListCell *lc; + RangeFunction *rf = makeNode(RangeFunction); + Alias *a = makeNode(Alias); + + a->aliasname = alias != NULL ? alias->aliasname : "f"; + + foreach(lc, cols) + { + OpenJson_Col_Def *cd = (OpenJson_Col_Def *) lfirst(lc); + int initialTmod = getElemTypMod(cd->elemType); + char *typeNameString = TypeNameToString(cd->elemType); + ColumnDef *n = (ColumnDef *) createOpenJsonWithColDef(cd->elemName, cd->elemType); + StringInfo format_cols = makeStringInfo(); + + if (strcmp(cd->elemPath, "") == 0) + { + /* + * If not path is provided with use the standard path + * [$.columnName] + */ + appendStringInfo(format_cols, "$.%s ", cd->elemName); + } + else + { + appendStringInfo(format_cols, "%s ", cd->elemPath); + } + + /* character types need to have the typmod appended to them */ + if (isCharType(typeNameString)) + { + int newTypMod = getElemTypMod(n->typeName); + + appendStringInfo(format_cols, "%s(%d)", typeNameString, newTypMod); + } + else + { + appendStringInfoString(format_cols, typeNameString); + } + + if (cd->asJson) + { + if (isNVarCharType(typeNameString) && initialTmod == TSQLMaxTypmod) + { + appendStringInfoString(format_cols, " AS JSON"); + } + else + { + /* AS JSON can only be used with nvarchar(max) */ + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("AS JSON in WITH clause can only be specified for column of type nvarchar(max)"))); + } + + } + + jsonWithParams = lappend(jsonWithParams, makeStringConst(format_cols->data, -1)); + rf->coldeflist = lappend(rf->coldeflist, n); + } + + fc = makeFuncCall(TsqlSystemFuncName("openjson_with"), jsonWithParams, COERCE_EXPLICIT_CALL, -1); + rf->functions = list_make1(list_make2(fc, NULL)); + rf->alias = alias; + return (Node *) rf; } /* @@ -470,124 +502,131 @@ TsqlOpenJSONWithMakeFuncCall(Node* jsonExpr, Node* path, List* cols, Alias* alia * If the column type is a character type, we need to change the underlying typmod */ Node * -createOpenJsonWithColDef(char* elemName, TypeName* elemType) +createOpenJsonWithColDef(char *elemName, TypeName *elemType) { - ColumnDef *n = makeNode(ColumnDef); - char* typeNameString = TypeNameToString(elemType); - n->colname = elemName; - if(isCharType(typeNameString)) - { - n->typeName = setCharTypmodForOpenjson(elemType); - } - else - { - n->typeName = elemType; - } - n->inhcount = 0; - n->is_local = true; - n->is_not_null = false; - n->is_from_type = false; - n->storage = 0; - n->raw_default = NULL; - n->cooked_default = NULL; - n->collOid = InvalidOid; - n->constraints = NIL; - n->location = -1; - return (Node*) n; + ColumnDef *n = makeNode(ColumnDef); + char *typeNameString = TypeNameToString(elemType); + + n->colname = elemName; + if (isCharType(typeNameString)) + { + n->typeName = setCharTypmodForOpenjson(elemType); + } + else + { + n->typeName = elemType; + } + n->inhcount = 0; + n->is_local = true; + n->is_not_null = false; + n->is_from_type = false; + n->storage = 0; + n->raw_default = NULL; + n->cooked_default = NULL; + n->collOid = InvalidOid; + n->constraints = NIL; + n->location = -1; + return (Node *) n; } TypeName * setCharTypmodForOpenjson(TypeName *t) { - int curTMod = getElemTypMod(t); - List *tmods = (List*) t->typmods; - if(tmods == NULL) - { - // Default value when no typmod is provided is 1 - t->typmods = list_make1(makeIntConst(1, -1)); - return t; - } - else if(curTMod == TSQLMaxTypmod) - { - // TSQLMaxTypmod is represented as -8000 so we need to change to - // the actual max value of 4000 - t->typmods = list_make1(makeIntConst(4000, -1)); - return t; - } - else - { - return t; - } + int curTMod = getElemTypMod(t); + List *tmods = (List *) t->typmods; + + if (tmods == NULL) + { + /* Default value when no typmod is provided is 1 */ + t->typmods = list_make1(makeIntConst(1, -1)); + return t; + } + else if (curTMod == TSQLMaxTypmod) + { + /* TSQLMaxTypmod is represented as -8000 so we need to change to */ + /* the actual max value of 4000 */ + t->typmods = list_make1(makeIntConst(4000, -1)); + return t; + } + else + { + return t; + } } -bool isCharType(char* typenameStr) +bool +isCharType(char *typenameStr) { - if(pg_strcasecmp(typenameStr, "char") == 0) - { - return true; - } - else if(pg_strcasecmp(typenameStr, "nchar") == 0) - { - return true; - } - else if(pg_strcasecmp(typenameStr, "varchar") == 0) - { - return true; - } - else if(pg_strcasecmp(typenameStr, "pg_catalog.char") == 0) - { - return true; - } - else if(pg_strcasecmp(typenameStr, "pg_catalog.varchar") == 0) - { - return true; - } - else if(pg_strcasecmp(typenameStr, "sys.char") == 0) - { - return true; - } - else if(pg_strcasecmp(typenameStr, "sys.nchar") == 0) - { - return true; - } - else if(pg_strcasecmp(typenameStr, "sys.varchar") == 0) - { - return true; - } - else if(isNVarCharType(typenameStr)) - { - return true; - } - return false; + if (pg_strcasecmp(typenameStr, "char") == 0) + { + return true; + } + else if (pg_strcasecmp(typenameStr, "nchar") == 0) + { + return true; + } + else if (pg_strcasecmp(typenameStr, "varchar") == 0) + { + return true; + } + else if (pg_strcasecmp(typenameStr, "pg_catalog.char") == 0) + { + return true; + } + else if (pg_strcasecmp(typenameStr, "pg_catalog.varchar") == 0) + { + return true; + } + else if (pg_strcasecmp(typenameStr, "sys.char") == 0) + { + return true; + } + else if (pg_strcasecmp(typenameStr, "sys.nchar") == 0) + { + return true; + } + else if (pg_strcasecmp(typenameStr, "sys.varchar") == 0) + { + return true; + } + else if (isNVarCharType(typenameStr)) + { + return true; + } + return false; } -bool isNVarCharType(char* typenameStr) +bool +isNVarCharType(char *typenameStr) { - if(pg_strcasecmp(typenameStr, "nvarchar") == 0) - { - return true; - } - else if(pg_strcasecmp(typenameStr, "sys.nvarchar") == 0) - { - return true; - } - return false; + if (pg_strcasecmp(typenameStr, "nvarchar") == 0) + { + return true; + } + else if (pg_strcasecmp(typenameStr, "sys.nvarchar") == 0) + { + return true; + } + return false; } -int getElemTypMod(TypeName *t) +int +getElemTypMod(TypeName *t) { - List *tmods = (List*) t->typmods; - if(tmods == NULL) - { - return 1; - } - else - { - ListCell *elems = (ListCell*) tmods->elements; - A_Expr *expr = (A_Expr*) lfirst(elems); - A_Const *constVal = (A_Const*) expr; - return constVal->val.ival.ival; - } + List *tmods = (List *) t->typmods; + + if (tmods == NULL) + { + return 1; + } + else + { + ListCell *elems = (ListCell *) tmods->elements; + A_Expr *expr = (A_Expr *) lfirst(elems); + A_Const *constVal = (A_Const *) expr; + + return constVal->val.ival.ival; + } } /* @@ -595,18 +634,19 @@ int getElemTypMod(TypeName *t) * a json_modify or json_query function call. If it is one of these two arguments it * sets the escape parameter to true */ -Node* -TsqlJsonModifyMakeFuncCall(Node* expr, Node* path, Node* newValue) +Node * +TsqlJsonModifyMakeFuncCall(Node *expr, Node *path, Node *newValue) { - FuncCall* fc; - FuncCall* fc_newval; - List* func_args = list_make2(expr, path); - bool escape = false; - switch(newValue->type) + FuncCall *fc; + FuncCall *fc_newval; + List *func_args = list_make2(expr, path); + bool escape = false; + + switch (newValue->type) { case T_FuncCall: - fc_newval = (FuncCall*) newValue; - if(is_json_modify(fc_newval->funcname) || is_json_query(fc_newval->funcname)) + fc_newval = (FuncCall *) newValue; + if (is_json_modify(fc_newval->funcname) || is_json_query(fc_newval->funcname)) { escape = true; } @@ -621,33 +661,35 @@ TsqlJsonModifyMakeFuncCall(Node* expr, Node* path, Node* newValue) } func_args = lappend(func_args, makeBoolAConst(escape, -1)); fc = makeFuncCall(TsqlSystemFuncName("json_modify"), func_args, COERCE_EXPLICIT_CALL, -1); - return (Node*) fc; + return (Node *) fc; } bool is_json_query(List *name) { - switch(list_length(name)) - { - case 1: - { - Node *func = (Node *) linitial(name); - if(strncmp("json_query", strVal(func), 10) == 0) - return true; - return false; - } - case 2: - { - Node *schema = (Node *) linitial(name); - Node *func = (Node *) lsecond(name); - if(strncmp("sys", strVal(schema), 3) == 0 && - strncmp("json_query", strVal(func), 10) == 0) - return true; - return false; - } - default: - return false; - } + switch (list_length(name)) + { + case 1: + { + Node *func = (Node *) linitial(name); + + if (strncmp("json_query", strVal(func), 10) == 0) + return true; + return false; + } + case 2: + { + Node *schema = (Node *) linitial(name); + Node *func = (Node *) lsecond(name); + + if (strncmp("sys", strVal(schema), 3) == 0 && + strncmp("json_query", strVal(func), 10) == 0) + return true; + return false; + } + default: + return false; + } } /* @@ -664,53 +706,54 @@ is_json_query(List *name) strcmp(l->catalogname, r->relation->catalogname) == 0))) static Node * -tsql_update_delete_stmt_with_join(Node *n, List* from_clause, Node* - where_clause, Node *top_clause, +tsql_update_delete_stmt_with_join(Node *n, List *from_clause, Node *where_clause, Node *top_clause, RangeVar *relation, core_yyscan_t yyscanner) { - DeleteStmt* n_d = NULL; - UpdateStmt* n_u = NULL; - RangeVar* target_table = NULL; - RangeVar* larg = NULL; - RangeVar* rarg = NULL; - JoinExpr* jexpr = linitial(from_clause); - SubLink * link; - List* indirect; + DeleteStmt *n_d = NULL; + UpdateStmt *n_u = NULL; + RangeVar *target_table = NULL; + RangeVar *larg = NULL; + RangeVar *rarg = NULL; + JoinExpr *jexpr = linitial(from_clause); + SubLink *link; + List *indirect; SelectStmt *selectstmt; - ResTarget *resTarget; + ResTarget *resTarget; + /* use queue to go over all join expr and find target table */ - List* queue = list_make1(jexpr); + List *queue = list_make1(jexpr); ListCell *queue_item; - if(IsA(n, DeleteStmt)) - n_d = (DeleteStmt*)n; + + if (IsA(n, DeleteStmt)) + n_d = (DeleteStmt *) n; else - n_u = (UpdateStmt*)n; + n_u = (UpdateStmt *) n; foreach(queue_item, queue) { - jexpr = (JoinExpr*)lfirst(queue_item); - if(IsA(jexpr->larg, JoinExpr)) + jexpr = (JoinExpr *) lfirst(queue_item); + if (IsA(jexpr->larg, JoinExpr)) { queue = lappend(queue, jexpr->larg); } - else if(IsA(jexpr->larg, RangeVar)) + else if (IsA(jexpr->larg, RangeVar)) { - larg = (RangeVar*)(jexpr->larg); + larg = (RangeVar *) (jexpr->larg); } - if(IsA(jexpr->rarg, JoinExpr)) + if (IsA(jexpr->rarg, JoinExpr)) { queue = lappend(queue, jexpr->rarg); } - else if(IsA(jexpr->rarg, RangeVar)) + else if (IsA(jexpr->rarg, RangeVar)) { - rarg = (RangeVar*)(jexpr->rarg); + rarg = (RangeVar *) (jexpr->rarg); } - if(larg && (TSQL_COMP_REL_NAME(larg,n_d) || TSQL_COMP_REL_NAME(larg,n_u))) + if (larg && (TSQL_COMP_REL_NAME(larg, n_d) || TSQL_COMP_REL_NAME(larg, n_u))) { target_table = larg; break; } - if(rarg && (TSQL_COMP_REL_NAME(rarg,n_d) || TSQL_COMP_REL_NAME(rarg,n_u))) + if (rarg && (TSQL_COMP_REL_NAME(rarg, n_d) || TSQL_COMP_REL_NAME(rarg, n_u))) { target_table = rarg; break; @@ -718,29 +761,30 @@ tsql_update_delete_stmt_with_join(Node *n, List* from_clause, Node* larg = NULL; rarg = NULL; } - /* if target table doesn't show in JoinExpr, - * it indicates delete/update the whole table - * the original statement doesn't need to be changed + + /* + * if target table doesn't show in JoinExpr, it indicates delete/update + * the whole table the original statement doesn't need to be changed */ - if(!target_table) + if (!target_table) { /* - * if we don't end up creating a subquery for JOIN, deal with TOP clause - * separately as it might require a subquery. + * if we don't end up creating a subquery for JOIN, deal with TOP + * clause separately as it might require a subquery. */ - if(n_d) + if (n_d) { - n_d -> usingClause = from_clause; - n_d -> whereClause = tsql_update_delete_stmt_with_top(top_clause, - relation, where_clause, yyscanner); - return (Node*)n_d; + n_d->usingClause = from_clause; + n_d->whereClause = tsql_update_delete_stmt_with_top(top_clause, + relation, where_clause, yyscanner); + return (Node *) n_d; } else { - n_u -> fromClause = from_clause; - n_u -> whereClause = tsql_update_delete_stmt_with_top(top_clause, - relation, where_clause, yyscanner); - return (Node*)n_u; + n_u->fromClause = from_clause; + n_u->whereClause = tsql_update_delete_stmt_with_top(top_clause, + relation, where_clause, yyscanner); + return (Node *) n_u; } } /* construct select statment->target */ @@ -748,15 +792,15 @@ tsql_update_delete_stmt_with_join(Node *n, List* from_clause, Node* resTarget->name = NULL; resTarget->indirection = NIL; indirect = list_make1((Node *) makeString("ctid")); - if(target_table->alias) + if (target_table->alias) { resTarget->val = makeColumnRef(target_table->alias->aliasname, - indirect,-1,yyscanner); + indirect, -1, yyscanner); } else { resTarget->val = makeColumnRef(target_table->relname, - indirect,-1,yyscanner); + indirect, -1, yyscanner); } selectstmt = makeNode(SelectStmt); @@ -768,23 +812,23 @@ tsql_update_delete_stmt_with_join(Node *n, List* from_clause, Node* selectstmt->limitCount = top_clause; /* construct where_clause(subLink) */ link = makeNode(SubLink); - link->subselect = (Node*)selectstmt; + link->subselect = (Node *) selectstmt; link->subLinkType = ANY_SUBLINK; link->subLinkId = 0; - link->testexpr = (Node*)makeColumnRef(pstrdup("ctid"), - NIL, -1, yyscanner);; + link->testexpr = (Node *) makeColumnRef(pstrdup("ctid"), + NIL, -1, yyscanner);; link->operName = NIL; /* show it's IN not = ANY */ link->location = -1; - if(n_d) + if (n_d) { - n_d->whereClause = (Node*)link; - return (Node*)n_d; + n_d->whereClause = (Node *) link; + return (Node *) n_d; } else { - n_u->whereClause = (Node*)link; - return (Node*)n_u; + n_u->whereClause = (Node *) link; + return (Node *) n_u; } } @@ -802,10 +846,10 @@ static Node * tsql_update_delete_stmt_with_top(Node *top_clause, RangeVar *relation, Node *where_clause, core_yyscan_t yyscanner) { - SubLink * link; - List* indirect; + SubLink *link; + List *indirect; SelectStmt *selectstmt; - ResTarget *resTarget; + ResTarget *resTarget; if (top_clause == NULL) return where_clause; @@ -815,15 +859,15 @@ tsql_update_delete_stmt_with_top(Node *top_clause, RangeVar *relation, Node resTarget->name = NULL; resTarget->indirection = NIL; indirect = list_make1((Node *) makeString("ctid")); - if(relation->alias) + if (relation->alias) { resTarget->val = makeColumnRef(relation->alias->aliasname, - indirect,-1,yyscanner); + indirect, -1, yyscanner); } else { resTarget->val = makeColumnRef(relation->relname, - indirect,-1,yyscanner); + indirect, -1, yyscanner); } /* construct select statement */ @@ -835,15 +879,15 @@ tsql_update_delete_stmt_with_top(Node *top_clause, RangeVar *relation, Node /* construct where_clause(subLink) */ link = makeNode(SubLink); - link->subselect = (Node*)selectstmt; + link->subselect = (Node *) selectstmt; link->subLinkType = ANY_SUBLINK; link->subLinkId = 0; - link->testexpr = (Node*)makeColumnRef(pstrdup("ctid"), - NIL, -1, yyscanner);; + link->testexpr = (Node *) makeColumnRef(pstrdup("ctid"), + NIL, -1, yyscanner);; link->operName = NIL; /* show it's IN not = ANY */ link->location = -1; - return (Node *)link; + return (Node *) link; } /* @@ -851,29 +895,30 @@ tsql_update_delete_stmt_with_top(Node *top_clause, RangeVar *relation, Node * tsql_update_delete_stmt_from_clause_alias */ static void -tsql_update_delete_stmt_from_clause_alias_helper(RangeVar *relation,RangeVar *rv) -{ +tsql_update_delete_stmt_from_clause_alias_helper(RangeVar *relation, RangeVar *rv) +{ if (rv->alias && rv->alias->aliasname && - strcmp(rv->alias->aliasname, relation->relname) == 0) + strcmp(rv->alias->aliasname, relation->relname) == 0) { if (relation->schemaname) { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("The correlation name \'%s\' has the same exposed name as table \'%s.%s\'.", + errmsg("The correlation name \'%s\' has the same exposed name as table \'%s.%s\'.", rv->alias->aliasname, relation->schemaname, relation->relname))); } + /* - * Save the original alias name so that "inserted" and - * "deleted" tables in OUTPUT clause can be linked to it - */ + * Save the original alias name so that "inserted" and "deleted" + * tables in OUTPUT clause can be linked to it + */ update_delete_target_alias = relation->relname; /* - * Update the relation to have the real table name as - * relname, and the original alias name as an alias - */ + * Update the relation to have the real table name as relname, and the + * original alias name as an alias + */ relation->catalogname = rv->catalogname; relation->schemaname = rv->schemaname; relation->relname = rv->relname; @@ -882,10 +927,9 @@ tsql_update_delete_stmt_from_clause_alias_helper(RangeVar *relation,RangeVar *rv relation->alias = rv->alias; /* - * To avoid alias collision, remove the alias of the table - * in the FROM clause, because it will already be an alias - * of the target relation - */ + * To avoid alias collision, remove the alias of the table in the FROM + * clause, because it will already be an alias of the target relation + */ rv->alias = NULL; } } @@ -893,54 +937,59 @@ tsql_update_delete_stmt_from_clause_alias_helper(RangeVar *relation,RangeVar *rv static void tsql_update_delete_stmt_from_clause_alias(RangeVar *relation, List *from_clause) { - ListCell *lc; + ListCell *lc; + foreach(lc, from_clause) { - Node *n = lfirst(lc); + Node *n = lfirst(lc); + if (IsA(n, RangeVar)) { - RangeVar *rv = (RangeVar *) n; - tsql_update_delete_stmt_from_clause_alias_helper(relation,rv); + RangeVar *rv = (RangeVar *) n; + + tsql_update_delete_stmt_from_clause_alias_helper(relation, rv); } else if (IsA(n, JoinExpr)) { - JoinExpr *jexpr = (JoinExpr *) n; - if(IsA(jexpr->larg, RangeVar)) + JoinExpr *jexpr = (JoinExpr *) n; + + if (IsA(jexpr->larg, RangeVar)) { - tsql_update_delete_stmt_from_clause_alias_helper(relation,(RangeVar*)(jexpr->larg)); + tsql_update_delete_stmt_from_clause_alias_helper(relation, (RangeVar *) (jexpr->larg)); } - if(IsA(jexpr->rarg, RangeVar)) + if (IsA(jexpr->rarg, RangeVar)) { - tsql_update_delete_stmt_from_clause_alias_helper(relation,(RangeVar*)(jexpr->rarg)); - } + tsql_update_delete_stmt_from_clause_alias_helper(relation, (RangeVar *) (jexpr->rarg)); + } } } } -static Node * -tsql_insert_output_into_cte_transformation(WithClause *opt_with_clause, RangeVar *insert_target, - List *insert_column_list, List *tsql_output_clause, RangeVar *output_target, List *tsql_output_into_target_columns, - InsertStmt *tsql_output_insert_rest, int select_location) +static Node * +tsql_insert_output_into_cte_transformation(WithClause *opt_with_clause, RangeVar *insert_target, + List *insert_column_list, List *tsql_output_clause, RangeVar *output_target, List *tsql_output_into_target_columns, + InsertStmt *tsql_output_insert_rest, int select_location) { - + CommonTableExpr *cte = makeNode(CommonTableExpr); WithClause *w = makeNode(WithClause); SelectStmt *n = makeNode(SelectStmt); InsertStmt *i = makeNode(InsertStmt); - char* internal_ctename = NULL; - char ctename[NAMEDATALEN]; - ListCell *expr; - char col_alias_arr[NAMEDATALEN]; - char *col_alias = NULL; - List *output_list = NIL, *queue = NIL; - ListCell *lc; - Node *field1; - char *qualifier = NULL; - - snprintf(ctename, NAMEDATALEN, "internal_output_cte##sys_gen##%p", (void*) i); + char *internal_ctename = NULL; + char ctename[NAMEDATALEN]; + ListCell *expr; + char col_alias_arr[NAMEDATALEN]; + char *col_alias = NULL; + List *output_list = NIL, + *queue = NIL; + ListCell *lc; + Node *field1; + char *qualifier = NULL; + + snprintf(ctename, NAMEDATALEN, "internal_output_cte##sys_gen##%p", (void *) i); internal_ctename = pstrdup(ctename); - - // PreparableStmt inside CTE + + /* PreparableStmt inside CTE */ i->cols = insert_column_list; i->selectStmt = tsql_output_insert_rest->selectStmt; i->relation = insert_target; @@ -949,35 +998,38 @@ tsql_insert_output_into_cte_transformation(WithClause *opt_with_clause, RangeVar i->withClause = NULL; i->override = false; - /* - * Make sure we do not pass inserted qualifier to the SELECT target list. - * Instead, we add an alias for column names qualified by inserted, and remove - * the inserted qualifier from *. We also make sure only one * is left in - * the output list inside the CTE. - */ + /* + * Make sure we do not pass inserted qualifier to the SELECT target list. + * Instead, we add an alias for column names qualified by inserted, and + * remove the inserted qualifier from *. We also make sure only one * is + * left in the output list inside the CTE. + */ output_list = copyObject(tsql_output_clause); foreach(lc, output_list) { ResTarget *res = (ResTarget *) lfirst(lc); + queue = NIL; queue = list_make1(res->val); - + foreach(expr, queue) { - Node *node = (Node *) lfirst(expr); + Node *node = (Node *) lfirst(expr); + if (IsA(node, ColumnRef)) { ColumnRef *cref = (ColumnRef *) node; + if (list_length(cref->fields) >= 2) { field1 = (Node *) linitial(cref->fields); qualifier = strVal(field1); - + if (!strcmp(qualifier, "inserted")) { - if (IsA((Node*) llast(cref->fields), String)) + if (IsA((Node *) llast(cref->fields), String)) { - snprintf(col_alias_arr, NAMEDATALEN, "sys_gen##%pins_%s", (void*) tsql_output_clause, strVal(llast(cref->fields))); + snprintf(col_alias_arr, NAMEDATALEN, "sys_gen##%pins_%s", (void *) tsql_output_clause, strVal(llast(cref->fields))); col_alias = pstrdup(col_alias_arr); } else @@ -987,31 +1039,33 @@ tsql_insert_output_into_cte_transformation(WithClause *opt_with_clause, RangeVar cref->fields = list_make1(makeString(col_alias)); } } - else if(IsA(node, A_Expr)) + else if (IsA(node, A_Expr)) { - A_Expr *a_expr = (A_Expr *) node; + A_Expr *a_expr = (A_Expr *) node; + if (a_expr->lexpr) queue = lappend(queue, a_expr->lexpr); if (a_expr->rexpr) queue = lappend(queue, a_expr->rexpr); } - else if(IsA(node, FuncCall)) + else if (IsA(node, FuncCall)) { - FuncCall *func_call = (FuncCall*) node; + FuncCall *func_call = (FuncCall *) node; + if (func_call->args) queue = list_concat(queue, func_call->args); } } } - - // SelectStmt inside outer InsertStmt + + /* SelectStmt inside outer InsertStmt */ n->limitCount = NULL; n->targetList = output_list; n->intoClause = NULL; n->fromClause = list_make1(makeRangeVar(NULL, internal_ctename, select_location)); - // Outer InsertStmt - tsql_output_insert_rest->selectStmt = (Node*) n; + /* Outer InsertStmt */ + tsql_output_insert_rest->selectStmt = (Node *) n; tsql_output_insert_rest->relation = output_target; tsql_output_insert_rest->onConflictClause = NULL; tsql_output_insert_rest->returningList = NULL; @@ -1020,17 +1074,17 @@ tsql_insert_output_into_cte_transformation(WithClause *opt_with_clause, RangeVar else tsql_output_insert_rest->cols = tsql_output_into_target_columns; - // CTE + /* CTE */ cte->ctename = internal_ctename; cte->aliascolnames = NULL; cte->ctematerialized = CTEMaterializeDefault; cte->ctequery = (Node *) i; cte->location = 1; - if(opt_with_clause) + if (opt_with_clause) { - opt_with_clause->ctes = lappend(opt_with_clause->ctes, (Node*) cte); - tsql_output_insert_rest->withClause = opt_with_clause; + opt_with_clause->ctes = lappend(opt_with_clause->ctes, (Node *) cte); + tsql_output_insert_rest->withClause = opt_with_clause; } else { @@ -1040,74 +1094,78 @@ tsql_insert_output_into_cte_transformation(WithClause *opt_with_clause, RangeVar tsql_output_insert_rest->withClause = w; } - output_into_insert_transformation = true; - + output_into_insert_transformation = true; + return (Node *) tsql_output_insert_rest; } static Node * tsql_delete_output_into_cte_transformation(WithClause *opt_with_clause, Node *opt_top_clause, - RangeVar *relation_expr_opt_alias, List *tsql_output_clause, RangeVar *insert_target, - List *tsql_output_into_target_columns, List *from_clause, Node *where_or_current_clause, - core_yyscan_t yyscanner) + RangeVar *relation_expr_opt_alias, List *tsql_output_clause, RangeVar *insert_target, + List *tsql_output_into_target_columns, List *from_clause, Node *where_or_current_clause, + core_yyscan_t yyscanner) { CommonTableExpr *cte = makeNode(CommonTableExpr); WithClause *w = makeNode(WithClause); SelectStmt *n = makeNode(SelectStmt); DeleteStmt *d = makeNode(DeleteStmt); InsertStmt *i = makeNode(InsertStmt); - ListCell *lc; - Node *field1; - char *qualifier = NULL; - List *output_list = NIL, *queue = NIL; - char *internal_ctename = NULL; - char ctename[NAMEDATALEN]; - ListCell *expr; - char col_alias_arr[NAMEDATALEN]; - char *col_alias = NULL; - - snprintf(ctename, NAMEDATALEN, "internal_output_cte##sys_gen##%p", (void*) i); + ListCell *lc; + Node *field1; + char *qualifier = NULL; + List *output_list = NIL, + *queue = NIL; + char *internal_ctename = NULL; + char ctename[NAMEDATALEN]; + ListCell *expr; + char col_alias_arr[NAMEDATALEN]; + char *col_alias = NULL; + + snprintf(ctename, NAMEDATALEN, "internal_output_cte##sys_gen##%p", (void *) i); internal_ctename = pstrdup(ctename); - - // PreparableStmt inside CTE + + /* PreparableStmt inside CTE */ d->relation = relation_expr_opt_alias; tsql_update_delete_stmt_from_clause_alias(d->relation, from_clause); if (from_clause != NULL && IsA(linitial(from_clause), JoinExpr)) { - d = (DeleteStmt*)tsql_update_delete_stmt_with_join( - (Node*)d, from_clause, where_or_current_clause, opt_top_clause, - relation_expr_opt_alias, yyscanner); + d = (DeleteStmt *) tsql_update_delete_stmt_with_join( + (Node *) d, from_clause, where_or_current_clause, opt_top_clause, + relation_expr_opt_alias, yyscanner); output_update_transformation = true; } else { d->usingClause = from_clause; d->whereClause = tsql_update_delete_stmt_with_top(opt_top_clause, - relation_expr_opt_alias, where_or_current_clause, yyscanner); + relation_expr_opt_alias, where_or_current_clause, yyscanner); if (from_clause != NULL && (IsA(linitial(from_clause), RangeSubselect) || IsA(linitial(from_clause), RangeVar))) output_update_transformation = true; } d->returningList = get_transformed_output_list(tsql_output_clause); d->withClause = opt_with_clause; - - /* - * Make sure we do not pass deleted qualifier to the SELECT target list. - * Instead, we add an alias for column names qualified bydeleted, and remove - * the deleted qualifier from *. - */ + + /* + * Make sure we do not pass deleted qualifier to the SELECT target list. + * Instead, we add an alias for column names qualified bydeleted, and + * remove the deleted qualifier from *. + */ output_list = copyObject(tsql_output_clause); foreach(lc, output_list) { ResTarget *res = (ResTarget *) lfirst(lc); + queue = NIL; queue = list_make1(res->val); foreach(expr, queue) { - Node *node = (Node *) lfirst(expr); + Node *node = (Node *) lfirst(expr); + if (IsA(node, ColumnRef)) { ColumnRef *cref = (ColumnRef *) node; + if (list_length(cref->fields) >= 2) { field1 = (Node *) linitial(cref->fields); @@ -1115,9 +1173,9 @@ tsql_delete_output_into_cte_transformation(WithClause *opt_with_clause, Node *op if (!strcmp(qualifier, "deleted")) { - if (IsA((Node*) llast(cref->fields), String)) + if (IsA((Node *) llast(cref->fields), String)) { - snprintf(col_alias_arr, NAMEDATALEN, "sys_gen##%pdel_%s", (void*) tsql_output_clause, strVal(llast(cref->fields))); + snprintf(col_alias_arr, NAMEDATALEN, "sys_gen##%pdel_%s", (void *) tsql_output_clause, strVal(llast(cref->fields))); col_alias = pstrdup(col_alias_arr); } else @@ -1127,47 +1185,49 @@ tsql_delete_output_into_cte_transformation(WithClause *opt_with_clause, Node *op cref->fields = list_make1(makeString(col_alias)); } } - else if(IsA(node, A_Expr)) + else if (IsA(node, A_Expr)) { - A_Expr *a_expr = (A_Expr *) node; + A_Expr *a_expr = (A_Expr *) node; + if (a_expr->lexpr) queue = lappend(queue, a_expr->lexpr); if (a_expr->rexpr) queue = lappend(queue, a_expr->rexpr); } - else if(IsA(node, FuncCall)) + else if (IsA(node, FuncCall)) { - FuncCall *func_call = (FuncCall*) node; + FuncCall *func_call = (FuncCall *) node; + if (func_call->args) queue = list_concat(queue, func_call->args); } } } - - // SelectStmt inside outer InsertStmt + + /* SelectStmt inside outer InsertStmt */ n->limitCount = NULL; n->targetList = output_list; n->intoClause = NULL; n->fromClause = list_make1(makeRangeVar(NULL, internal_ctename, 4)); - // Outer InsertStmt - i->selectStmt = (Node*) n; + /* Outer InsertStmt */ + i->selectStmt = (Node *) n; i->relation = insert_target; i->onConflictClause = NULL; i->returningList = NULL; i->cols = tsql_output_into_target_columns; - // CTE + /* CTE */ cte->ctename = internal_ctename; cte->aliascolnames = NULL; cte->ctematerialized = CTEMaterializeDefault; cte->ctequery = (Node *) d; cte->location = 1; - if(opt_with_clause) + if (opt_with_clause) { - opt_with_clause->ctes = lappend(opt_with_clause->ctes, (Node*) cte); - i->withClause = opt_with_clause; + opt_with_clause->ctes = lappend(opt_with_clause->ctes, (Node *) cte); + i->withClause = opt_with_clause; } else { @@ -1182,21 +1242,23 @@ tsql_delete_output_into_cte_transformation(WithClause *opt_with_clause, Node *op static void tsql_check_update_output_transformation(List *tsql_output_clause) { - ListCell *lc; - bool deleted = false; + ListCell *lc; + bool deleted = false; /* - * Check for deleted qualifier in OUTPUT list. If there is no deleted qualifier, - * there is no need for parse tree rewrite because PG already supports - * returning modified (inserted) values. - */ + * Check for deleted qualifier in OUTPUT list. If there is no deleted + * qualifier, there is no need for parse tree rewrite because PG already + * supports returning modified (inserted) values. + */ foreach(lc, tsql_output_clause) { ResTarget *res = (ResTarget *) lfirst(lc); + if (IsA(res->val, ColumnRef)) { - ColumnRef *cref = (ColumnRef *) res->val; - if(!strcmp(strVal((Node *) linitial(cref->fields)), "deleted")) + ColumnRef *cref = (ColumnRef *) res->val; + + if (!strcmp(strVal((Node *) linitial(cref->fields)), "deleted")) { deleted = true; break; @@ -1209,37 +1271,38 @@ tsql_check_update_output_transformation(List *tsql_output_clause) static Node * tsql_update_output_into_cte_transformation(WithClause *opt_with_clause, Node *opt_top_clause, - RangeVar *relation_expr_opt_alias, List *set_clause_list, - List *tsql_output_clause, RangeVar *insert_target, List *tsql_output_into_target_columns, - List *from_clause, Node *where_or_current_clause, core_yyscan_t yyscanner) + RangeVar *relation_expr_opt_alias, List *set_clause_list, + List *tsql_output_clause, RangeVar *insert_target, List *tsql_output_into_target_columns, + List *from_clause, Node *where_or_current_clause, core_yyscan_t yyscanner) { CommonTableExpr *cte = makeNode(CommonTableExpr); WithClause *w = makeNode(WithClause); SelectStmt *n = makeNode(SelectStmt); UpdateStmt *u = makeNode(UpdateStmt); InsertStmt *i = makeNode(InsertStmt); - ListCell *lc; - Node *field1; - char *qualifier = NULL; - List *output_list = NIL, *queue = NIL; - char *internal_ctename = NULL; - char ctename[NAMEDATALEN]; - ListCell *expr; - char col_alias_arr[NAMEDATALEN]; - char *col_alias = NULL; - - snprintf(ctename, NAMEDATALEN, "internal_output_cte##sys_gen##%p", (void*) i); + ListCell *lc; + Node *field1; + char *qualifier = NULL; + List *output_list = NIL, + *queue = NIL; + char *internal_ctename = NULL; + char ctename[NAMEDATALEN]; + ListCell *expr; + char col_alias_arr[NAMEDATALEN]; + char *col_alias = NULL; + + snprintf(ctename, NAMEDATALEN, "internal_output_cte##sys_gen##%p", (void *) i); internal_ctename = pstrdup(ctename); - - // PreparableStmt inside CTE + + /* PreparableStmt inside CTE */ u->relation = relation_expr_opt_alias; tsql_update_delete_stmt_from_clause_alias(u->relation, from_clause); u->targetList = set_clause_list; if (from_clause != NULL && IsA(linitial(from_clause), JoinExpr)) { - u = (UpdateStmt*)tsql_update_delete_stmt_with_join( - (Node*)u, from_clause, where_or_current_clause, opt_top_clause, - relation_expr_opt_alias, yyscanner); + u = (UpdateStmt *) tsql_update_delete_stmt_with_join( + (Node *) u, from_clause, where_or_current_clause, opt_top_clause, + relation_expr_opt_alias, yyscanner); } else { @@ -1250,35 +1313,38 @@ tsql_update_output_into_cte_transformation(WithClause *opt_with_clause, Node *op u->withClause = opt_with_clause; tsql_check_update_output_transformation(tsql_output_clause); - - /* - * Make sure we do not pass deleted or inserted qualifier to the SELECT target list. - * Instead, we add an alias for column names qualified by inserted/deleted, and remove - * the inserted/deleted qualifier from *. - */ + + /* + * Make sure we do not pass deleted or inserted qualifier to the SELECT + * target list. Instead, we add an alias for column names qualified by + * inserted/deleted, and remove the inserted/deleted qualifier from *. + */ output_list = copyObject(tsql_output_clause); foreach(lc, output_list) { ResTarget *res = (ResTarget *) lfirst(lc); + queue = NIL; queue = list_make1(res->val); foreach(expr, queue) { - Node *node = (Node *) lfirst(expr); + Node *node = (Node *) lfirst(expr); + if (IsA(node, ColumnRef)) { ColumnRef *cref = (ColumnRef *) node; + if (list_length(cref->fields) >= 2) { field1 = (Node *) linitial(cref->fields); qualifier = strVal(field1); - - if(!strcmp(qualifier, "deleted")) + + if (!strcmp(qualifier, "deleted")) { - if (IsA((Node*) llast(cref->fields), String)) + if (IsA((Node *) llast(cref->fields), String)) { - snprintf(col_alias_arr, NAMEDATALEN, "sys_gen##%pdel_%s", (void*) tsql_output_clause, strVal(llast(cref->fields))); + snprintf(col_alias_arr, NAMEDATALEN, "sys_gen##%pdel_%s", (void *) tsql_output_clause, strVal(llast(cref->fields))); col_alias = pstrdup(col_alias_arr); } else @@ -1286,9 +1352,9 @@ tsql_update_output_into_cte_transformation(WithClause *opt_with_clause, Node *op } else if (!strcmp(qualifier, "inserted")) { - if (IsA((Node*) llast(cref->fields), String)) + if (IsA((Node *) llast(cref->fields), String)) { - snprintf(col_alias_arr, NAMEDATALEN, "sys_gen##%pins_%s", (void*) tsql_output_clause, strVal(llast(cref->fields))); + snprintf(col_alias_arr, NAMEDATALEN, "sys_gen##%pins_%s", (void *) tsql_output_clause, strVal(llast(cref->fields))); col_alias = pstrdup(col_alias_arr); } else @@ -1298,47 +1364,49 @@ tsql_update_output_into_cte_transformation(WithClause *opt_with_clause, Node *op cref->fields = list_make1(makeString(col_alias)); } } - else if(IsA(node, A_Expr)) + else if (IsA(node, A_Expr)) { - A_Expr *a_expr = (A_Expr *) node; + A_Expr *a_expr = (A_Expr *) node; + if (a_expr->lexpr) queue = lappend(queue, a_expr->lexpr); if (a_expr->rexpr) queue = lappend(queue, a_expr->rexpr); } - else if(IsA(node, FuncCall)) + else if (IsA(node, FuncCall)) { - FuncCall *func_call = (FuncCall*) node; + FuncCall *func_call = (FuncCall *) node; + if (func_call->args) queue = list_concat(queue, func_call->args); } } } - - // SelectStmt inside outer InsertStmt + + /* SelectStmt inside outer InsertStmt */ n->limitCount = NULL; n->targetList = output_list; n->intoClause = NULL; n->fromClause = list_make1(makeRangeVar(NULL, internal_ctename, -1)); - // Outer InsertStmt - i->selectStmt = (Node*) n; + /* Outer InsertStmt */ + i->selectStmt = (Node *) n; i->relation = insert_target; i->onConflictClause = NULL; i->returningList = NULL; i->cols = tsql_output_into_target_columns; - // CTE + /* CTE */ cte->ctename = internal_ctename; cte->aliascolnames = NULL; cte->ctematerialized = CTEMaterializeDefault; cte->ctequery = (Node *) u; cte->location = 1; - if(opt_with_clause) + if (opt_with_clause) { - opt_with_clause->ctes = lappend(opt_with_clause->ctes, (Node*) cte); - i->withClause = opt_with_clause; + opt_with_clause->ctes = lappend(opt_with_clause->ctes, (Node *) cte); + i->withClause = opt_with_clause; } else { @@ -1349,84 +1417,95 @@ tsql_update_output_into_cte_transformation(WithClause *opt_with_clause, Node *op } return (Node *) i; } - + /* -* get_transformed_output_list() extracts the ColumnRefs from functions and -* expressions so that the returning list in the rewritten CTE for OUTPUT INTO -* transformation does not contain functions and expressions. It also adds an +* get_transformed_output_list() extracts the ColumnRefs from functions and +* expressions so that the returning list in the rewritten CTE for OUTPUT INTO +* transformation does not contain functions and expressions. It also adds an * alias to columns qualified by inserted or deleted. */ static List * get_transformed_output_list(List *tsql_output_clause) { - List *transformed_returning_list = NIL, *queue = NIL, *output_list = NIL; - List *ins_colnames = NIL, *del_colnames = NIL; - ListCell *o_target, *expr; - char col_alias_arr[NAMEDATALEN]; - char *col_alias = NULL; + List *transformed_returning_list = NIL, + *queue = NIL, + *output_list = NIL; + List *ins_colnames = NIL, + *del_colnames = NIL; + ListCell *o_target, + *expr; + char col_alias_arr[NAMEDATALEN]; + char *col_alias = NULL; PLtsql_execstate *estate; - int i = 0; - bool local_variable = false, ins_star = false, del_star = false, is_duplicate = false; - + int i = 0; + bool local_variable = false, + ins_star = false, + del_star = false, + is_duplicate = false; + estate = get_current_tsql_estate(); output_list = copyObject(tsql_output_clause); foreach(o_target, output_list) { - ResTarget *res = (ResTarget *) lfirst(o_target); + ResTarget *res = (ResTarget *) lfirst(o_target); + queue = NIL; queue = list_make1(res->val); foreach(expr, queue) { - Node *node = (Node *) lfirst(expr); + Node *node = (Node *) lfirst(expr); + if (IsA(node, ColumnRef)) { - ResTarget *target = makeNode(ResTarget); + ResTarget *target = makeNode(ResTarget); ColumnRef *cref = (ColumnRef *) node; + local_variable = false; - - if(!strcmp(strVal(linitial(cref->fields)), "deleted") && list_length(cref->fields) >= 2) + + if (!strcmp(strVal(linitial(cref->fields)), "deleted") && list_length(cref->fields) >= 2) { - if (IsA((Node*) llast(cref->fields), String)) + if (IsA((Node *) llast(cref->fields), String)) { is_duplicate = returning_list_has_column_name(del_colnames, strVal(llast(cref->fields))); if (!is_duplicate) { - snprintf(col_alias_arr, NAMEDATALEN, "sys_gen##%pdel_%s", (void*) tsql_output_clause, strVal(llast(cref->fields))); + snprintf(col_alias_arr, NAMEDATALEN, "sys_gen##%pdel_%s", (void *) tsql_output_clause, strVal(llast(cref->fields))); col_alias = pstrdup(col_alias_arr); target->name = col_alias; del_colnames = lappend(del_colnames, strVal(llast(cref->fields))); } } - else if (IsA((Node*) llast(cref->fields), A_Star)) + else if (IsA((Node *) llast(cref->fields), A_Star)) ins_star = true; - + } - else if(!strcmp(strVal(linitial(cref->fields)), "inserted") && list_length(cref->fields) >= 2) + else if (!strcmp(strVal(linitial(cref->fields)), "inserted") && list_length(cref->fields) >= 2) { - if (IsA((Node*) llast(cref->fields), String)) + if (IsA((Node *) llast(cref->fields), String)) { is_duplicate = returning_list_has_column_name(ins_colnames, strVal(llast(cref->fields))); if (!is_duplicate) { - snprintf(col_alias_arr, NAMEDATALEN, "sys_gen##%pins_%s", (void*) tsql_output_clause, strVal(llast(cref->fields))); + snprintf(col_alias_arr, NAMEDATALEN, "sys_gen##%pins_%s", (void *) tsql_output_clause, strVal(llast(cref->fields))); col_alias = pstrdup(col_alias_arr); target->name = col_alias; ins_colnames = lappend(ins_colnames, strVal(llast(cref->fields))); } } - else if (IsA((Node*) llast(cref->fields), A_Star)) + else if (IsA((Node *) llast(cref->fields), A_Star)) del_star = true; } else { - if(!strncmp(strVal(linitial(cref->fields)), "@", 1) && estate) + if (!strncmp(strVal(linitial(cref->fields)), "@", 1) && estate) { for (i = 0; i < estate->ndatums; i++) { PLtsql_datum *d = estate->datums[i]; - if (!strcmp(strVal(linitial(cref->fields)), ((PLtsql_variable*) d)->refname)) + + if (!strcmp(strVal(linitial(cref->fields)), ((PLtsql_variable *) d)->refname)) { local_variable = true; break; @@ -1438,27 +1517,28 @@ get_transformed_output_list(List *tsql_output_clause) ereport( ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("OUTPUT INTO does not support both inserted.* and deleted.* in target list") - ) - ); + errmsg("OUTPUT INTO does not support both inserted.* and deleted.* in target list") + ) + ); if (!local_variable) { - target->val = (Node*) cref; + target->val = (Node *) cref; transformed_returning_list = lappend(transformed_returning_list, target); } } - else if(IsA(node, A_Expr)) + else if (IsA(node, A_Expr)) { - A_Expr *a_expr = (A_Expr *) node; + A_Expr *a_expr = (A_Expr *) node; if (a_expr->lexpr) queue = lappend(queue, a_expr->lexpr); if (a_expr->rexpr) queue = lappend(queue, a_expr->rexpr); } - else if(IsA(node, FuncCall)) + else if (IsA(node, FuncCall)) { - FuncCall *func_call = (FuncCall*) node; + FuncCall *func_call = (FuncCall *) node; + if (func_call->args) queue = list_concat(queue, func_call->args); } @@ -1469,22 +1549,23 @@ get_transformed_output_list(List *tsql_output_clause) /* * returning_list_has_column_name() checks whether a particular column name already -* exists in the transformed returning list for OUTPUT clause. Such a scenario is -* possible because get_transformed_output_list() removes functions and expressions +* exists in the transformed returning list for OUTPUT clause. Such a scenario is +* possible because get_transformed_output_list() removes functions and expressions * and only retains the column names. */ static bool returning_list_has_column_name(List *existing_colnames, char *current_colname) { - ListCell *name; - bool is_duplicate = false; + ListCell *name; + bool is_duplicate = false; if (existing_colnames == NIL) return false; foreach(name, existing_colnames) { - char *colname = (char*) lfirst(name); + char *colname = (char *) lfirst(name); + if (!strcmp(colname, current_colname)) { is_duplicate = true; @@ -1498,28 +1579,29 @@ returning_list_has_column_name(List *existing_colnames, char *current_colname) * Make a function call to tsql_select_for_xml_agg() for FOR JSON clause. */ ResTarget * -TsqlForXMLMakeFuncCall(TSQL_ForClause* forclause) +TsqlForXMLMakeFuncCall(TSQL_ForClause *forclause) { - ResTarget *rt = makeNode(ResTarget); - FuncCall *fc; - List *func_name; - List *func_args; - bool binary_base64 = false; - bool return_xml_type = false; - char* root_name = NULL; + ResTarget *rt = makeNode(ResTarget); + FuncCall *fc; + List *func_name; + List *func_args; + bool binary_base64 = false; + bool return_xml_type = false; + char *root_name = NULL; /* Resolve the XML common directive list if provided */ if (forclause->commonDirectives != NIL) { - ListCell *lc; - foreach (lc, forclause->commonDirectives) + ListCell *lc; + + foreach(lc, forclause->commonDirectives) { - Node *myNode = lfirst(lc); - A_Const *myConst; + Node *myNode = lfirst(lc); + A_Const *myConst; /* commonDirective is either integer const or string const */ Assert(IsA(myNode, A_Const)); - myConst = (A_Const *)myNode; + myConst = (A_Const *) myNode; Assert(IsA(&myConst->val, Integer) || IsA(&myConst->val, String)); if (IsA(&myConst->val, Integer)) { @@ -1536,15 +1618,16 @@ TsqlForXMLMakeFuncCall(TSQL_ForClause* forclause) } /* - * Finally make function call to tsql_select_for_xml_agg or tsql_select_for_xml_text_agg - * depending on the return_xml_type flag (TYPE option in the FOR XML clause). - * The only difference of the two functions is the return type. tsql_select_for_xml_agg - * returns XML type, tsql_select_for_xml_text_agg returns text type. + * Finally make function call to tsql_select_for_xml_agg or + * tsql_select_for_xml_text_agg depending on the return_xml_type flag + * (TYPE option in the FOR XML clause). The only difference of the two + * functions is the return type. tsql_select_for_xml_agg returns XML type, + * tsql_select_for_xml_text_agg returns text type. */ if (return_xml_type) - func_name= list_make2(makeString("sys"), makeString("tsql_select_for_xml_agg")); + func_name = list_make2(makeString("sys"), makeString("tsql_select_for_xml_agg")); else - func_name= list_make2(makeString("sys"), makeString("tsql_select_for_xml_text_agg")); + func_name = list_make2(makeString("sys"), makeString("tsql_select_for_xml_text_agg")); func_args = list_make5(makeColumnRef(construct_unique_index_name("rows", "tsql_for"), NIL, -1, NULL), makeIntConst(forclause->mode, -1), forclause->elementName ? makeStringConst(forclause->elementName, -1) : makeStringConst("row", -1), @@ -1552,14 +1635,16 @@ TsqlForXMLMakeFuncCall(TSQL_ForClause* forclause) root_name ? makeStringConst(root_name, -1) : makeStringConst("", -1)); fc = makeFuncCall(func_name, func_args, COERCE_EXPLICIT_CALL, -1); - /* In SQL Server if the result is empty then 0 rows are returned. Unfortunately it is not - * possible to mimic this behavior solely using an aggregate, so we use an additional SRF - * and pass the result to that function so that returning 0 rows is possible. + /* + * In SQL Server if the result is empty then 0 rows are returned. + * Unfortunately it is not possible to mimic this behavior solely using an + * aggregate, so we use an additional SRF and pass the result to that + * function so that returning 0 rows is possible. */ - func_name= list_make2(makeString("sys"), - makeString(return_xml_type ? - "tsql_select_for_xml_result" : - "tsql_select_for_xml_text_result")); + func_name = list_make2(makeString("sys"), + makeString(return_xml_type ? + "tsql_select_for_xml_result" : + "tsql_select_for_xml_text_result")); func_args = list_make1(fc); fc = makeFuncCall(func_name, func_args, COERCE_EXPLICIT_CALL, -1); @@ -1576,28 +1661,29 @@ TsqlForXMLMakeFuncCall(TSQL_ForClause* forclause) * Make a function call to tsql_select_for_json_agg() for FOR JSON clause. */ static ResTarget * -TsqlForJSONMakeFuncCall(TSQL_ForClause* forclause) +TsqlForJSONMakeFuncCall(TSQL_ForClause *forclause) { - ResTarget *rt = makeNode(ResTarget); - FuncCall *fc; - List *func_name; - List *func_args; - bool include_null_values = false; - bool without_array_wrapper = false; - char* root_name = NULL; + ResTarget *rt = makeNode(ResTarget); + FuncCall *fc; + List *func_name; + List *func_args; + bool include_null_values = false; + bool without_array_wrapper = false; + char *root_name = NULL; /* Resolve the JSON common directive list if provided */ if (forclause->commonDirectives != NIL) { - ListCell *lc; - foreach (lc, forclause->commonDirectives) + ListCell *lc; + + foreach(lc, forclause->commonDirectives) { - Node *myNode = lfirst(lc); - A_Const *myConst; + Node *myNode = lfirst(lc); + A_Const *myConst; /* commonDirective is either integer const or string const */ Assert(IsA(myNode, A_Const)); - myConst = (A_Const *)myNode; + myConst = (A_Const *) myNode; Assert(IsA(&myConst->val, Integer) || IsA(&myConst->val, String)); if (IsA(&myConst->val, Integer)) { @@ -1613,18 +1699,21 @@ TsqlForJSONMakeFuncCall(TSQL_ForClause* forclause) } } - /* ROOT option and WITHOUT_ARRAY_WRAPPER option cannot be used together in FOR JSON */ + /* + * ROOT option and WITHOUT_ARRAY_WRAPPER option cannot be used together in + * FOR JSON + */ if (root_name && without_array_wrapper) { ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("ROOT option and WITHOUT_ARRAY_WRAPPER option cannot be used together in FOR JSON. Remove one of these options"))); + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("ROOT option and WITHOUT_ARRAY_WRAPPER option cannot be used together in FOR JSON. Remove one of these options"))); } - + /* * Make function call to tsql_select_for_json_agg */ - func_name= list_make2(makeString("sys"), makeString("tsql_select_for_json_agg")); + func_name = list_make2(makeString("sys"), makeString("tsql_select_for_json_agg")); func_args = list_make5(makeColumnRef(construct_unique_index_name("rows", "tsql_for"), NIL, -1, NULL), makeIntConst(forclause->mode, -1), makeBoolAConst(include_null_values, -1), @@ -1632,11 +1721,13 @@ TsqlForJSONMakeFuncCall(TSQL_ForClause* forclause) root_name ? makeStringConst(root_name, -1) : makeNullAConst(-1)); fc = makeFuncCall(func_name, func_args, COERCE_EXPLICIT_CALL, -1); - /* In SQL Server if the result is empty then 0 rows are returned. Unfortunately it is not - * possible to mimic this behavior solely using an aggregate, so we use an additional SRF - * and pass the result to that function so that returning 0 rows is possible. + /* + * In SQL Server if the result is empty then 0 rows are returned. + * Unfortunately it is not possible to mimic this behavior solely using an + * aggregate, so we use an additional SRF and pass the result to that + * function so that returning 0 rows is possible. */ - func_name= list_make2(makeString("sys"), makeString("tsql_select_for_json_result")); + func_name = list_make2(makeString("sys"), makeString("tsql_select_for_json_result")); func_args = list_make1(fc); fc = makeFuncCall(func_name, func_args, COERCE_EXPLICIT_CALL, -1); @@ -1651,7 +1742,7 @@ TsqlForJSONMakeFuncCall(TSQL_ForClause* forclause) /* * Create an aliased sub-select clause for use in FOR XML/JSON - * rule resolution. We re-use construct_unique_index_name to + * rule resolution. We re-use construct_unique_index_name to * generate a unique row name to reference - this makes it virtually * impossible for any query to accidentally use the same alias name. * construct_unique_index_name should only fail in case of OOM, which @@ -1661,6 +1752,7 @@ static RangeSubselect * TsqlForClauseSubselect(Node *selectstmt) { RangeSubselect *rss = makeNode(RangeSubselect); + rss->subquery = selectstmt; rss->alias = makeAlias(construct_unique_index_name("rows", "tsql_for"), NIL); return rss; diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-prologue.y.h b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-prologue.y.h index 0effc69038..baf85cb493 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-prologue.y.h +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-prologue.y.h @@ -18,17 +18,17 @@ #define MD5_HASH_LEN 32 -static void pgtsql_base_yyerror(YYLTYPE *yylloc, core_yyscan_t yyscanner, const char *msg); +static void pgtsql_base_yyerror(YYLTYPE * yylloc, core_yyscan_t yyscanner, const char *msg); -List *TsqlSystemFuncName(char *name); -List *TsqlSystemFuncName2(char *name); +List *TsqlSystemFuncName(char *name); +List *TsqlSystemFuncName2(char *name); typedef struct OpenJson_Col_Def { - char *elemName; - TypeName *elemType; - char *elemPath; - bool asJson; + char *elemName; + TypeName *elemType; + char *elemPath; + bool asJson; } OpenJson_Col_Def; extern bool output_update_transformation; @@ -45,41 +45,40 @@ static Node *TsqlFunctionParse(Node *arg, TypeName *typename, Node *culture, boo static Node *TsqlFunctionIIF(Node *bool_expr, Node *arg1, Node *arg2, int location); static Node *TsqlFunctionChoose(Node *int_expr, List *choosable, int location); -static void tsql_check_param_readonly(const char* paramname, TypeName *typename, bool readonly); +static void tsql_check_param_readonly(const char *paramname, TypeName *typename, bool readonly); static ResTarget *TsqlForXMLMakeFuncCall(TSQL_ForClause *forclause); static ResTarget *TsqlForJSONMakeFuncCall(TSQL_ForClause *forclause); static RangeSubselect *TsqlForClauseSubselect(Node *selectstmt); -static Node *TsqlOpenJSONSimpleMakeFuncCall(Node* jsonExpr, Node* path); -static Node *TsqlOpenJSONWithMakeFuncCall(Node* jsonExpr, Node* path, List* cols, Alias* alias); -static Node *createOpenJsonWithColDef(char* elemName, TypeName* elemType); -static int getElemTypMod(TypeName *t); -static TypeName* setCharTypmodForOpenjson(TypeName *t); -static bool isCharType(char* typenameStr); -static bool isNVarCharType(char* typenameStr); +static Node *TsqlOpenJSONSimpleMakeFuncCall(Node *jsonExpr, Node *path); +static Node *TsqlOpenJSONWithMakeFuncCall(Node *jsonExpr, Node *path, List *cols, Alias *alias); +static Node *createOpenJsonWithColDef(char *elemName, TypeName *elemType); +static int getElemTypMod(TypeName *t); +static TypeName *setCharTypmodForOpenjson(TypeName *t); +static bool isCharType(char *typenameStr); +static bool isNVarCharType(char *typenameStr); -static Node *TsqlJsonModifyMakeFuncCall(Node* expr, Node* path, Node* newValue); +static Node *TsqlJsonModifyMakeFuncCall(Node *expr, Node *path, Node *newValue); static bool is_json_query(List *name); -char * construct_unique_index_name(char *index_name, char *relation_name); +char *construct_unique_index_name(char *index_name, char *relation_name); -static Node *tsql_update_delete_stmt_with_join(Node *n, List* from_clause, Node* - where_clause, Node *top_clause, RangeVar *relation, - core_yyscan_t yyscanner); +static Node *tsql_update_delete_stmt_with_join(Node *n, List *from_clause, Node *where_clause, Node *top_clause, RangeVar *relation, + core_yyscan_t yyscanner); static Node *tsql_update_delete_stmt_with_top(Node *top_clause, RangeVar - *relation, Node *where_clause, core_yyscan_t yyscanner); + *relation, Node *where_clause, core_yyscan_t yyscanner); static void tsql_update_delete_stmt_from_clause_alias(RangeVar *relation, List *from_clause); -static Node *tsql_insert_output_into_cte_transformation(WithClause *opt_with_clause, RangeVar *insert_target, - List *insert_column_list, List *tsql_output_clause, RangeVar *output_target, List *tsql_output_into_target_columns, - InsertStmt *tsql_output_insert_rest, int select_location); +static Node *tsql_insert_output_into_cte_transformation(WithClause *opt_with_clause, RangeVar *insert_target, + List *insert_column_list, List *tsql_output_clause, RangeVar *output_target, List *tsql_output_into_target_columns, + InsertStmt *tsql_output_insert_rest, int select_location); static Node *tsql_delete_output_into_cte_transformation(WithClause *opt_with_clause, Node *opt_top_clause, - RangeVar *relation_expr_opt_alias, List *tsql_output_clause, RangeVar *insert_target, - List *tsql_output_into_target_columns, List *from_clause, Node *where_or_current_clause, - core_yyscan_t yyscanner); + RangeVar *relation_expr_opt_alias, List *tsql_output_clause, RangeVar *insert_target, + List *tsql_output_into_target_columns, List *from_clause, Node *where_or_current_clause, + core_yyscan_t yyscanner); static void tsql_check_update_output_transformation(List *tsql_output_clause); static Node *tsql_update_output_into_cte_transformation(WithClause *opt_with_clause, Node *opt_top_clause, - RangeVar *relation_expr_opt_alias, List *set_clause_list, - List *tsql_output_clause, RangeVar *insert_target, List *tsql_output_into_target_columns, - List *from_clause, Node *where_or_current_clause, core_yyscan_t yyscanner); + RangeVar *relation_expr_opt_alias, List *set_clause_list, + List *tsql_output_clause, RangeVar *insert_target, List *tsql_output_into_target_columns, + List *from_clause, Node *where_or_current_clause, core_yyscan_t yyscanner); static List *get_transformed_output_list(List *tsql_output_clause); static bool returning_list_has_column_name(List *existing_colnames, char *current_colname); diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram_hook.c b/contrib/babelfishpg_tsql/src/backend_parser/gram_hook.c index 76a78e2f24..41a099066b 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram_hook.c +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram_hook.c @@ -6,18 +6,19 @@ #include "parser/parser.h" #include "parser/parse_expr.h" #include "parser/scanner.h" -#include "src/pltsql.h" /* needed for pltsql_protocol_plugin_ptr */ +#include "src/pltsql.h" /* needed for pltsql_protocol_plugin_ptr */ extern bool babelfish_dump_restore; -void install_backend_gram_hooks(void); +void install_backend_gram_hooks(void); static List *rewrite_typmod_expr(List *expr_list); -static Node * makeIntConst(int val, int location); -static void TsqlValidateNumericTypmods(List **typmods, bool isNumeric, void* yyscanner); +static Node *makeIntConst(int val, int location); +static void TsqlValidateNumericTypmods(List **typmods, bool isNumeric, void *yyscanner); static bool tsql_is_recursive_cte(WithClause *with_clause); static void fix_tsql_domain_typmods(TypeName *typname); -void install_backend_gram_hooks() +void +install_backend_gram_hooks() { rewrite_typmod_expr_hook = rewrite_typmod_expr; validate_numeric_typmods_hook = TsqlValidateNumericTypmods; @@ -40,7 +41,7 @@ fix_tsql_domain_typmods(TypeName *typname) if (list_length(typname->names) >= 2 && strcmp(strVal(linitial(typname->names)), "sys") == 0 && (strcmp(strVal(lsecond(typname->names)), "sysname") == 0 || - strcmp(strVal(lsecond(typname->names)), "_ci_sysname") == 0)) + strcmp(strVal(lsecond(typname->names)), "_ci_sysname") == 0)) typname->typmods = NIL; } @@ -48,39 +49,41 @@ static List * rewrite_typmod_expr(List *expr_list) { /* - * Look for ( max ) if we are in tsql dialect, MAX can be used - * in sys.varchar, sys.nvarchar, sys.binary and sys.varbinary. - * map it to TSQLMaxTypmod + * Look for ( max ) if we are in tsql dialect, MAX can be used in + * sys.varchar, sys.nvarchar, sys.binary and sys.varbinary. map it to + * TSQLMaxTypmod */ - Node *expr; + Node *expr; Assert(sql_dialect == SQL_DIALECT_TSQL); expr = linitial(expr_list); if (list_length(expr_list) == 1 && IsA(expr, ColumnRef)) { - ColumnRef *columnref = (ColumnRef *) expr; + ColumnRef *columnref = (ColumnRef *) expr; + if (list_length(columnref->fields) == 1) { - char *str = ((String *) linitial(columnref->fields))->sval; - if (strcmp( str, "max") == 0) + char *str = ((String *) linitial(columnref->fields))->sval; + + if (strcmp(str, "max") == 0) return list_make1(makeIntConst(TSQLMaxTypmod, -1)); } } - return expr_list; /* nothing to do */ + return expr_list; /* nothing to do */ } static Node * makeIntConst(int val, int location) { - A_Const *n = makeNode(A_Const); + A_Const *n = makeNode(A_Const); n->val.ival.type = T_Integer; n->val.ival.ival = val; n->location = location; - return (Node *)n; + return (Node *) n; } /* @@ -92,7 +95,7 @@ makeIntConst(int val, int location) void TsqlValidateNumericTypmods(List **typmods, bool isNumeric, void *yyscanner) { - int precision = 0; + int precision = 0; if (*typmods == NIL) { @@ -104,50 +107,56 @@ TsqlValidateNumericTypmods(List **typmods, bool isNumeric, void *yyscanner) IS_TDS_CLIENT()) && list_length(*typmods) <= 2); - switch(list_length(*typmods)) + switch (list_length(*typmods)) { case 1: - { - Node *expr = linitial(*typmods); - if (IsA(expr, A_Const)) { - A_Const *con = (A_Const *) expr; - if (IsA(&(con->val), Integer)) - precision = intVal(&(con->val)); - if (precision > TSQLMaxNumPrecision) + Node *expr = linitial(*typmods); + + if (IsA(expr, A_Const)) { - const char *type = isNumeric ? - "numeric" : "decimal"; - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("The size (%d) given to the type '%s' exceeds the maximum allowed (38)", precision, type), - scanner_errposition(con->location, yyscanner))); + A_Const *con = (A_Const *) expr; + + if (IsA(&(con->val), Integer)) + precision = intVal(&(con->val)); + if (precision > TSQLMaxNumPrecision) + { + const char *type = isNumeric ? + "numeric" : "decimal"; + + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("The size (%d) given to the type '%s' exceeds the maximum allowed (38)", precision, type), + scanner_errposition(con->location, yyscanner))); + } } + /* Set default scale to 0 when only precision is provided */ + *typmods = list_append_unique(*typmods, makeIntConst(0, -1)); + break; } - /* Set default scale to 0 when only precision is provided */ - *typmods = list_append_unique(*typmods, makeIntConst(0, -1)); - break; - } case 2: - { - Node *expr = linitial(*typmods); - if (IsA(expr, A_Const)) { - A_Const *con = (A_Const *) expr; - if (IsA(&(con->val), Integer)) - precision = intVal(&(con->val)); - if (precision > TSQLMaxNumPrecision) + Node *expr = linitial(*typmods); + + if (IsA(expr, A_Const)) { - const char *type = isNumeric ? - "numeric" : "decimal"; - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("The size (%d) given to the type '%s' exceeds the maximum allowed (38)", precision, type), - scanner_errposition(con->location, yyscanner))); + A_Const *con = (A_Const *) expr; + + if (IsA(&(con->val), Integer)) + precision = intVal(&(con->val)); + if (precision > TSQLMaxNumPrecision) + { + const char *type = isNumeric ? + "numeric" : "decimal"; + + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("The size (%d) given to the type '%s' exceeds the maximum allowed (38)", precision, type), + scanner_errposition(con->location, yyscanner))); + } } + break; } - break; - } case 0: break; } @@ -155,9 +164,9 @@ TsqlValidateNumericTypmods(List **typmods, bool isNumeric, void *yyscanner) typedef struct { - char *cur_cte_name; /* current CTE name */ - List *inner_ctes; /* inner CTE-list list */ - bool is_recursive; + char *cur_cte_name; /* current CTE name */ + List *inner_ctes; /* inner CTE-list list */ + bool is_recursive; } CteContext; /* @@ -173,6 +182,7 @@ check_recursive_cte_walker(Node *node, CteContext *context) if (IsA(node, RangeVar)) { RangeVar *rv = (RangeVar *) node; + if (!rv->schemaname) { ListCell *lc; @@ -193,8 +203,8 @@ check_recursive_cte_walker(Node *node, CteContext *context) } if (strcmp(rv->relname, context->cur_cte_name) == 0) { - context->is_recursive = true; /* found recursive CTE */ - return true; /* terminate the worker */ + context->is_recursive = true; /* found recursive CTE */ + return true; /* terminate the worker */ } } return false; @@ -203,12 +213,13 @@ check_recursive_cte_walker(Node *node, CteContext *context) { SelectStmt *stmt = (SelectStmt *) node; ListCell *lc; + if (stmt->withClause) { /* - * In T-SQL mode, name resolution follows non-RECURSIVE rule. - * In the non-RECURSIVE case, query names are visible to the - * WITH items after them and to the main query. + * In T-SQL mode, name resolution follows non-RECURSIVE rule. In + * the non-RECURSIVE case, query names are visible to the WITH + * items after them and to the main query. */ ListCell *cell1; @@ -249,11 +260,12 @@ static bool tsql_is_recursive_cte(WithClause *with_clause) { ListCell *lc; + foreach(lc, with_clause->ctes) { SelectStmt *stmt; CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc); - CteContext context; + CteContext context; /* cannot be recursive */ if (!IsA(cte->ctequery, SelectStmt)) @@ -261,14 +273,14 @@ tsql_is_recursive_cte(WithClause *with_clause) stmt = (SelectStmt *) cte->ctequery; - /* recursive CTE must have at least one SET OP */ + /* recursive CTE must have at least one SET OP */ if (stmt->op == SETOP_NONE) continue; context.cur_cte_name = cte->ctename; context.inner_ctes = NULL; context.is_recursive = false; - check_recursive_cte_walker((Node*) stmt, &context); + check_recursive_cte_walker((Node *) stmt, &context); if (context.is_recursive) return true; } diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gramparse.h b/contrib/babelfishpg_tsql/src/backend_parser/gramparse.h index 17af1d3ea3..40c53d5c59 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gramparse.h +++ b/contrib/babelfishpg_tsql/src/backend_parser/gramparse.h @@ -38,12 +38,12 @@ typedef struct base_yy_extra_type pgtsql_base_yy_extra_type; #define pg_yyget_extra(yyscanner) (*((base_yy_extra_type **) (yyscanner))) /* from parser.c */ -extern int pgtsql_base_yylex(YYSTYPE *lvalp, YYLTYPE *llocp, - core_yyscan_t yyscanner); +extern int pgtsql_base_yylex(YYSTYPE *lvalp, YYLTYPE * llocp, + core_yyscan_t yyscanner); /* from pgtsql_gram.y */ extern void pgtsql_parser_init(pgtsql_base_yy_extra_type *yyext); -extern int pgtsql_base_yyparse(core_yyscan_t yyscanner); -extern int pgtsql_base_yydebug; +extern int pgtsql_base_yyparse(core_yyscan_t yyscanner); +extern int pgtsql_base_yydebug; #endif /* PGTSQL_GRAMPARSE_H */ diff --git a/contrib/babelfishpg_tsql/src/backend_parser/parser.c b/contrib/babelfishpg_tsql/src/backend_parser/parser.c index 03d75b31ff..37db5620eb 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/parser.c +++ b/contrib/babelfishpg_tsql/src/backend_parser/parser.c @@ -29,9 +29,9 @@ #include "src/pltsql.h" #include "tcop/tcopprot.h" -int pgtsql_base_yydebug; +int pgtsql_base_yydebug; -List *babelfishpg_tsql_raw_parser(const char *str, RawParseMode mode); +List *babelfishpg_tsql_raw_parser(const char *str, RawParseMode mode); /* * raw_parser @@ -46,10 +46,11 @@ babelfishpg_tsql_raw_parser(const char *str, RawParseMode mode) core_yyscan_t yyscanner; pgtsql_base_yy_extra_type yyextra; int yyresult; - List *raw_parsetree_list; + List *raw_parsetree_list; instr_time parseStart; instr_time parseEnd; - /* + + /* * parse identifiers case-insensitively if the database collation is CI_AS */ pltsql_case_insensitive_identifiers = tsql_is_server_collation_CI_AS(); @@ -57,7 +58,7 @@ babelfishpg_tsql_raw_parser(const char *str, RawParseMode mode) /* initialize the flex scanner */ yyscanner = pgtsql_scanner_init(str, &yyextra.core_yy_extra, - &pgtsql_ScanKeywords, pgtsql_ScanKeywordTokens); + &pgtsql_ScanKeywords, pgtsql_ScanKeywordTokens); /* base_yylex() only needs us to initialize the lookahead token, if any */ if (mode == RAW_PARSE_DEFAULT) @@ -95,7 +96,7 @@ babelfishpg_tsql_raw_parser(const char *str, RawParseMode mode) raw_parsetree_list = yyextra.parsetree; /* check if query string needs to be logged */ if (raw_parsetree_list && check_log_statement(raw_parsetree_list) && - pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)) + pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)) (*pltsql_protocol_plugin_ptr)->stmt_needs_logging = true; INSTR_TIME_SET_CURRENT(parseEnd); @@ -123,7 +124,7 @@ babelfishpg_tsql_raw_parser(const char *str, RawParseMode mode) * same thing anyway, but notationally they're different). */ int -pgtsql_base_yylex(YYSTYPE *lvalp, YYLTYPE *llocp, core_yyscan_t yyscanner) +pgtsql_base_yylex(YYSTYPE *lvalp, YYLTYPE * llocp, core_yyscan_t yyscanner) { pgtsql_base_yy_extra_type *yyextra = pg_yyget_extra(yyscanner); int cur_token; @@ -246,10 +247,11 @@ pgtsql_base_yylex(YYSTYPE *lvalp, YYLTYPE *llocp, core_yyscan_t yyscanner) { case '(': cur_token = UPDATE_paren; - break; + break; } break; case WITH: + /* * Replace WITH by WITH_LA if it's followed by TIME or ORDINALITY * Replace WITH by WITH_paren if it's followed by '(' @@ -290,11 +292,11 @@ pgtsql_base_yylex(YYSTYPE *lvalp, YYLTYPE *llocp, core_yyscan_t yyscanner) break; case FOR: switch (next_token) - { + { case XML_P: cur_token = TSQL_FOR; break; - + case TSQL_JSON: cur_token = TSQL_FOR; break; diff --git a/contrib/babelfishpg_tsql/src/backend_parser/scan-tsql-epilogue.l.c b/contrib/babelfishpg_tsql/src/backend_parser/scan-tsql-epilogue.l.c index 584f5dd141..53a3929968 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/scan-tsql-epilogue.l.c +++ b/contrib/babelfishpg_tsql/src/backend_parser/scan-tsql-epilogue.l.c @@ -3,17 +3,16 @@ */ core_yyscan_t pgtsql_scanner_init(const char *str, - core_yy_extra_type *yyext, - const ScanKeywordList *keywordlist, - const uint16 *keyword_tokens) + core_yy_extra_type *yyext, + const ScanKeywordList *keywordlist, + const uint16 *keyword_tokens) { Size slen = strlen(str); yyscan_t scanner; /* - * If sql_dialect is set to SQL_DIALECT_TSQL - * arrange to inject a dialect selector token - * (DIALECT_TSQL) + * If sql_dialect is set to SQL_DIALECT_TSQL arrange to inject a dialect + * selector token (DIALECT_TSQL) */ if (sql_dialect == SQL_DIALECT_TSQL) dialect_selector = DIALECT_TSQL; @@ -58,8 +57,7 @@ pgtsql_scanner_finish(core_yyscan_t yyscanner) scanner_finish(yyscanner); } -void * -core_yyalloc(yy_size_t bytes, core_yyscan_t yyscanner); +void *core_yyalloc(yy_size_t bytes, core_yyscan_t yyscanner); void * pgtsql_core_yyalloc(yy_size_t bytes, core_yyscan_t yyscanner) @@ -67,8 +65,7 @@ pgtsql_core_yyalloc(yy_size_t bytes, core_yyscan_t yyscanner) return core_yyalloc(bytes, yyscanner); } -void * -core_yyrealloc(void *ptr, yy_size_t bytes, core_yyscan_t yyscanner); +void *core_yyrealloc(void *ptr, yy_size_t bytes, core_yyscan_t yyscanner); void * pgtsql_core_yyrealloc(void *ptr, yy_size_t bytes, core_yyscan_t yyscanner) @@ -77,7 +74,7 @@ pgtsql_core_yyrealloc(void *ptr, yy_size_t bytes, core_yyscan_t yyscanner) } void -core_yyfree(void *ptr, core_yyscan_t yyscanner); + core_yyfree(void *ptr, core_yyscan_t yyscanner); void pgtsql_core_yyfree(void *ptr, core_yyscan_t yyscanner) diff --git a/contrib/babelfishpg_tsql/src/backend_parser/scan-tsql-prologue.l.h b/contrib/babelfishpg_tsql/src/backend_parser/scan-tsql-prologue.l.h index dec4bd7863..53bf60dafe 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/scan-tsql-prologue.l.h +++ b/contrib/babelfishpg_tsql/src/backend_parser/scan-tsql-prologue.l.h @@ -13,7 +13,7 @@ const uint16 pgtsql_ScanKeywordTokens[] = { #undef PG_KEYWORD -int dialect_selector = 0; +int dialect_selector = 0; /* * If dialect_selector is set to a value other than diff --git a/contrib/babelfishpg_tsql/src/backend_parser/scanner.h b/contrib/babelfishpg_tsql/src/backend_parser/scanner.h index f9189a3128..43b9489da1 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/scanner.h +++ b/contrib/babelfishpg_tsql/src/backend_parser/scanner.h @@ -5,15 +5,15 @@ extern const uint16 pgtsql_ScanKeywordTokens[]; -extern int pgtsql_core_yylex(core_YYSTYPE *lvalp, YYLTYPE *llocp, core_yyscan_t yyscanner); +extern int pgtsql_core_yylex(core_YYSTYPE *lvalp, YYLTYPE * llocp, core_yyscan_t yyscanner); core_yyscan_t -pgtsql_scanner_init(const char *str, - core_yy_extra_type *yyext, - const ScanKeywordList *keywordlist, - const uint16 *keyword_tokens); + pgtsql_scanner_init(const char *str, + core_yy_extra_type *yyext, + const ScanKeywordList *keywordlist, + const uint16 *keyword_tokens); void -pgtsql_scanner_finish(core_yyscan_t yyscanner); + pgtsql_scanner_finish(core_yyscan_t yyscanner); #endif /* PGTSQL_SCANNER_H */ diff --git a/contrib/babelfishpg_tsql/src/catalog.c b/contrib/babelfishpg_tsql/src/catalog.c index 139f9b0a91..0a2bfc48f0 100644 --- a/contrib/babelfishpg_tsql/src/catalog.c +++ b/contrib/babelfishpg_tsql/src/catalog.c @@ -36,21 +36,21 @@ /***************************************** * SYS schema *****************************************/ -Oid sys_schema_oid = InvalidOid; +Oid sys_schema_oid = InvalidOid; /***************************************** * SYSDATABASES *****************************************/ -Oid sysdatabases_oid = InvalidOid; -Oid sysdatabaese_idx_oid_oid = InvalidOid; -Oid sysdatabaese_idx_name_oid = InvalidOid; +Oid sysdatabases_oid = InvalidOid; +Oid sysdatabaese_idx_oid_oid = InvalidOid; +Oid sysdatabaese_idx_name_oid = InvalidOid; /***************************************** * NAMESPACE_EXT *****************************************/ -Oid namespace_ext_oid = InvalidOid; -Oid namespace_ext_idx_oid_oid = InvalidOid; -int namespace_ext_num_cols = 4; +Oid namespace_ext_oid = InvalidOid; +Oid namespace_ext_idx_oid_oid = InvalidOid; +int namespace_ext_num_cols = 4; /***************************************** * LOGIN EXT @@ -91,49 +91,50 @@ extern bool babelfish_dump_restore; extern char *orig_proc_funcname; static struct cachedesc my_cacheinfo[] = { - {-1, /* SYSDATABASEOID */ - -1, - 1, - { - Anum_sysdatabaese_oid, - 0, - 0, - 0 - }, - 16 - }, - {-1, /* SYSDATABASENAME */ - -1, - 1, - { - Anum_sysdatabaese_name, - 0, - 0, - 0 - }, - 16 - }, - {-1, /* PROCNSPSIGNATURE */ - -1, - 2, - { - Anum_bbf_function_ext_nspname, - Anum_bbf_function_ext_funcsignature, - 0, - 0 - }, - 16 - } + {-1, /* SYSDATABASEOID */ + -1, + 1, + { + Anum_sysdatabaese_oid, + 0, + 0, + 0 + }, + 16 + }, + {-1, /* SYSDATABASENAME */ + -1, + 1, + { + Anum_sysdatabaese_name, + 0, + 0, + 0 + }, + 16 + }, + {-1, /* PROCNSPSIGNATURE */ + -1, + 2, + { + Anum_bbf_function_ext_nspname, + Anum_bbf_function_ext_funcsignature, + 0, + 0 + }, + 16 + } }; PG_FUNCTION_INFO_V1(init_catalog); -Datum init_catalog(PG_FUNCTION_ARGS) +Datum +init_catalog(PG_FUNCTION_ARGS) { /* sys schema */ sys_schema_oid = get_namespace_oid("sys", true); if (!OidIsValid(sys_schema_oid)) - PG_RETURN_INT32(0); + PG_RETURN_INT32(0); /* sysdatabases */ sysdatabases_oid = get_relname_relid(SYSDATABASES_TABLE_NAME, sys_schema_oid); @@ -177,10 +178,13 @@ Datum init_catalog(PG_FUNCTION_ARGS) PG_RETURN_INT32(0); } -void initTsqlSyscache() { +void +initTsqlSyscache() +{ Assert(my_cacheinfo[0].reloid != -1); /* Initialize info for catcache */ - if (!tsql_syscache_inited) { + if (!tsql_syscache_inited) + { InitExtensionCatalogCache(my_cacheinfo, SYSDATABASEOID, 3); tsql_syscache_inited = true; } @@ -190,77 +194,81 @@ void initTsqlSyscache() { * Catalog Hooks *****************************************/ -bool +bool IsPLtsqlExtendedCatalog(Oid relationId) { if (relationId == sysdatabases_oid || relationId == bbf_function_ext_oid) return true; if (PrevIsExtendedCatalogHook) - return (*PrevIsExtendedCatalogHook)(relationId); + return (*PrevIsExtendedCatalogHook) (relationId); return false; } /***************************************** * SYSDATABASES *****************************************/ -int16 get_db_id(const char *dbname) +int16 +get_db_id(const char *dbname) { - int16 db_id = 0; - HeapTuple tuple; - Form_sysdatabases sysdb; + int16 db_id = 0; + HeapTuple tuple; + Form_sysdatabases sysdb; - tuple = SearchSysCache1(SYSDATABASENAME, CStringGetTextDatum(dbname)); + tuple = SearchSysCache1(SYSDATABASENAME, CStringGetTextDatum(dbname)); - if (!HeapTupleIsValid(tuple)) - return InvalidDbid; + if (!HeapTupleIsValid(tuple)) + return InvalidDbid; - sysdb = ((Form_sysdatabases) GETSTRUCT(tuple)); - db_id = sysdb->dbid; - ReleaseSysCache(tuple); + sysdb = ((Form_sysdatabases) GETSTRUCT(tuple)); + db_id = sysdb->dbid; + ReleaseSysCache(tuple); return db_id; } -char *get_db_name(int16 dbid) +char * +get_db_name(int16 dbid) { - HeapTuple tuple; - Datum name_datum; - char *name = NULL; - bool isNull; + HeapTuple tuple; + Datum name_datum; + char *name = NULL; + bool isNull; - tuple = SearchSysCache1(SYSDATABASEOID, Int16GetDatum(dbid)); + tuple = SearchSysCache1(SYSDATABASEOID, Int16GetDatum(dbid)); - if (!HeapTupleIsValid(tuple)) - return NULL; + if (!HeapTupleIsValid(tuple)) + return NULL; - name_datum = SysCacheGetAttr(SYSDATABASEOID, tuple, Anum_sysdatabaese_name, &isNull); - name = TextDatumGetCString(name_datum); - ReleaseSysCache(tuple); + name_datum = SysCacheGetAttr(SYSDATABASEOID, tuple, Anum_sysdatabaese_name, &isNull); + name = TextDatumGetCString(name_datum); + ReleaseSysCache(tuple); return name; } -const char *get_one_user_db_name(void) +const char * +get_one_user_db_name(void) { - HeapTuple tuple; - TableScanDesc scan; - Relation rel; - char *user_db_name = NULL; - bool is_null; + HeapTuple tuple; + TableScanDesc scan; + Relation rel; + char *user_db_name = NULL; + bool is_null; rel = table_open(sysdatabases_oid, AccessShareLock); scan = table_beginscan_catalog(rel, 0, NULL); tuple = heap_getnext(scan, ForwardScanDirection); - while (HeapTupleIsValid(tuple)) + while (HeapTupleIsValid(tuple)) { - char *db_name; + char *db_name; + + Datum name = heap_getattr(tuple, Anum_sysdatabaese_name, + rel->rd_att, &is_null); - Datum name = heap_getattr(tuple, Anum_sysdatabaese_name, - rel->rd_att, &is_null); db_name = TextDatumGetCString(name); - // check that db_name is not "master", "tempdb", or "msdb" + /* check that db_name is not "master", "tempdb", or "msdb" */ if ((strlen(db_name) != 6 || (strncmp(db_name, "master", 6) != 0)) && (strlen(db_name) != 6 || (strncmp(db_name, "tempdb", 6) != 0)) && (strlen(db_name) != 4 || (strncmp(db_name, "msdb", 4) != 0))) @@ -270,7 +278,7 @@ const char *get_one_user_db_name(void) } tuple = heap_getnext(scan, ForwardScanDirection); } - + table_endscan(scan); table_close(rel, AccessShareLock); @@ -283,63 +291,63 @@ PG_FUNCTION_INFO_V1(babelfish_helpdb); Datum babelfish_helpdb(PG_FUNCTION_ARGS) { - ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - char *dbname; - char *dbname_lower; - ScanKeyData scanKey; - TupleDesc tupdesc; - Tuplestorestate *tupstore; - MemoryContext per_query_ctx; - MemoryContext oldcontext; - Relation rel; - SysScanDesc scan; - HeapTuple tuple; - Form_sysdatabases sysdb; - Oid datetime_output_func; - bool typIsVarlena; - Oid datetime_type; - Oid sys_nspoid = get_namespace_oid("sys", false); - int index; - - /* check to see if caller supports us returning a tuplestore */ - if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("set-valued function called in context that cannot accept a set"))); - if (!(rsinfo->allowedModes & SFRM_Materialize)) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("materialize mode required, but it is not " \ - "allowed in this context"))); - - /* need to build tuplestore in query context */ - per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; - oldcontext = MemoryContextSwitchTo(per_query_ctx); - - /* - * build tupdesc for result tuples. - */ - tupdesc = CreateTemplateTupleDesc(7); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", - VARCHAROID, 128, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "db_size", - VARCHAROID, 13, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 3, "owner", - VARCHAROID, 128, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 4, "dbid", - INT4OID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 5, "created", - VARCHAROID, 11, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 6, "status", - VARCHAROID, 600, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 7, "compatibility_level", - INT2OID, -1, 0); - - tupstore = - tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random, - false, 1024); - /* generate junk in short-term context */ - MemoryContextSwitchTo(oldcontext); + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + char *dbname; + char *dbname_lower; + ScanKeyData scanKey; + TupleDesc tupdesc; + Tuplestorestate *tupstore; + MemoryContext per_query_ctx; + MemoryContext oldcontext; + Relation rel; + SysScanDesc scan; + HeapTuple tuple; + Form_sysdatabases sysdb; + Oid datetime_output_func; + bool typIsVarlena; + Oid datetime_type; + Oid sys_nspoid = get_namespace_oid("sys", false); + int index; + + /* check to see if caller supports us returning a tuplestore */ + if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("set-valued function called in context that cannot accept a set"))); + if (!(rsinfo->allowedModes & SFRM_Materialize)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("materialize mode required, but it is not " \ + "allowed in this context"))); + + /* need to build tuplestore in query context */ + per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; + oldcontext = MemoryContextSwitchTo(per_query_ctx); + + /* + * build tupdesc for result tuples. + */ + tupdesc = CreateTemplateTupleDesc(7); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", + VARCHAROID, 128, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "db_size", + VARCHAROID, 13, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "owner", + VARCHAROID, 128, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 4, "dbid", + INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 5, "created", + VARCHAROID, 11, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 6, "status", + VARCHAROID, 600, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 7, "compatibility_level", + INT2OID, -1, 0); + + tupstore = + tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random, + false, 1024); + /* generate junk in short-term context */ + MemoryContextSwitchTo(oldcontext); rel = table_open(sysdatabases_oid, AccessShareLock); @@ -349,9 +357,9 @@ babelfish_helpdb(PG_FUNCTION_ARGS) dbname_lower = str_tolower(dbname, strlen(dbname), DEFAULT_COLLATION_OID); /* Remove trailing spaces at the end of user typed dbname */ index = -1; - for (int i = 0; dbname_lower[i]!='\0'; i++) + for (int i = 0; dbname_lower[i] != '\0'; i++) { - if (dbname_lower[i]!=' ') + if (dbname_lower[i] != ' ') { index = i; } @@ -359,14 +367,14 @@ babelfish_helpdb(PG_FUNCTION_ARGS) dbname_lower[index + 1] = '\0'; if (!DbidIsValid(get_db_id(dbname_lower))) ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_DATABASE), - errmsg("The database '%s' does not exist. Supply a valid database name. To see available databases, use sys.databases.", dbname))); + (errcode(ERRCODE_UNDEFINED_DATABASE), + errmsg("The database '%s' does not exist. Supply a valid database name. To see available databases, use sys.databases.", dbname))); ScanKeyInit(&scanKey, - Anum_sysdatabaese_name, - BTEqualStrategyNumber, F_TEXTEQ, - CStringGetTextDatum(dbname_lower)); + Anum_sysdatabaese_name, + BTEqualStrategyNumber, F_TEXTEQ, + CStringGetTextDatum(dbname_lower)); scan = systable_beginscan(rel, sysdatabaese_idx_name_oid, true, - NULL, 1, &scanKey); + NULL, 1, &scanKey); } else { @@ -374,30 +382,30 @@ babelfish_helpdb(PG_FUNCTION_ARGS) } datetime_type = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, - CStringGetDatum("datetime"), ObjectIdGetDatum(sys_nspoid)); + CStringGetDatum("datetime"), ObjectIdGetDatum(sys_nspoid)); getTypeOutputInfo(datetime_type, &datetime_output_func, &typIsVarlena); - /* scan all the variables in top estate */ + /* scan all the variables in top estate */ while (HeapTupleIsValid(tuple = systable_getnext(scan))) { - Datum values[7]; - bool nulls[7]; - char *db_name_entry; - Timestamp tmstmp; - char *tmstmp_str; + Datum values[7]; + bool nulls[7]; + char *db_name_entry; + Timestamp tmstmp; + char *tmstmp_str; bool isNull; sysdb = ((Form_sysdatabases) GETSTRUCT(tuple)); - MemSet(nulls, 0, sizeof(nulls)); + MemSet(nulls, 0, sizeof(nulls)); db_name_entry = TextDatumGetCString(heap_getattr(tuple, Anum_sysdatabaese_name, - RelationGetDescr(rel), &isNull)); + RelationGetDescr(rel), &isNull)); values[0] = CStringGetTextDatum(db_name_entry); - nulls[1] = 1; + nulls[1] = 1; values[2] = CStringGetTextDatum(NameStr(sysdb->owner)); @@ -408,29 +416,29 @@ babelfish_helpdb(PG_FUNCTION_ARGS) else if (strlen(db_name_entry) == 4 && (strncmp(db_name_entry, "msdb", 4) == 0)) values[3] = 4; else - values[3] = sysdb->dbid; + values[3] = sysdb->dbid; tmstmp = DatumGetTimestamp(heap_getattr(tuple, Anum_sysdatabaese_crdate, - RelationGetDescr(rel), &isNull)); + RelationGetDescr(rel), &isNull)); tmstmp_str = OidOutputFunctionCall(datetime_output_func, tmstmp); values[4] = CStringGetTextDatum(tmstmp_str); - nulls[5] = 1; + nulls[5] = 1; values[6] = UInt8GetDatum(120); - tuplestore_putvalues(tupstore, tupdesc, values, nulls); - } + tuplestore_putvalues(tupstore, tupdesc, values, nulls); + } systable_endscan(scan); table_close(rel, AccessShareLock); - /* clean up and return the tuplestore */ - tuplestore_donestoring(tupstore); + /* clean up and return the tuplestore */ + tuplestore_donestoring(tupstore); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; + rsinfo->returnMode = SFRM_Materialize; + rsinfo->setResult = tupstore; + rsinfo->setDesc = tupdesc; - PG_RETURN_NULL(); + PG_RETURN_NULL(); } /***************************************** @@ -440,14 +448,14 @@ babelfish_helpdb(PG_FUNCTION_ARGS) const char * get_logical_schema_name(const char *physical_schema_name, bool missingOk) { - Relation rel; + Relation rel; HeapTuple tuple; ScanKeyData scanKey; SysScanDesc scan; Datum datum; - const char *logical_name; + const char *logical_name; TupleDesc dsc; - bool isnull; + bool isnull; if (get_namespace_oid(physical_schema_name, false) == InvalidOid) return NULL; @@ -470,8 +478,8 @@ get_logical_schema_name(const char *physical_schema_name, bool missingOk) table_close(rel, AccessShareLock); if (!missingOk) ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("Could find logical schema name for: \"%s\"", physical_schema_name))); + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("Could find logical schema name for: \"%s\"", physical_schema_name))); return NULL; } datum = heap_getattr(tuple, Anum_namespace_ext_orig_name, dsc, &isnull); @@ -485,10 +493,10 @@ get_logical_schema_name(const char *physical_schema_name, bool missingOk) int16 get_dbid_from_physical_schema_name(const char *physical_schema_name, bool missingOk) { - Relation rel; + Relation rel; HeapTuple tuple; - ScanKeyData scanKey; - SysScanDesc scan; + ScanKeyData scanKey; + SysScanDesc scan; Datum datum; int16 dbid; TupleDesc dsc; @@ -515,8 +523,8 @@ get_dbid_from_physical_schema_name(const char *physical_schema_name, bool missin table_close(rel, AccessShareLock); if (!missingOk) ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("Could not find db id for: \"%s\"", physical_schema_name))); + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("Could not find db id for: \"%s\"", physical_schema_name))); return InvalidDbid; } datum = heap_getattr(tuple, Anum_namespace_ext_dbid, dsc, &isnull); @@ -536,8 +544,8 @@ is_login(Oid role_oid) { Relation relation; bool is_login = true; - ScanKeyData scanKey; - SysScanDesc scan; + ScanKeyData scanKey; + SysScanDesc scan; HeapTuple tuple; HeapTuple authtuple; NameData rolname; @@ -546,7 +554,7 @@ is_login(Oid role_oid) if (!HeapTupleIsValid(authtuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("role with OID %u does not exist", role_oid))); + errmsg("role with OID %u does not exist", role_oid))); rolname = ((Form_pg_authid) GETSTRUCT(authtuple))->rolname; relation = table_open(get_authid_login_ext_oid(), AccessShareLock); @@ -578,10 +586,10 @@ is_login_name(char *rolname) { Relation relation; bool is_login = true; - ScanKeyData scanKey; - SysScanDesc scan; + ScanKeyData scanKey; + SysScanDesc scan; HeapTuple tuple; - NameData *login; + NameData *login; relation = table_open(get_authid_login_ext_oid(), AccessShareLock); @@ -608,10 +616,11 @@ is_login_name(char *rolname) } PG_FUNCTION_INFO_V1(bbf_get_login_default_db); -Datum bbf_get_login_default_db(PG_FUNCTION_ARGS) +Datum +bbf_get_login_default_db(PG_FUNCTION_ARGS) { - char *login_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); - char *ret; + char *login_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); + char *ret; ret = get_login_default_db(login_name); @@ -624,20 +633,20 @@ Datum bbf_get_login_default_db(PG_FUNCTION_ARGS) char * get_login_default_db(char *login_name) { - Relation bbf_authid_login_ext_rel; - TupleDesc dsc; - HeapTuple tuple; - ScanKeyData scanKey; - SysScanDesc scan; - Datum datum; - bool isnull; - char *default_db_name; + Relation bbf_authid_login_ext_rel; + TupleDesc dsc; + HeapTuple tuple; + ScanKeyData scanKey; + SysScanDesc scan; + Datum datum; + bool isnull; + char *default_db_name; /* Fetch the relation */ bbf_authid_login_ext_rel = table_open(get_authid_login_ext_oid(), AccessShareLock); dsc = RelationGetDescr(bbf_authid_login_ext_rel); - /* Search and obtain the tuple on the role name*/ + /* Search and obtain the tuple on the role name */ ScanKeyInit(&scanKey, Anum_bbf_authid_login_ext_rolname, BTEqualStrategyNumber, F_NAMEEQ, @@ -655,17 +664,17 @@ get_login_default_db(char *login_name) return NULL; } - datum = heap_getattr(tuple, LOGIN_EXT_DEFAULT_DATABASE_NAME+1, dsc, &isnull); + datum = heap_getattr(tuple, LOGIN_EXT_DEFAULT_DATABASE_NAME + 1, dsc, &isnull); default_db_name = pstrdup(TextDatumGetCString(datum)); systable_endscan(scan); table_close(bbf_authid_login_ext_rel, AccessShareLock); - tuple = SearchSysCache1(SYSDATABASENAME, CStringGetTextDatum(default_db_name)); + tuple = SearchSysCache1(SYSDATABASENAME, CStringGetTextDatum(default_db_name)); if (!HeapTupleIsValid(tuple)) return NULL; - ReleaseSysCache(tuple); + ReleaseSysCache(tuple); return default_db_name; } @@ -699,18 +708,18 @@ is_user(Oid role_oid) { Relation relation; bool is_user = true; - ScanKeyData scanKey; - SysScanDesc scan; + ScanKeyData scanKey; + SysScanDesc scan; HeapTuple tuple; HeapTuple authtuple; NameData rolname; - char *type_str = ""; + char *type_str = ""; authtuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(role_oid)); if (!HeapTupleIsValid(authtuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("role with OID %u does not exist", role_oid))); + errmsg("role with OID %u does not exist", role_oid))); rolname = ((Form_pg_authid) GETSTRUCT(authtuple))->rolname; relation = table_open(get_authid_user_ext_oid(), AccessShareLock); @@ -741,9 +750,8 @@ is_user(Oid role_oid) } /* - * Only sysadmin can not be dropped. For the rest - * of the cases i.e., type is "S" or "U" etc, we should - * drop the user + * Only sysadmin can not be dropped. For the rest of the cases i.e., type + * is "S" or "U" etc, we should drop the user */ if (strcmp(type_str, "R") == 0) is_user = false; @@ -761,19 +769,19 @@ is_role(Oid role_oid) { Relation relation; bool is_role = true; - ScanKeyData scanKey; - SysScanDesc scan; + ScanKeyData scanKey; + SysScanDesc scan; HeapTuple tuple; HeapTuple authtuple; NameData rolname; - BpChar type; - char *type_str = ""; + BpChar type; + char *type_str = ""; authtuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(role_oid)); if (!HeapTupleIsValid(authtuple)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("role with OID %u does not exist", role_oid))); + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("role with OID %u does not exist", role_oid))); rolname = ((Form_pg_authid) GETSTRUCT(authtuple))->rolname; relation = table_open(get_authid_user_ext_oid(), AccessShareLock); @@ -797,7 +805,7 @@ is_role(Oid role_oid) type_str = bpchar_to_cstring(&type); if (strcmp(type_str, "R") != 0) - is_role = false; + is_role = false; } systable_endscan(scan); @@ -831,12 +839,12 @@ get_authid_user_ext_idx_oid(void) char * get_authid_user_ext_physical_name(const char *db_name, const char *login) { - Relation bbf_authid_user_ext_rel; - HeapTuple tuple_user_ext; - ScanKeyData key[3]; - TableScanDesc scan; - char *user_name = NULL; - NameData *login_name; + Relation bbf_authid_user_ext_rel; + HeapTuple tuple_user_ext; + ScanKeyData key[3]; + TableScanDesc scan; + char *user_name = NULL; + NameData *login_name; if (!db_name || !login) return NULL; @@ -879,12 +887,12 @@ get_authid_user_ext_physical_name(const char *db_name, const char *login) char * get_authid_user_ext_schema_name(const char *db_name, const char *user) { - Relation bbf_authid_user_ext_rel; - HeapTuple tuple_user_ext; - ScanKeyData key[2]; - TableScanDesc scan; - char *schema_name = NULL; - NameData *user_name; + Relation bbf_authid_user_ext_rel; + HeapTuple tuple_user_ext; + ScanKeyData key[2]; + TableScanDesc scan; + char *schema_name = NULL; + NameData *user_name; if (!db_name || !user) return NULL; @@ -908,8 +916,8 @@ get_authid_user_ext_schema_name(const char *db_name, const char *user) tuple_user_ext = heap_getnext(scan, ForwardScanDirection); if (HeapTupleIsValid(tuple_user_ext)) { - Datum datum; - bool is_null; + Datum datum; + bool is_null; datum = heap_getattr(tuple_user_ext, Anum_bbf_authid_user_ext_default_schema_name, @@ -927,11 +935,11 @@ get_authid_user_ext_schema_name(const char *db_name, const char *user) List * get_authid_user_ext_db_users(const char *db_name) { - Relation bbf_authid_user_ext_rel; - HeapTuple tuple; - ScanKeyData key; - TableScanDesc scan; - List *db_users_list = NIL; + Relation bbf_authid_user_ext_rel; + HeapTuple tuple; + ScanKeyData key; + TableScanDesc scan; + List *db_users_list = NIL; if (!db_name) return NULL; @@ -949,7 +957,7 @@ get_authid_user_ext_db_users(const char *db_name) tuple = heap_getnext(scan, ForwardScanDirection); while (HeapTupleIsValid(tuple)) { - char *user_name; + char *user_name; Form_authid_user_ext userform; userform = (Form_authid_user_ext) GETSTRUCT(tuple); @@ -973,9 +981,9 @@ get_authid_user_ext_db_users(const char *db_name) char * get_user_for_database(const char *db_name) { - char *user = NULL; - const char *login; - bool login_is_db_owner; + char *user = NULL; + const char *login; + bool login_is_db_owner; login = GetUserNameFromId(GetSessionUserId(), false); user = get_authid_user_ext_physical_name(db_name, login); @@ -983,14 +991,17 @@ get_user_for_database(const char *db_name) if (!user) { - Oid datdba; + Oid datdba; datdba = get_role_oid("sysadmin", false); if (is_member_of_role(GetSessionUserId(), datdba) || login_is_db_owner) user = (char *) get_dbo_role_name(db_name); else { - /* Get the guest role name only if the guest is enabled on the current db.*/ + /* + * Get the guest role name only if the guest is enabled on the + * current db. + */ if (guest_has_dbaccess((char *) db_name)) user = (char *) get_guest_role_name(db_name); else @@ -998,8 +1009,8 @@ get_user_for_database(const char *db_name) } } - if (user && !(is_member_of_role(GetSessionUserId(), get_role_oid(user, false)) - || login_is_db_owner)) + if (user && !(is_member_of_role(GetSessionUserId(), get_role_oid(user, false)) + || login_is_db_owner)) user = NULL; return user; @@ -1033,11 +1044,12 @@ HeapTuple search_bbf_view_def(Relation bbf_view_def_rel, int16 dbid, const char *logical_schema_name, const char *view_name) { - ScanKeyData scanKey[3]; - SysScanDesc scan; - HeapTuple scantup, oldtup; + ScanKeyData scanKey[3]; + SysScanDesc scan; + HeapTuple scantup, + oldtup; - if(!DbidIsValid(dbid) || logical_schema_name == NULL || view_name == NULL) + if (!DbidIsValid(dbid) || logical_schema_name == NULL || view_name == NULL) return NULL; @@ -1071,12 +1083,13 @@ search_bbf_view_def(Relation bbf_view_def_rel, int16 dbid, const char *logical_s bool check_is_tsql_view(Oid relid) { - Oid schema_oid; + Oid schema_oid; Relation bbf_view_def_rel; HeapTuple scantup; - char *view_name, *schema_name; + char *view_name, + *schema_name; int16 logical_dbid; - const char *logical_schema_name; + const char *logical_schema_name; bool is_tsql_view = false; view_name = get_rel_name(relid); @@ -1120,10 +1133,10 @@ check_is_tsql_view(Oid relid) void clean_up_bbf_view_def(int16 dbid) { - Relation bbf_view_def_rel; - HeapTuple scantup; - ScanKeyData scanKey[1]; - SysScanDesc scan; + Relation bbf_view_def_rel; + HeapTuple scantup; + ScanKeyData scanKey[1]; + SysScanDesc scan; /* Fetch the relation */ bbf_view_def_rel = table_open(get_bbf_view_def_oid(), RowExclusiveLock); @@ -1142,7 +1155,7 @@ clean_up_bbf_view_def(int16 dbid) { if (HeapTupleIsValid(scantup)) CatalogTupleDelete(bbf_view_def_rel, - &scantup->t_self); + &scantup->t_self); } systable_endscan(scan); @@ -1158,7 +1171,7 @@ get_bbf_function_ext_oid() { if (!OidIsValid(bbf_function_ext_oid)) bbf_function_ext_oid = get_relname_relid(BBF_FUNCTION_EXT_TABLE_NAME, - get_namespace_oid("sys", false)); + get_namespace_oid("sys", false)); return bbf_function_ext_oid; } @@ -1168,7 +1181,7 @@ get_bbf_function_ext_idx_oid() { if (!OidIsValid(bbf_function_ext_idx_oid)) bbf_function_ext_idx_oid = get_relname_relid(BBF_FUNCTION_EXT_IDX_NAME, - get_namespace_oid("sys", false)); + get_namespace_oid("sys", false)); return bbf_function_ext_idx_oid; } @@ -1176,14 +1189,14 @@ get_bbf_function_ext_idx_oid() HeapTuple get_bbf_function_tuple_from_proctuple(HeapTuple proctuple) { - HeapTuple bbffunctuple; + HeapTuple bbffunctuple; Form_pg_proc form; - char *physical_schemaname; - const char *func_signature; + char *physical_schemaname; + const char *func_signature; /* Disallow extended catalog lookup during restore */ if (!HeapTupleIsValid(proctuple) || babelfish_dump_restore) - return NULL; /* concurrently dropped */ + return NULL; /* concurrently dropped */ form = (Form_pg_proc) GETSTRUCT(proctuple); if (!is_pltsql_language_oid(form->prolang)) return NULL; @@ -1192,8 +1205,8 @@ get_bbf_function_tuple_from_proctuple(HeapTuple proctuple) if (physical_schemaname == NULL) { elog(ERROR, - "Could not find physical schemaname for %u", - form->pronamespace); + "Could not find physical schemaname for %u", + form->pronamespace); } /* skip for shared schemas */ @@ -1226,11 +1239,12 @@ get_bbf_function_tuple_from_proctuple(HeapTuple proctuple) void clean_up_bbf_function_ext(int16 dbid) { - Relation bbf_function_ext_rel, namespace_rel; - AttrNumber attnum; - HeapTuple scantup; - ScanKeyData scanKey[1]; - TableScanDesc scan; + Relation bbf_function_ext_rel, + namespace_rel; + AttrNumber attnum; + HeapTuple scantup; + ScanKeyData scanKey[1]; + TableScanDesc scan; /* Fetch the relations */ namespace_rel = table_open(namespace_ext_oid, AccessShareLock); @@ -1238,12 +1252,12 @@ clean_up_bbf_function_ext(int16 dbid) attnum = (AttrNumber) attnameAttNum(namespace_rel, "dbid", false); if (attnum == InvalidAttrNumber) - ereport(ERROR, + ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column \"dbid\" of relation \"%s\" does not exist", RelationGetRelationName(namespace_rel)))); - ScanKeyInit(&scanKey[0], + ScanKeyInit(&scanKey[0], attnum, BTEqualStrategyNumber, F_INT2EQ, Int16GetDatum(dbid)); @@ -1256,7 +1270,7 @@ clean_up_bbf_function_ext(int16 dbid) bool isNull; Datum nspname; HeapTuple functup; - SysScanDesc funcscan; + SysScanDesc funcscan; nspname = heap_getattr(scantup, Anum_namespace_ext_namespace, @@ -1277,7 +1291,7 @@ clean_up_bbf_function_ext(int16 dbid) { if (HeapTupleIsValid(functup)) CatalogTupleDelete(bbf_function_ext_rel, - &functup->t_self); + &functup->t_self); } systable_endscan(funcscan); @@ -1298,7 +1312,7 @@ get_bbf_domain_mapping_oid() { if (!OidIsValid(bbf_domain_mapping_oid)) bbf_domain_mapping_oid = get_relname_relid(BBF_DOMAIN_MAPPING_TABLE_NAME, - get_namespace_oid("sys", false)); + get_namespace_oid("sys", false)); return bbf_domain_mapping_oid; } @@ -1308,7 +1322,7 @@ get_bbf_domain_mapping_idx_oid() { if (!OidIsValid(bbf_domain_mapping_idx_oid)) bbf_domain_mapping_idx_oid = get_relname_relid(BBF_DOMAIN_MAPPING_IDX_NAME, - get_namespace_oid("sys", false)); + get_namespace_oid("sys", false)); return bbf_domain_mapping_idx_oid; } @@ -1321,19 +1335,21 @@ get_bbf_domain_mapping_idx_oid() * rules to check the metadata integrity. *****************************************/ -/* +/* * This parameter controls whether the metadata check would stop at the first - * detected error. + * detected error. */ -bool stop_at_first_error = false; +bool stop_at_first_error = false; + /* * This parameter controls whether the function will return consistent rule list * or detected inconsistency. */ -bool return_consistency = false; +bool return_consistency = false; /* Core function declaration */ static void metadata_inconsistency_check(Tuplestorestate *res_tupstore, TupleDesc res_tupdesc); + /* Value function declaration */ static Datum get_master(HeapTuple tuple, TupleDesc dsc); static Datum get_tempdb(HeapTuple tuple, TupleDesc dsc); @@ -1358,21 +1374,25 @@ static Datum get_user_rolname(HeapTuple tuple, TupleDesc dsc); static Datum get_database_name(HeapTuple tuple, TupleDesc dsc); static Datum get_function_nspname(HeapTuple tuple, TupleDesc dsc); static Datum get_function_name(HeapTuple tuple, TupleDesc dsc); + /* Condition function declaration */ static bool is_multidb(void); static bool is_singledb_exists_userdb(void); + /* Rule validation function declaration */ static bool check_exist(void *arg, HeapTuple tuple); static bool check_rules(Rule rules[], size_t num_rules, HeapTuple tuple, TupleDesc dsc, Tuplestorestate *res_tupstore, TupleDesc res_tupdesc); -static bool check_must_match_rules(Rule rules[], size_t num_rules, Oid catalog_oid, +static bool check_must_match_rules(Rule rules[], size_t num_rules, Oid catalog_oid, Tuplestorestate *res_tupstore, TupleDesc res_tupdesc); + /* Helper function declaration */ static void update_report(Rule *rule, Tuplestorestate *res_tupstore, TupleDesc res_tupdesc); static void init_catalog_data(void); static void get_catalog_info(Rule *rule); static void create_guest_role_for_db(const char *dbname); static char *get_db_owner_role_name(const char *dbname); + /* Helper function Rename BBF catalog update*/ static void rename_view_update_bbf_catalog(RenameStmt *stmt); static void rename_procfunc_update_bbf_catalog(RenameStmt *stmt); @@ -1380,10 +1400,10 @@ static void rename_procfunc_update_bbf_catalog(RenameStmt *stmt); /***************************************** * Catalog Extra Info * --------------------------------------- - * MUST also edit init_catalog_data() when + * MUST also edit init_catalog_data() when * editing the listed catalogs here. *****************************************/ -RelData catalog_data[] = +RelData catalog_data[] = { {"babelfish_sysdatabases", InvalidOid, InvalidOid, true, InvalidOid, Anum_sysdatabaese_name, F_TEXTEQ}, {"babelfish_namespace_ext", InvalidOid, InvalidOid, true, InvalidOid, Anum_namespace_ext_namespace, F_NAMEEQ}, @@ -1393,106 +1413,106 @@ RelData catalog_data[] = {"pg_authid", InvalidOid, InvalidOid, true, InvalidOid, Anum_pg_authid_rolname, F_NAMEEQ}, {"pg_proc", InvalidOid, InvalidOid, false, InvalidOid, Anum_pg_proc_proname, F_NAMEEQ} }; - + /***************************************** * Rule Definitions * --------------------------------------- * 1. Must have rule * A.a must have some value V * 2. Must match rule - * B->A, if we have a value V2 in B.b, + * B->A, if we have a value V2 in B.b, * then A.a should have value V1 *****************************************/ /* Must have rules */ -Rule must_have_rules[] = +Rule must_have_rules[] = { {"master must exist in babelfish_sysdatabases", - "babelfish_sysdatabases", "name", NULL, get_master, NULL, check_exist, NULL}, + "babelfish_sysdatabases", "name", NULL, get_master, NULL, check_exist, NULL}, {"tempdb must exist in babelfish_sysdatabases", - "babelfish_sysdatabases", "name", NULL, get_tempdb, NULL, check_exist, NULL}, + "babelfish_sysdatabases", "name", NULL, get_tempdb, NULL, check_exist, NULL}, {"msdb must exist in babelfish_sysdatabases", - "babelfish_sysdatabases", "name", NULL, get_msdb, NULL, check_exist, NULL}, + "babelfish_sysdatabases", "name", NULL, get_msdb, NULL, check_exist, NULL}, {"Current role name must exist in babelfish_authid_login_ext", - "babelfish_authid_login_ext", "rolname", NULL, get_cur_rolname, NULL, check_exist, NULL}, + "babelfish_authid_login_ext", "rolname", NULL, get_cur_rolname, NULL, check_exist, NULL}, {"master_dbo must exist in babelfish_namespace_ext", - "babelfish_namespace_ext", "nspname", NULL, get_master_dbo, NULL, check_exist, NULL}, + "babelfish_namespace_ext", "nspname", NULL, get_master_dbo, NULL, check_exist, NULL}, {"tempdb_dbo must exist in babelfish_namespace_ext", - "babelfish_namespace_ext", "nspname", NULL, get_tempdb_dbo, NULL, check_exist, NULL}, + "babelfish_namespace_ext", "nspname", NULL, get_tempdb_dbo, NULL, check_exist, NULL}, {"msdb_dbo must exist in babelfish_namespace_ext", - "babelfish_namespace_ext", "nspname", NULL, get_msdb_dbo, NULL, check_exist, NULL}, + "babelfish_namespace_ext", "nspname", NULL, get_msdb_dbo, NULL, check_exist, NULL}, {"In single-db mode, if user db exists, dbo must exist in babelfish_namespace_ext", - "babelfish_namespace_ext", "nspname", NULL, get_dbo, is_singledb_exists_userdb, check_exist, NULL}, + "babelfish_namespace_ext", "nspname", NULL, get_dbo, is_singledb_exists_userdb, check_exist, NULL}, {"In single-db mode, if user db exists, db_owner must exist in babelfish_authid_user_ext", - "babelfish_authid_user_ext", "rolname", NULL, get_db_owner, is_singledb_exists_userdb, check_exist, NULL}, + "babelfish_authid_user_ext", "rolname", NULL, get_db_owner, is_singledb_exists_userdb, check_exist, NULL}, {"In single-db mode, if user db exists, dbo must exist in babelfish_authid_user_ext", - "babelfish_authid_user_ext", "rolname", NULL, get_dbo, is_singledb_exists_userdb, check_exist, NULL}, + "babelfish_authid_user_ext", "rolname", NULL, get_dbo, is_singledb_exists_userdb, check_exist, NULL}, {"master_db_owner must exist in babelfish_authid_user_ext", - "babelfish_authid_user_ext", "rolname", NULL, get_master_db_owner, NULL, check_exist, NULL}, + "babelfish_authid_user_ext", "rolname", NULL, get_master_db_owner, NULL, check_exist, NULL}, {"master_dbo must exist in babelfish_authid_user_ext", - "babelfish_authid_user_ext", "rolname", NULL, get_master_dbo, NULL, check_exist, NULL}, + "babelfish_authid_user_ext", "rolname", NULL, get_master_dbo, NULL, check_exist, NULL}, {"tempdb_db_owner must exist in babelfish_authid_user_ext", - "babelfish_authid_user_ext", "rolname", NULL, get_tempdb_db_owner, NULL, check_exist, NULL}, + "babelfish_authid_user_ext", "rolname", NULL, get_tempdb_db_owner, NULL, check_exist, NULL}, {"tempdb_dbo must exist in babelfish_authid_user_ext", - "babelfish_authid_user_ext", "rolname", NULL, get_tempdb_dbo, NULL, check_exist, NULL}, + "babelfish_authid_user_ext", "rolname", NULL, get_tempdb_dbo, NULL, check_exist, NULL}, {"msdb_db_owner must exist in babelfish_authid_user_ext", - "babelfish_authid_user_ext", "rolname", NULL, get_msdb_db_owner, NULL, check_exist, NULL}, + "babelfish_authid_user_ext", "rolname", NULL, get_msdb_db_owner, NULL, check_exist, NULL}, {"msdb_dbo must exist in babelfish_authid_user_ext", - "babelfish_authid_user_ext", "rolname", NULL, get_msdb_dbo, NULL, check_exist, NULL} + "babelfish_authid_user_ext", "rolname", NULL, get_msdb_dbo, NULL, check_exist, NULL} }; /* Must match rules, MUST comply with metadata_inconsistency_check() */ /* babelfish_sysdatabases */ -Rule must_match_rules_sysdb[] = +Rule must_match_rules_sysdb[] = { - {" in babelfish_sysdatabases must also exist in babelfish_authid_login_ext", - "babelfish_authid_login_ext", "rolname", NULL, get_owner, NULL, check_exist, NULL}, + {" in babelfish_sysdatabases must also exist in babelfish_authid_login_ext", + "babelfish_authid_login_ext", "rolname", NULL, get_owner, NULL, check_exist, NULL}, {"In multi-db mode, for each in babelfish_sysdatabases, _db_owner must also exist in pg_authid", - "pg_authid", "rolname", NULL, get_name_db_owner, is_multidb, check_exist, NULL}, + "pg_authid", "rolname", NULL, get_name_db_owner, is_multidb, check_exist, NULL}, {"In multi-db mode, for each in babelfish_sysdatabases, _dbo must also exist in pg_authid", - "pg_authid", "rolname", NULL, get_name_dbo, is_multidb, check_exist, NULL}, + "pg_authid", "rolname", NULL, get_name_dbo, is_multidb, check_exist, NULL}, {"In multi-db mode, for each in babelfish_sysdatabases, _dbo must also exist in babelfish_namespace_ext", - "babelfish_namespace_ext", "nspname", NULL, get_name_dbo, is_multidb, check_exist, NULL}, + "babelfish_namespace_ext", "nspname", NULL, get_name_dbo, is_multidb, check_exist, NULL}, {"In multi-db mode, for each in babelfish_sysdatabases, _guest must also exist in babelfish_authid_user_ext", - "babelfish_authid_user_ext", "rolname", NULL, get_name_guest, is_multidb, check_exist, NULL}, + "babelfish_authid_user_ext", "rolname", NULL, get_name_guest, is_multidb, check_exist, NULL}, {"In single-db mode, for each in babelfish_sysdatabases, _guest must also exist in babelfish_authid_user_ext", - "babelfish_authid_user_ext", "rolname", NULL, get_name_guest, is_singledb_exists_userdb, check_exist, NULL} + "babelfish_authid_user_ext", "rolname", NULL, get_name_guest, is_singledb_exists_userdb, check_exist, NULL} }; /* babelfish_namespace_ext */ -Rule must_match_rules_nsp[] = +Rule must_match_rules_nsp[] = { {" in babelfish_namespace_ext must also exist in pg_namespace", - "pg_namespace", "nspname", NULL, get_nspname, NULL, check_exist, NULL} + "pg_namespace", "nspname", NULL, get_nspname, NULL, check_exist, NULL} }; /* babelfish_authid_login_ext */ -Rule must_match_rules_login[] = +Rule must_match_rules_login[] = { {" in babelfish_authid_login_ext must also exist in pg_authid", - "pg_authid", "rolname", NULL, get_login_rolname, NULL, check_exist, NULL}, + "pg_authid", "rolname", NULL, get_login_rolname, NULL, check_exist, NULL}, {" in babelfish_authid_login_ext must also exist in babelfish_sysdatabases", - "babelfish_sysdatabases", "name", NULL, get_default_database_name, NULL, check_exist, NULL} + "babelfish_sysdatabases", "name", NULL, get_default_database_name, NULL, check_exist, NULL} }; /* babelfish_authid_user_ext */ -Rule must_match_rules_user[] = +Rule must_match_rules_user[] = { {" in babelfish_authid_user_ext must also exist in pg_authid", - "pg_authid", "rolname", NULL, get_user_rolname, NULL, check_exist, NULL}, + "pg_authid", "rolname", NULL, get_user_rolname, NULL, check_exist, NULL}, {" in babelfish_authid_user_ext must also exist in babelfish_sysdatabases", - "babelfish_sysdatabases", "name", NULL, get_database_name, NULL, check_exist, NULL} + "babelfish_sysdatabases", "name", NULL, get_database_name, NULL, check_exist, NULL} }; /* babelfish_function_ext */ -Rule must_match_rules_function[] = +Rule must_match_rules_function[] = { {" in babelfish_function_ext must also exist in babelfish_namespace_ext", - "babelfish_namespace_ext", "nspname", NULL, get_function_nspname, NULL, check_exist, NULL}, + "babelfish_namespace_ext", "nspname", NULL, get_function_nspname, NULL, check_exist, NULL}, {" in babelfish_function_ext must also exist in pg_proc", - "pg_proc", "proname", NULL, get_function_name, NULL, check_exist, NULL} + "pg_proc", "proname", NULL, get_function_name, NULL, check_exist, NULL} }; - + /***************************************** * Core function *****************************************/ @@ -1507,51 +1527,51 @@ PG_FUNCTION_INFO_V1(babelfish_inconsistent_metadata); Datum babelfish_inconsistent_metadata(PG_FUNCTION_ARGS) { - ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - MemoryContext per_query_ctx; - MemoryContext oldcontext; - TupleDesc tupdesc; - Tuplestorestate *tupstore; + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + MemoryContext per_query_ctx; + MemoryContext oldcontext; + TupleDesc tupdesc; + Tuplestorestate *tupstore; return_consistency = PG_GETARG_BOOL(0); - /* check to see if caller supports us returning a tuplestore */ - if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("set-valued function called in context that cannot accept a set"))); - if (!(rsinfo->allowedModes & SFRM_Materialize)) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("materialize mode required, but it is not " \ - "allowed in this context"))); - - /* need to build tuplestore in query context */ - per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; - oldcontext = MemoryContextSwitchTo(per_query_ctx); - - /* - * build tupdesc for result tuples. - */ - tupdesc = CreateTemplateTupleDesc(4); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "object_type", - VARCHAROID, 32, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "schema_name", - VARCHAROID, 128, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 3, "object_name", - VARCHAROID, 128, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 4, "detail", - JSONBOID, -1, 0); - tupstore = - tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random, - false, 1024); - - /* generate junk in short-term context */ - MemoryContextSwitchTo(oldcontext); + /* check to see if caller supports us returning a tuplestore */ + if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("set-valued function called in context that cannot accept a set"))); + if (!(rsinfo->allowedModes & SFRM_Materialize)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("materialize mode required, but it is not " \ + "allowed in this context"))); + + /* need to build tuplestore in query context */ + per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; + oldcontext = MemoryContextSwitchTo(per_query_ctx); + + /* + * build tupdesc for result tuples. + */ + tupdesc = CreateTemplateTupleDesc(4); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "object_type", + VARCHAROID, 32, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "schema_name", + VARCHAROID, 128, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "object_name", + VARCHAROID, 128, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 4, "detail", + JSONBOID, -1, 0); + tupstore = + tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random, + false, 1024); + + /* generate junk in short-term context */ + MemoryContextSwitchTo(oldcontext); PG_TRY(); { - if(metadata_inconsistency_check_enabled()) + if (metadata_inconsistency_check_enabled()) { /* Check metadata inconsistency */ metadata_inconsistency_check(tupstore, tupdesc); @@ -1576,31 +1596,31 @@ babelfish_inconsistent_metadata(PG_FUNCTION_ARGS) static void metadata_inconsistency_check(Tuplestorestate *res_tupstore, TupleDesc res_tupdesc) { - size_t num_must_have_rules = sizeof(must_have_rules) / sizeof(must_have_rules[0]); - size_t num_must_match_rules_sysdb = sizeof(must_match_rules_sysdb) / sizeof(must_match_rules_sysdb[0]); - size_t num_must_match_rules_nsp = sizeof(must_match_rules_nsp) / sizeof(must_match_rules_nsp[0]); - size_t num_must_match_rules_login = sizeof(must_match_rules_login) / sizeof(must_match_rules_login[0]); - size_t num_must_match_rules_user = sizeof(must_match_rules_user) / sizeof(must_match_rules_user[0]); - size_t num_must_match_rules_function = sizeof(must_match_rules_function) / sizeof(must_match_rules_function[0]); + size_t num_must_have_rules = sizeof(must_have_rules) / sizeof(must_have_rules[0]); + size_t num_must_match_rules_sysdb = sizeof(must_match_rules_sysdb) / sizeof(must_match_rules_sysdb[0]); + size_t num_must_match_rules_nsp = sizeof(must_match_rules_nsp) / sizeof(must_match_rules_nsp[0]); + size_t num_must_match_rules_login = sizeof(must_match_rules_login) / sizeof(must_match_rules_login[0]); + size_t num_must_match_rules_user = sizeof(must_match_rules_user) / sizeof(must_match_rules_user[0]); + size_t num_must_match_rules_function = sizeof(must_match_rules_function) / sizeof(must_match_rules_function[0]); /* Initialize the catalog_data array to fetch catalog info */ init_catalog_data(); - /* + /* * If any of the following function call returns false, that means an * inconsistency is detected AND stop_at_first_error is set to true, thus * we should immediately stop checking and output the result */ if ( - /* Must have rules */ + /* Must have rules */ !(check_rules(must_have_rules, num_must_have_rules, NULL, NULL, res_tupstore, res_tupdesc)) - /* Must match rules, MUST comply with the defined must match rules */ + /* Must match rules, MUST comply with the defined must match rules */ || - !(check_must_match_rules(must_match_rules_sysdb, num_must_match_rules_sysdb, + !(check_must_match_rules(must_match_rules_sysdb, num_must_match_rules_sysdb, sysdatabases_oid, res_tupstore, res_tupdesc)) || - !(check_must_match_rules(must_match_rules_nsp, num_must_match_rules_nsp, - namespace_ext_oid, res_tupstore, res_tupdesc)) + !(check_must_match_rules(must_match_rules_nsp, num_must_match_rules_nsp, + namespace_ext_oid, res_tupstore, res_tupdesc)) || !(check_must_match_rules(must_match_rules_login, num_must_match_rules_login, bbf_authid_login_ext_oid, res_tupstore, res_tupdesc)) @@ -1610,11 +1630,11 @@ metadata_inconsistency_check(Tuplestorestate *res_tupstore, TupleDesc res_tupdes || !(check_must_match_rules(must_match_rules_function, num_must_match_rules_function, bbf_function_ext_oid, res_tupstore, res_tupdesc)) - ) + ) return; } -/* +/* * Check all rules in a rule array. * It only returns false when an inconsistency is detected AND * stop_at_first_error is set to true. @@ -1626,7 +1646,7 @@ check_rules(Rule rules[], size_t num_rules, HeapTuple tuple, TupleDesc dsc, { for (size_t i = 0; i < num_rules; i++) { - Rule *rule = &(rules[i]); + Rule *rule = &(rules[i]); /* Check the rule's required condition */ if (rule->func_cond && !(rule->func_cond) ()) @@ -1664,25 +1684,25 @@ check_rules(Rule rules[], size_t num_rules, HeapTuple tuple, TupleDesc dsc, return true; } -/* +/* * Check a set of must match rules that depend on a certain catalog. * It only returns false when an inconsistency is detected AND * stop_at_first_error is set to true. */ static bool -check_must_match_rules(Rule rules[], size_t num_rules, Oid catalog_oid, +check_must_match_rules(Rule rules[], size_t num_rules, Oid catalog_oid, Tuplestorestate *res_tupstore, TupleDesc res_tupdesc) { - HeapTuple tuple; - TupleDesc dsc; - SysScanDesc scan; - Relation rel; + HeapTuple tuple; + TupleDesc dsc; + SysScanDesc scan; + Relation rel; /* Rules depending on the catalog */ rel = table_open(catalog_oid, AccessShareLock); dsc = RelationGetDescr(rel); scan = systable_beginscan(rel, 0, false, NULL, 0, NULL); - + PG_TRY(); { while (HeapTupleIsValid(tuple = systable_getnext(scan))) @@ -1699,9 +1719,9 @@ check_must_match_rules(Rule rules[], size_t num_rules, Oid catalog_oid, PG_FINALLY(); { if (scan) - systable_endscan(scan); + systable_endscan(scan); if (rel) - table_close(rel, AccessShareLock); + table_close(rel, AccessShareLock); } PG_END_TRY(); @@ -1733,7 +1753,8 @@ get_msdb(HeapTuple tuple, TupleDesc dsc) static Datum get_cur_rolname(HeapTuple tuple, TupleDesc dsc) { - char *rolname = GetUserNameFromId(GetSessionUserId(), false); + char *rolname = GetUserNameFromId(GetSessionUserId(), false); + truncate_identifier(rolname, strlen(rolname), false); return CStringGetDatum(rolname); } @@ -1790,6 +1811,7 @@ static Datum get_owner(HeapTuple tuple, TupleDesc dsc) { Form_sysdatabases sysdb = ((Form_sysdatabases) GETSTRUCT(tuple)); + return NameGetDatum(&(sysdb->owner)); } @@ -1798,8 +1820,8 @@ get_name_db_owner(HeapTuple tuple, TupleDesc dsc) { Form_sysdatabases sysdb = ((Form_sysdatabases) GETSTRUCT(tuple)); const text *name = &(sysdb->name); - char *name_str = text_to_cstring(name); - char *name_db_owner = palloc0(MAX_BBF_NAMEDATALEND); + char *name_str = text_to_cstring(name); + char *name_db_owner = palloc0(MAX_BBF_NAMEDATALEND); truncate_identifier(name_str, strlen(name_str), false); snprintf(name_db_owner, MAX_BBF_NAMEDATALEND, "%s_db_owner", name_str); @@ -1812,8 +1834,8 @@ get_name_dbo(HeapTuple tuple, TupleDesc dsc) { Form_sysdatabases sysdb = ((Form_sysdatabases) GETSTRUCT(tuple)); const text *name = &(sysdb->name); - char *name_str = text_to_cstring(name); - char *name_dbo = palloc0(MAX_BBF_NAMEDATALEND); + char *name_str = text_to_cstring(name); + char *name_dbo = palloc0(MAX_BBF_NAMEDATALEND); truncate_identifier(name_str, strlen(name_str), false); snprintf(name_dbo, MAX_BBF_NAMEDATALEND, "%s_dbo", name_str); @@ -1826,8 +1848,8 @@ get_name_guest(HeapTuple tuple, TupleDesc dsc) { Form_sysdatabases sysdb = ((Form_sysdatabases) GETSTRUCT(tuple)); const text *name = &(sysdb->name); - char *name_str = text_to_cstring(name); - char *name_dbo = palloc0(MAX_BBF_NAMEDATALEND); + char *name_str = text_to_cstring(name); + char *name_dbo = palloc0(MAX_BBF_NAMEDATALEND); truncate_identifier(name_str, strlen(name_str), false); snprintf(name_dbo, MAX_BBF_NAMEDATALEND, "%s_guest", name_str); @@ -1838,8 +1860,9 @@ get_name_guest(HeapTuple tuple, TupleDesc dsc) static Datum get_nspname(HeapTuple tuple, TupleDesc dsc) { - bool isNull; - Datum nspname = heap_getattr(tuple, Anum_namespace_ext_namespace, dsc, &isNull); + bool isNull; + Datum nspname = heap_getattr(tuple, Anum_namespace_ext_namespace, dsc, &isNull); + return nspname; } @@ -1847,6 +1870,7 @@ static Datum get_login_rolname(HeapTuple tuple, TupleDesc dsc) { Form_authid_login_ext authid = ((Form_authid_login_ext) GETSTRUCT(tuple)); + return NameGetDatum(&(authid->rolname)); } @@ -1854,6 +1878,7 @@ static Datum get_default_database_name(HeapTuple tuple, TupleDesc dsc) { Form_authid_login_ext authid = ((Form_authid_login_ext) GETSTRUCT(tuple)); + return PointerGetDatum(&(authid->default_database_name)); } @@ -1861,14 +1886,16 @@ static Datum get_user_rolname(HeapTuple tuple, TupleDesc dsc) { Form_authid_user_ext authid = ((Form_authid_user_ext) GETSTRUCT(tuple)); + return NameGetDatum(&(authid->rolname)); } static Datum get_database_name(HeapTuple tuple, TupleDesc dsc) { - bool isNull; - Datum dbname = heap_getattr(tuple, Anum_bbf_authid_user_ext_database_name, dsc, &isNull); + bool isNull; + Datum dbname = heap_getattr(tuple, Anum_bbf_authid_user_ext_database_name, dsc, &isNull); + return dbname; } @@ -1876,6 +1903,7 @@ static Datum get_function_nspname(HeapTuple tuple, TupleDesc dsc) { Form_bbf_function_ext func = ((Form_bbf_function_ext) GETSTRUCT(tuple)); + return NameGetDatum(&(func->schema)); } @@ -1883,6 +1911,7 @@ static Datum get_function_name(HeapTuple tuple, TupleDesc dsc) { Form_bbf_function_ext func = ((Form_bbf_function_ext) GETSTRUCT(tuple)); + return NameGetDatum(&(func->funcname)); } @@ -1909,12 +1938,12 @@ is_multidb(void) static bool check_exist(void *arg, HeapTuple tuple) { - bool found; - Relation rel; - SysScanDesc scan; - ScanKeyData scanKey; - Rule *rule; - Datum datum; + bool found; + Relation rel; + SysScanDesc scan; + ScanKeyData scanKey; + Rule *rule; + Datum datum; rule = (Rule *) arg; @@ -1929,10 +1958,10 @@ check_exist(void *arg, HeapTuple tuple) /* Get the wanted datum through value function */ datum = (rule->func_val) (tuple, rule->tupdesc); - ScanKeyInit(&scanKey, - rule->tbldata->attnum, - BTEqualStrategyNumber, - rule->tbldata->regproc, + ScanKeyInit(&scanKey, + rule->tbldata->attnum, + BTEqualStrategyNumber, + rule->tbldata->regproc, datum); scan = systable_beginscan(rel, rule->tbldata->idx_oid, rule->tbldata->index_ok, NULL, 1, &scanKey); @@ -1950,17 +1979,17 @@ check_exist(void *arg, HeapTuple tuple) * Helper functions *****************************************/ -static void +static void update_report(Rule *rule, Tuplestorestate *res_tupstore, TupleDesc res_tupdesc) { Datum values[4]; bool nulls[4]; - const char *object_type; - const char *schema_name; - const char *object_name = rule->colname; + const char *object_type; + const char *schema_name; + const char *object_name = rule->colname; int str_len = strlen(rule->desc) + strlen("{\"Rule\":\"\"}") + 1; - char *detail = palloc0(str_len); - Jsonb *detail_jsonb; + char *detail = palloc0(str_len); + Jsonb *detail_jsonb; snprintf(detail, str_len, "{\"Rule\":\"%s\"}", rule->desc); detail_jsonb = DatumGetJsonbP(DirectFunctionCall1(jsonb_in, CStringGetDatum(detail))); @@ -2046,8 +2075,8 @@ init_catalog_data(void) static void get_catalog_info(Rule *rule) { - size_t num_catalog = sizeof(catalog_data) / sizeof(catalog_data[0]); - size_t i = 0; + size_t num_catalog = sizeof(catalog_data) / sizeof(catalog_data[0]); + size_t i = 0; for (; i < num_catalog; i++) { @@ -2060,7 +2089,7 @@ get_catalog_info(Rule *rule) if (i == num_catalog) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Failed to find \"%s\" in the pre-defined catalog data array", + errmsg("Failed to find \"%s\" in the pre-defined catalog data array", rule->tblname))); } @@ -2071,21 +2100,21 @@ get_catalog_info(Rule *rule) void alter_user_can_connect(bool is_grant, char *user_name, char *db_name) { - Relation bbf_authid_user_ext_rel; - TupleDesc bbf_authid_user_ext_dsc; - ScanKeyData key[2]; - HeapTuple usertuple; - HeapTuple new_tuple; - TableScanDesc tblscan; - Datum new_record_user_ext[BBF_AUTHID_USER_EXT_NUM_COLS]; - bool new_record_nulls_user_ext[BBF_AUTHID_USER_EXT_NUM_COLS]; - bool new_record_repl_user_ext[BBF_AUTHID_USER_EXT_NUM_COLS]; + Relation bbf_authid_user_ext_rel; + TupleDesc bbf_authid_user_ext_dsc; + ScanKeyData key[2]; + HeapTuple usertuple; + HeapTuple new_tuple; + TableScanDesc tblscan; + Datum new_record_user_ext[BBF_AUTHID_USER_EXT_NUM_COLS]; + bool new_record_nulls_user_ext[BBF_AUTHID_USER_EXT_NUM_COLS]; + bool new_record_repl_user_ext[BBF_AUTHID_USER_EXT_NUM_COLS]; bbf_authid_user_ext_rel = table_open(get_authid_user_ext_oid(), RowExclusiveLock); bbf_authid_user_ext_dsc = RelationGetDescr(bbf_authid_user_ext_rel); - /* Search and obtain the tuple based on the user name and db name */ + /* Search and obtain the tuple based on the user name and db name */ ScanKeyInit(&key[0], Anum_bbf_authid_user_ext_orig_username, BTEqualStrategyNumber, F_TEXTEQ, @@ -2107,9 +2136,12 @@ alter_user_can_connect(bool is_grant, char *user_name, char *db_name) if (!HeapTupleIsValid(usertuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("Cannot find the user \"%s\", because it does not exist or you do not have permission.", user_name))); + errmsg("Cannot find the user \"%s\", because it does not exist or you do not have permission.", user_name))); - /* Update the column user_can_connect to 1 in case of GRANT and to 0 in case of REVOKE */ + /* + * Update the column user_can_connect to 1 in case of GRANT and to 0 in + * case of REVOKE + */ if (is_grant) new_record_user_ext[USER_EXT_USER_CAN_CONNECT] = Int32GetDatum(1); else @@ -2135,11 +2167,11 @@ alter_user_can_connect(bool is_grant, char *user_name, char *db_name) bool guest_has_dbaccess(const char *db_name) { - Relation bbf_authid_user_ext_rel; - HeapTuple tuple_user_ext; - ScanKeyData key[3]; - TableScanDesc scan; - bool has_access = false; + Relation bbf_authid_user_ext_rel; + HeapTuple tuple_user_ext; + ScanKeyData key[3]; + TableScanDesc scan; + bool has_access = false; bbf_authid_user_ext_rel = table_open(get_authid_user_ext_oid(), RowExclusiveLock); @@ -2168,12 +2200,13 @@ guest_has_dbaccess(const char *db_name) } PG_FUNCTION_INFO_V1(update_user_catalog_for_guest); -Datum update_user_catalog_for_guest(PG_FUNCTION_ARGS) +Datum +update_user_catalog_for_guest(PG_FUNCTION_ARGS) { - Relation db_rel; - TableScanDesc scan; - HeapTuple tuple; - bool is_null; + Relation db_rel; + TableScanDesc scan; + HeapTuple tuple; + bool is_null; db_rel = table_open(sysdatabases_oid, AccessShareLock); scan = table_beginscan_catalog(db_rel, 0, NULL); @@ -2181,14 +2214,13 @@ Datum update_user_catalog_for_guest(PG_FUNCTION_ARGS) while (HeapTupleIsValid(tuple)) { - Datum db_name_datum = heap_getattr(tuple, Anum_sysdatabaese_name, - db_rel->rd_att, &is_null); - const char *db_name = TextDatumGetCString(db_name_datum); + Datum db_name_datum = heap_getattr(tuple, Anum_sysdatabaese_name, + db_rel->rd_att, &is_null); + const char *db_name = TextDatumGetCString(db_name_datum); /* - * For each database, check if the guest user exists. - * If exists, check the next database. - * If not, create the guest user on that database. + * For each database, check if the guest user exists. If exists, check + * the next database. If not, create the guest user on that database. */ if (guest_role_exists_for_db(db_name)) { @@ -2206,16 +2238,16 @@ Datum update_user_catalog_for_guest(PG_FUNCTION_ARGS) bool guest_role_exists_for_db(const char *dbname) { - const char *guest_role = get_guest_role_name(dbname); + const char *guest_role = get_guest_role_name(dbname); bool role_exists = false; Relation bbf_authid_user_ext_rel; HeapTuple tuple; - ScanKeyData scanKey; - SysScanDesc scan; + ScanKeyData scanKey; + SysScanDesc scan; /* Fetch the relation */ bbf_authid_user_ext_rel = table_open(get_authid_user_ext_oid(), - RowExclusiveLock); + RowExclusiveLock); /* Search if the role exists */ ScanKeyInit(&scanKey, @@ -2241,18 +2273,18 @@ guest_role_exists_for_db(const char *dbname) static void create_guest_role_for_db(const char *dbname) { - const char *guest = get_guest_role_name(dbname); - const char *db_owner_role = get_db_owner_role_name(dbname); - List *logins = NIL; - List *res; - StringInfoData query; - Node *stmt; - ListCell *res_item; - int i = 0; - const char *prev_current_user; - int16 old_dbid; - char *old_dbname; - int16 dbid = get_db_id(dbname); + const char *guest = get_guest_role_name(dbname); + const char *db_owner_role = get_db_owner_role_name(dbname); + List *logins = NIL; + List *res; + StringInfoData query; + Node *stmt; + ListCell *res_item; + int i = 0; + const char *prev_current_user; + int16 old_dbid; + char *old_dbname; + int16 dbid = get_db_id(dbname); initStringInfo(&query); appendStringInfo(&query, "CREATE ROLE dummy INHERIT ROLE dummy; "); @@ -2267,6 +2299,7 @@ create_guest_role_for_db(const char *dbname) if (list_length(logins) > 0) { AccessPriv *tmp = makeNode(AccessPriv); + tmp->priv_name = pstrdup(guest); tmp->cols = NIL; @@ -2281,7 +2314,7 @@ create_guest_role_for_db(const char *dbname) old_dbid = get_cur_db_id(); old_dbname = get_cur_db_name(); - set_cur_db(dbid, dbname); /* temporarily set current dbid as the new id */ + set_cur_db(dbid, dbname); /* temporarily set current dbid as the new id */ PG_TRY(); { @@ -2303,11 +2336,11 @@ create_guest_role_for_db(const char *dbname) ProcessUtility(wrapper, "(CREATE LOGICAL DATABASE )", false, - PROCESS_UTILITY_SUBCOMMAND, - NULL, - NULL, - None_Receiver, - NULL); + PROCESS_UTILITY_SUBCOMMAND, + NULL, + NULL, + None_Receiver, + NULL); /* make sure later steps can see the object created here */ CommandCounterIncrement(); @@ -2338,9 +2371,9 @@ get_db_owner_role_name(const char *dbname) { Relation bbf_authid_user_ext_rel; HeapTuple tuple_user_ext; - ScanKeyData key[2]; - TableScanDesc scan; - char *db_owner_role = NULL; + ScanKeyData key[2]; + TableScanDesc scan; + char *db_owner_role = NULL; bbf_authid_user_ext_rel = table_open(get_authid_user_ext_oid(), RowExclusiveLock); @@ -2357,10 +2390,11 @@ get_db_owner_role_name(const char *dbname) tuple_user_ext = heap_getnext(scan, ForwardScanDirection); if (HeapTupleIsValid(tuple_user_ext)) - { - Form_authid_user_ext userform = (Form_authid_user_ext) GETSTRUCT(tuple_user_ext); - db_owner_role = pstrdup(NameStr(userform->rolname)); - } + { + Form_authid_user_ext userform = (Form_authid_user_ext) GETSTRUCT(tuple_user_ext); + + db_owner_role = pstrdup(NameStr(userform->rolname)); + } table_endscan(scan); table_close(bbf_authid_user_ext_rel, RowExclusiveLock); @@ -2371,7 +2405,7 @@ void rename_update_bbf_catalog(RenameStmt *stmt) { switch (stmt->renameType) - { + { case OBJECT_TABLE: break; case OBJECT_VIEW: @@ -2386,38 +2420,38 @@ rename_update_bbf_catalog(RenameStmt *stmt) case OBJECT_SEQUENCE: break; default: - break; + break; } } static void rename_view_update_bbf_catalog(RenameStmt *stmt) { - // update the 'object_name' in 'babelfish_view_def' - Relation bbf_view_def_rel; - TupleDesc bbf_view_def_dsc; - ScanKeyData key[3]; - HeapTuple usertuple; - HeapTuple new_tuple; - TableScanDesc tblscan; - Datum new_record_view_def[BBF_VIEW_DEF_NUM_COLS]; - bool new_record_nulls_view_def[BBF_VIEW_DEF_NUM_COLS]; - bool new_record_repl_view_def[BBF_VIEW_DEF_NUM_COLS]; - int16 dbid; - const char *logical_schema_name; - - // build the tuple to insert + /* update the 'object_name' in 'babelfish_view_def' */ + Relation bbf_view_def_rel; + TupleDesc bbf_view_def_dsc; + ScanKeyData key[3]; + HeapTuple usertuple; + HeapTuple new_tuple; + TableScanDesc tblscan; + Datum new_record_view_def[BBF_VIEW_DEF_NUM_COLS]; + bool new_record_nulls_view_def[BBF_VIEW_DEF_NUM_COLS]; + bool new_record_repl_view_def[BBF_VIEW_DEF_NUM_COLS]; + int16 dbid; + const char *logical_schema_name; + + /* build the tuple to insert */ MemSet(new_record_view_def, 0, sizeof(new_record_view_def)); MemSet(new_record_nulls_view_def, false, sizeof(new_record_nulls_view_def)); MemSet(new_record_repl_view_def, false, sizeof(new_record_repl_view_def)); - // open the catalog table + /* open the catalog table */ bbf_view_def_rel = table_open(get_bbf_view_def_oid(), RowExclusiveLock); - // get the description of the table + /* get the description of the table */ bbf_view_def_dsc = RelationGetDescr(bbf_view_def_rel); - // search for the row for update => build the key + /* search for the row for update => build the key */ dbid = get_dbid_from_physical_schema_name(stmt->relation->schemaname, true); ScanKeyInit(&key[0], Anum_bbf_view_def_dbid, @@ -2433,21 +2467,22 @@ rename_view_update_bbf_catalog(RenameStmt *stmt) BTEqualStrategyNumber, F_TEXTEQ, CStringGetTextDatum(stmt->relation->relname)); - // scan + /* scan */ tblscan = table_beginscan_catalog(bbf_view_def_rel, 3, key); - - // get the scan result -> original tuple + + /* get the scan result -> original tuple */ usertuple = heap_getnext(tblscan, ForwardScanDirection); - if (!HeapTupleIsValid(usertuple)) { + if (!HeapTupleIsValid(usertuple)) + { table_endscan(tblscan); table_close(bbf_view_def_rel, RowExclusiveLock); ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("Cannot find the view_name \"%s\", because it does not exist or you do not have permission.", stmt->subname))); + errmsg("Cannot find the view_name \"%s\", because it does not exist or you do not have permission.", stmt->subname))); } - - // create new tuple to substitute + + /* create new tuple to substitute */ new_record_view_def[Anum_bbf_view_def_object_name - 1] = CStringGetTextDatum(stmt->newname); new_record_repl_view_def[Anum_bbf_view_def_object_name - 1] = true; @@ -2468,47 +2503,51 @@ rename_view_update_bbf_catalog(RenameStmt *stmt) static void rename_procfunc_update_bbf_catalog(RenameStmt *stmt) { - // update the 'funcname', 'orig_name', 'funcsignature' in 'babelfish_function_ext' - Relation bbf_func_ext_rel; - TupleDesc bbf_func_ext_dsc; - ScanKeyData key[2]; - HeapTuple usertuple; - HeapTuple sec_tuple; - HeapTuple new_tuple; - TableScanDesc tblscan; - Datum new_record_func_ext[BBF_FUNCTION_EXT_NUM_COLS]; - bool new_record_nulls_func_ext[BBF_FUNCTION_EXT_NUM_COLS]; - bool new_record_repl_func_ext[BBF_FUNCTION_EXT_NUM_COLS]; - NameData *objname_data; - NameData *schemaname_data; - bool is_null; - char *funcsign, *new_funcsign; - Datum funcsign_datum; - Node *schema; - char *schemaname; - ObjectWithArgs *objwargs = (ObjectWithArgs *)stmt->object; - - // build the tuple to insert + /* + * update the 'funcname', 'orig_name', 'funcsignature' in + * 'babelfish_function_ext' + */ + Relation bbf_func_ext_rel; + TupleDesc bbf_func_ext_dsc; + ScanKeyData key[2]; + HeapTuple usertuple; + HeapTuple sec_tuple; + HeapTuple new_tuple; + TableScanDesc tblscan; + Datum new_record_func_ext[BBF_FUNCTION_EXT_NUM_COLS]; + bool new_record_nulls_func_ext[BBF_FUNCTION_EXT_NUM_COLS]; + bool new_record_repl_func_ext[BBF_FUNCTION_EXT_NUM_COLS]; + NameData *objname_data; + NameData *schemaname_data; + bool is_null; + char *funcsign, + *new_funcsign; + Datum funcsign_datum; + Node *schema; + char *schemaname; + ObjectWithArgs *objwargs = (ObjectWithArgs *) stmt->object; + + /* build the tuple to insert */ MemSet(new_record_func_ext, 0, sizeof(new_record_func_ext)); MemSet(new_record_nulls_func_ext, false, sizeof(new_record_nulls_func_ext)); MemSet(new_record_repl_func_ext, false, sizeof(new_record_repl_func_ext)); - // open the catalog table + /* open the catalog table */ bbf_func_ext_rel = table_open(get_bbf_function_ext_oid(), RowExclusiveLock); - // get the description of the table + /* get the description of the table */ bbf_func_ext_dsc = RelationGetDescr(bbf_func_ext_rel); - // search for the row for update => build the key - // Keys: schema_name, obj_name + /* search for the row for update => build the key */ + /* Keys: schema_name, obj_name */ schema = (Node *) linitial(objwargs->objname); schemaname = strVal(schema); schemaname_data = (NameData *) palloc0(NAMEDATALEN); snprintf(schemaname_data->data, NAMEDATALEN, "%s", schemaname); ScanKeyInit(&key[0], - Anum_bbf_function_ext_nspname, - BTEqualStrategyNumber, F_NAMEEQ, - NameGetDatum(schemaname_data)); + Anum_bbf_function_ext_nspname, + BTEqualStrategyNumber, F_NAMEEQ, + NameGetDatum(schemaname_data)); objname_data = (NameData *) palloc0(NAMEDATALEN); snprintf(objname_data->data, NAMEDATALEN, "%s", stmt->subname); ScanKeyInit(&key[1], @@ -2516,21 +2555,22 @@ rename_procfunc_update_bbf_catalog(RenameStmt *stmt) BTEqualStrategyNumber, F_NAMEEQ, NameGetDatum(objname_data)); - // scan + /* scan */ tblscan = table_beginscan_catalog(bbf_func_ext_rel, 2, key); - - // get the scan result -> original tuple + + /* get the scan result -> original tuple */ usertuple = heap_getnext(tblscan, ForwardScanDirection); - if (!HeapTupleIsValid(usertuple)) { + if (!HeapTupleIsValid(usertuple)) + { table_endscan(tblscan); table_close(bbf_func_ext_rel, RowExclusiveLock); ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("Cannot find the object \"%s\", because it does not exist or you do not have permission.", stmt->subname))); + errmsg("Cannot find the object \"%s\", because it does not exist or you do not have permission.", stmt->subname))); } - // create new tuple to substitute + /* create new tuple to substitute */ funcsign_datum = heap_getattr(usertuple, Anum_bbf_function_ext_funcsignature, bbf_func_ext_rel->rd_att, &is_null); funcsign = pstrdup(TextDatumGetCString(funcsign_datum)); @@ -2549,14 +2589,15 @@ rename_procfunc_update_bbf_catalog(RenameStmt *stmt) new_record_nulls_func_ext, new_record_repl_func_ext); - // if there is more than 1 match, throw error + /* if there is more than 1 match, throw error */ sec_tuple = heap_getnext(tblscan, ForwardScanDirection); - if (HeapTupleIsValid(sec_tuple)) { + if (HeapTupleIsValid(sec_tuple)) + { table_endscan(tblscan); table_close(bbf_func_ext_rel, RowExclusiveLock); ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("There are multiple objects with the given name \"%s\".", stmt->subname))); + errmsg("There are multiple objects with the given name \"%s\".", stmt->subname))); } CatalogTupleUpdate(bbf_func_ext_rel, &new_tuple->t_self, new_tuple); @@ -2565,4 +2606,4 @@ rename_procfunc_update_bbf_catalog(RenameStmt *stmt) table_endscan(tblscan); table_close(bbf_func_ext_rel, RowExclusiveLock); -} \ No newline at end of file +} diff --git a/contrib/babelfishpg_tsql/src/catalog.h b/contrib/babelfishpg_tsql/src/catalog.h index 1370eb49bb..d495da4a01 100644 --- a/contrib/babelfishpg_tsql/src/catalog.h +++ b/contrib/babelfishpg_tsql/src/catalog.h @@ -22,7 +22,7 @@ extern bool IsPLtsqlExtendedCatalog(Oid relationId); /***************************************** * SYS schema *****************************************/ -extern Oid sys_schema_oid; +extern Oid sys_schema_oid; /***************************************** * SYSDATABASES @@ -31,9 +31,9 @@ extern Oid sys_schema_oid; #define SYSDATABASES_PK_NAME "babelfish_sysdatabases_pkey" #define SYSDATABASES_OID_IDX_NAME "babelfish_sysdatabases_dboid_key" -extern Oid sysdatabases_oid; -extern Oid sysdatabaese_idx_oid_oid; -extern Oid sysdatabaese_idx_name_oid; +extern Oid sysdatabases_oid; +extern Oid sysdatabaese_idx_oid_oid; +extern Oid sysdatabaese_idx_name_oid; /* MUST comply with babelfish_sysdatabases table */ #define SYSDATABASES_NUM_COLS 8 @@ -44,11 +44,11 @@ extern Oid sysdatabaese_idx_name_oid; /* MUST comply with babelfish_sysdatabases table */ typedef struct FormData_sysdatabases { - int16 dbid; + int16 dbid; int32 status; - int32 status2; - NameData owner; - NameData default_collation; + int32 status2; + NameData owner; + NameData default_collation; text name; TimestampTz crdate; text properties; @@ -59,14 +59,14 @@ typedef FormData_sysdatabases *Form_sysdatabases; /* MUST comply with babelfish_authid_login_ext table */ typedef struct FormData_authid_login_ext { - NameData rolname; + NameData rolname; int32 is_disabled; - char type; - int32 credential_id; - int32 owning_principal_id; - int32 is_fixed_role; - TimestampTz create_date; - TimestampTz modify_date; + char type; + int32 credential_id; + int32 owning_principal_id; + int32 is_fixed_role; + TimestampTz create_date; + TimestampTz modify_date; VarChar default_database_name; VarChar default_language_name; Jsonb properties; @@ -96,9 +96,9 @@ extern bool guest_has_dbaccess(const char *db_name); #define Anum_namespace_ext_orig_name 3 #define NAMESPACE_EXT_NUM_COLS 4 -extern Oid namespace_ext_oid; -extern Oid namespace_ext_idx_oid_oid; -extern int namespace_ext_num_cols; +extern Oid namespace_ext_oid; +extern Oid namespace_ext_idx_oid_oid; +extern int namespace_ext_num_cols; extern const char *get_logical_schema_name(const char *physical_schema_name, bool missingOk); extern int16 get_dbid_from_physical_schema_name(const char *physical_schema_name, bool missingOk); @@ -112,14 +112,14 @@ extern int16 get_dbid_from_physical_schema_name(const char *physical_schema_name #define Anum_bbf_authid_login_ext_type 3 #define Anum_bbf_authid_login_ext_orig_loginname 12 -extern Oid bbf_authid_login_ext_oid; -extern Oid bbf_authid_login_ext_idx_oid; +extern Oid bbf_authid_login_ext_oid; +extern Oid bbf_authid_login_ext_idx_oid; extern bool is_login(Oid role_oid); extern bool is_login_name(char *rolname); extern char *get_login_default_db(char *login_name); -extern Oid get_authid_login_ext_oid(void); -extern Oid get_authid_login_ext_idx_oid(void); +extern Oid get_authid_login_ext_oid(void); +extern Oid get_authid_login_ext_idx_oid(void); /***************************************** * USER EXT @@ -132,13 +132,13 @@ extern Oid get_authid_login_ext_idx_oid(void); #define Anum_bbf_authid_user_ext_database_name 12 #define Anum_bbf_authid_user_ext_default_schema_name 13 #define Anum_bbf_authid_user_ext_user_can_connect 16 -extern Oid bbf_authid_user_ext_oid; -extern Oid bbf_authid_user_ext_idx_oid; +extern Oid bbf_authid_user_ext_oid; +extern Oid bbf_authid_user_ext_idx_oid; extern bool is_user(Oid role_oid); extern bool is_role(Oid role_oid); -extern Oid get_authid_user_ext_oid(void); -extern Oid get_authid_user_ext_idx_oid(void); +extern Oid get_authid_user_ext_oid(void); +extern Oid get_authid_user_ext_idx_oid(void); extern char *get_authid_user_ext_physical_name(const char *db_name, const char *login_name); extern char *get_authid_user_ext_schema_name(const char *db_name, const char *user_name); extern List *get_authid_user_ext_db_users(const char *db_name); @@ -149,7 +149,7 @@ extern bool guest_role_exists_for_db(const char *dbname); /* MUST comply with babelfish_authid_user_ext table */ typedef struct FormData_authid_user_ext { - NameData rolname; + NameData rolname; NameData login_name; BpChar type; int32 owning_principal_id; @@ -157,8 +157,8 @@ typedef struct FormData_authid_user_ext int32 authentication_type; int32 default_language_lcid; int32 allow_encrypted_value_modifications; - TimestampTz create_date; - TimestampTz modify_date; + TimestampTz create_date; + TimestampTz modify_date; VarChar orig_username; VarChar database_name; VarChar default_schema_name; @@ -182,13 +182,13 @@ typedef FormData_authid_user_ext *Form_authid_user_ext; #define BBF_VIEW_DEF_FLAG_IS_ANSI_NULLS_ON (1<<0) #define BBF_VIEW_DEF_FLAG_USES_QUOTED_IDENTIFIER (1<<1) #define BBF_VIEW_DEF_FLAG_CREATED_IN_OR_AFTER_2_4 (0<<2) -extern Oid bbf_view_def_oid; -extern Oid bbf_view_def_idx_oid; +extern Oid bbf_view_def_oid; +extern Oid bbf_view_def_idx_oid; -extern Oid get_bbf_view_def_oid(void); -extern Oid get_bbf_view_def_idx_oid(void); +extern Oid get_bbf_view_def_oid(void); +extern Oid get_bbf_view_def_idx_oid(void); extern HeapTuple search_bbf_view_def(Relation bbf_view_def_rel, int16 dbid, - const char *logical_schema_name, const char *view_name); + const char *logical_schema_name, const char *view_name); extern bool check_is_tsql_view(Oid relid); extern void clean_up_bbf_view_def(int16 dbid); @@ -202,9 +202,9 @@ typedef struct FormData_bbf_view_def uint64 flag_values; Timestamp create_date; Timestamp modify_date; -} FormData_bbf_view_def; +} FormData_bbf_view_def; -typedef FormData_bbf_view_def *Form_bbf_view_def; +typedef FormData_bbf_view_def * Form_bbf_view_def; /***************************************** * FUNCTION_EXT @@ -224,11 +224,11 @@ typedef FormData_bbf_view_def *Form_bbf_view_def; #define BBF_FUNCTION_EXT_NUM_COLS 10 #define FLAG_IS_ANSI_NULLS_ON (1<<0) #define FLAG_USES_QUOTED_IDENTIFIER (1<<1) -extern Oid bbf_function_ext_oid; -extern Oid bbf_function_ext_idx_oid; +extern Oid bbf_function_ext_oid; +extern Oid bbf_function_ext_idx_oid; -extern Oid get_bbf_function_ext_oid(void); -extern Oid get_bbf_function_ext_idx_oid(void); +extern Oid get_bbf_function_ext_oid(void); +extern Oid get_bbf_function_ext_idx_oid(void); extern HeapTuple get_bbf_function_tuple_from_proctuple(HeapTuple proctuple); extern void clean_up_bbf_function_ext(int16 dbid); @@ -258,11 +258,11 @@ typedef FormData_bbf_function_ext *Form_bbf_function_ext; #define Anum_bbf_domain_mapping_fq_domain_name 2 #define BBF_DOMAIN_MAPPING_NUM_COLS 2 -extern Oid bbf_domain_mapping_oid; -extern Oid bbf_domain_mapping_idx_oid; +extern Oid bbf_domain_mapping_oid; +extern Oid bbf_domain_mapping_idx_oid; -extern Oid get_bbf_domain_mapping_oid(void); -extern Oid get_bbf_domain_mapping_idx_oid(void); +extern Oid get_bbf_domain_mapping_oid(void); +extern Oid get_bbf_domain_mapping_idx_oid(void); /***************************************** * Metadata Check Rule @@ -282,13 +282,13 @@ extern Oid get_bbf_domain_mapping_idx_oid(void); */ typedef struct RelData { - const char *tblname; /* table name */ - Oid tbl_oid; /* table oid */ - Oid idx_oid; /* index oid */ - bool index_ok; /* if false, forces a heap scan */ - Oid atttype; /* index column's type oid */ - AttrNumber attnum; /* index column's attribute num */ - RegProcedure regproc; /* regproc used to scan through the index */ + const char *tblname; /* table name */ + Oid tbl_oid; /* table oid */ + Oid idx_oid; /* index oid */ + bool index_ok; /* if false, forces a heap scan */ + Oid atttype; /* index column's type oid */ + AttrNumber attnum; /* index column's attribute num */ + RegProcedure regproc; /* regproc used to scan through the index */ } RelData; /* @@ -306,17 +306,15 @@ typedef struct RelData */ typedef struct Rule { - const char *desc; /* rule description, mandatory field */ - const char *tblname; /* catalog name, mandatory field */ - const char *colname; /* column name, mandatory field */ - - /* - * The expected value should be the result of a value function. - * A value function reads a tuple and output a Datum. - * Must have rules: Input tuple is NULL. - * Must match rules: Input tuple is provided by a catalog (often different - * from tblname. - * tupdesc is the description for the input tuple. + const char *desc; /* rule description, mandatory field */ + const char *tblname; /* catalog name, mandatory field */ + const char *colname; /* column name, mandatory field */ + + /* + * The expected value should be the result of a value function. A value + * function reads a tuple and output a Datum. Must have rules: Input tuple + * is NULL. Must match rules: Input tuple is provided by a catalog (often + * different from tblname. tupdesc is the description for the input tuple. */ TupleDesc tupdesc; Datum (*func_val) (HeapTuple tuple, TupleDesc dsc); @@ -326,7 +324,7 @@ typedef struct Rule /* function to validate the rule */ bool (*func_check) (void *rule_arg, HeapTuple tuple); - RelData *tbldata; /* extra catalog info */ + RelData *tbldata; /* extra catalog info */ } Rule; #endif diff --git a/contrib/babelfishpg_tsql/src/codegen.c b/contrib/babelfishpg_tsql/src/codegen.c index cd54cf60f5..61a7657131 100644 --- a/contrib/babelfishpg_tsql/src/codegen.c +++ b/contrib/babelfishpg_tsql/src/codegen.c @@ -39,83 +39,87 @@ static void destroy_codegen_context(void *ctx); typedef struct { - char label[LABEL_LEN]; - size_t pc; + char label[LABEL_LEN]; + size_t pc; } LabelIndexEntry; typedef struct { - PLtsql_stmt_while *stmt; + PLtsql_stmt_while *stmt; } LoopContext; typedef struct { - ExecCodes *exec_codes; - HTAB *label_index; - DynaStack *loop_contexts; - CompileContext *cmpl_ctx; + ExecCodes *exec_codes; + HTAB *label_index; + DynaStack *loop_contexts; + CompileContext *cmpl_ctx; } CodegenContext; static void add_stmt(CodegenContext *ctx, PLtsql_stmt *stmt); -static Walker_context *make_codegen_context(CompileContext *cmpl_ctx) +static Walker_context * +make_codegen_context(CompileContext *cmpl_ctx) { - Walker_context *context = make_template_context(); - CodegenContext *generator; - HASHCTL hashCtl; - - /* Create Codegen Conext */ - generator = palloc(sizeof(CodegenContext)); - generator->exec_codes = palloc(sizeof(ExecCodes)); - generator->exec_codes->codes = create_vector(sizeof(PLtsql_stmt *)); - generator->exec_codes->proc_namespace = NULL; - generator->exec_codes->proc_name = NULL; - MemSet(&hashCtl, 0, sizeof(hashCtl)); - hashCtl.keysize = LABEL_LEN; - hashCtl.entrysize = sizeof(LabelIndexEntry); - hashCtl.hcxt = CurrentMemoryContext; - generator->label_index = hash_create("Label to index mapping", - 16, /* initial label index hashmap size */ - &hashCtl, - HASH_ELEM | HASH_STRINGS | HASH_CONTEXT ); /* string comp */ - - generator->loop_contexts = create_stack2(sizeof(LoopContext *), 8); - generator->cmpl_ctx = cmpl_ctx; - - /* Traverse actions */ - context->default_act = &stmt_default_act; - context->block_act = &stmt_block_act; - context->if_act = &stmt_if_act; - context->label_act = &stmt_label_act; - context->try_catch_act = &stmt_try_catch_act; - context->while_act = &stmt_while_act; - context->exit_act = &stmt_exit_act; - context->return_act = &stmt_return_act; - context->goto_act = &stmt_goto_act; - - /* Extra context */ - context->extra_ctx = (void *) generator; - context->destroy_extra_ctx = &destroy_codegen_context; - return context; + Walker_context *context = make_template_context(); + CodegenContext *generator; + HASHCTL hashCtl; + + /* Create Codegen Conext */ + generator = palloc(sizeof(CodegenContext)); + generator->exec_codes = palloc(sizeof(ExecCodes)); + generator->exec_codes->codes = create_vector(sizeof(PLtsql_stmt *)); + generator->exec_codes->proc_namespace = NULL; + generator->exec_codes->proc_name = NULL; + MemSet(&hashCtl, 0, sizeof(hashCtl)); + hashCtl.keysize = LABEL_LEN; + hashCtl.entrysize = sizeof(LabelIndexEntry); + hashCtl.hcxt = CurrentMemoryContext; + generator->label_index = hash_create("Label to index mapping", + 16, /* initial label index hashmap + * size */ + &hashCtl, + HASH_ELEM | HASH_STRINGS | HASH_CONTEXT); /* string comp */ + + generator->loop_contexts = create_stack2(sizeof(LoopContext *), 8); + generator->cmpl_ctx = cmpl_ctx; + + /* Traverse actions */ + context->default_act = &stmt_default_act; + context->block_act = &stmt_block_act; + context->if_act = &stmt_if_act; + context->label_act = &stmt_label_act; + context->try_catch_act = &stmt_try_catch_act; + context->while_act = &stmt_while_act; + context->exit_act = &stmt_exit_act; + context->return_act = &stmt_return_act; + context->goto_act = &stmt_goto_act; + + /* Extra context */ + context->extra_ctx = (void *) generator; + context->destroy_extra_ctx = &destroy_codegen_context; + return context; } -static void destroy_codegen_context(void *ctx) +static void +destroy_codegen_context(void *ctx) { - CodegenContext *codegen_ctx = (CodegenContext *) ctx; + CodegenContext *codegen_ctx = (CodegenContext *) ctx; - /* exec_codes ownershipt tranfered to plan, not freed here */ - hash_destroy(codegen_ctx->label_index); + /* exec_codes ownershipt tranfered to plan, not freed here */ + hash_destroy(codegen_ctx->label_index); destroy_stack(codegen_ctx->loop_contexts); - pfree(codegen_ctx); + pfree(codegen_ctx); } -/* +/* * for node added which is not part of tree_node, * shall have corresponging free function called through free_exec_codes */ -static void add_stmt(CodegenContext *ctx, PLtsql_stmt *stmt) +static void +add_stmt(CodegenContext *ctx, PLtsql_stmt *stmt) { - vec_push_back(ctx->exec_codes->codes, &stmt); + vec_push_back(ctx->exec_codes->codes, &stmt); } /*********************************************************************************** @@ -123,196 +127,206 @@ static void add_stmt(CodegenContext *ctx, PLtsql_stmt *stmt) **********************************************************************************/ /* Node creation */ -static PLtsql_stmt_goto *create_goto(int lineno); -static PLtsql_stmt_save_ctx *create_save_ctx(int lineno); -static PLtsql_stmt_restore_ctx_full *create_restore_ctx_full(int lineno); +static PLtsql_stmt_goto *create_goto(int lineno); +static PLtsql_stmt_save_ctx *create_save_ctx(int lineno); +static PLtsql_stmt_restore_ctx_full *create_restore_ctx_full(int lineno); static PLtsql_stmt_restore_ctx_partial *create_restore_ctx_partial(int lineno); /* Label creation */ -static void -create_and_register_label(CodegenContext *codegen_ctx, const char *format, int lineno, void *stmt); +static void + create_and_register_label(CodegenContext *codegen_ctx, const char *format, int lineno, void *stmt); /* handle dangling exception contexts */ static void -cleanup_exception_context(PLtsql_stmt *src, PLtsql_stmt *dst, CodegenContext *codegen_ctx); + cleanup_exception_context(PLtsql_stmt *src, PLtsql_stmt *dst, CodegenContext *codegen_ctx); static void -cleanup_all_exception_context(PLtsql_stmt *src, CodegenContext *codegen_ctx); + cleanup_all_exception_context(PLtsql_stmt *src, CodegenContext *codegen_ctx); -static PLtsql_stmt_goto *create_goto(int lineno) +static PLtsql_stmt_goto * +create_goto(int lineno) { - PLtsql_stmt_goto *stmt_goto; - - stmt_goto = palloc(sizeof(PLtsql_stmt_goto)); - stmt_goto->cmd_type = PLTSQL_STMT_GOTO; - stmt_goto->lineno = lineno; - stmt_goto->cond = NULL; /* unconditional goto */ - stmt_goto->target_pc = -1; - stmt_goto->target_label = palloc0(LABEL_LEN); - return stmt_goto; + PLtsql_stmt_goto *stmt_goto; + + stmt_goto = palloc(sizeof(PLtsql_stmt_goto)); + stmt_goto->cmd_type = PLTSQL_STMT_GOTO; + stmt_goto->lineno = lineno; + stmt_goto->cond = NULL; /* unconditional goto */ + stmt_goto->target_pc = -1; + stmt_goto->target_label = palloc0(LABEL_LEN); + return stmt_goto; } -static PLtsql_stmt_save_ctx *create_save_ctx(int lineno) +static PLtsql_stmt_save_ctx * +create_save_ctx(int lineno) { - PLtsql_stmt_save_ctx *save_ctx = palloc(sizeof(PLtsql_stmt_save_ctx)); + PLtsql_stmt_save_ctx *save_ctx = palloc(sizeof(PLtsql_stmt_save_ctx)); - save_ctx->cmd_type = PLTSQL_STMT_SAVE_CTX; - save_ctx->lineno = lineno; - save_ctx->target_pc = -1; - save_ctx->target_label = palloc0(LABEL_LEN); - return save_ctx; + save_ctx->cmd_type = PLTSQL_STMT_SAVE_CTX; + save_ctx->lineno = lineno; + save_ctx->target_pc = -1; + save_ctx->target_label = palloc0(LABEL_LEN); + return save_ctx; } -static PLtsql_stmt_restore_ctx_full *create_restore_ctx_full(int lineno) +static PLtsql_stmt_restore_ctx_full * +create_restore_ctx_full(int lineno) { - PLtsql_stmt_restore_ctx_full *restore_ctx = palloc(sizeof(PLtsql_stmt_restore_ctx_full)); + PLtsql_stmt_restore_ctx_full *restore_ctx = palloc(sizeof(PLtsql_stmt_restore_ctx_full)); - restore_ctx->cmd_type = PLTSQL_STMT_RESTORE_CTX_FULL; - restore_ctx->lineno = lineno; - return restore_ctx; + restore_ctx->cmd_type = PLTSQL_STMT_RESTORE_CTX_FULL; + restore_ctx->lineno = lineno; + return restore_ctx; } -static PLtsql_stmt_restore_ctx_partial *create_restore_ctx_partial(int lineno) +static PLtsql_stmt_restore_ctx_partial * +create_restore_ctx_partial(int lineno) { - PLtsql_stmt_restore_ctx_partial *restore_ctx = palloc(sizeof(PLtsql_stmt_restore_ctx_partial)); + PLtsql_stmt_restore_ctx_partial *restore_ctx = palloc(sizeof(PLtsql_stmt_restore_ctx_partial)); - restore_ctx->cmd_type = PLTSQL_STMT_RESTORE_CTX_PARTIAL; - restore_ctx->lineno = lineno; - return restore_ctx; + restore_ctx->cmd_type = PLTSQL_STMT_RESTORE_CTX_PARTIAL; + restore_ctx->lineno = lineno; + return restore_ctx; } -static void +static void create_and_register_label(CodegenContext *codegen_ctx, const char *format, int lineno, void *stmt) { - LabelIndexEntry *label_entry; - char buf[LABEL_LEN]; + LabelIndexEntry *label_entry; + char buf[LABEL_LEN]; - snprintf(buf, LABEL_LEN, format, lineno, stmt); - label_entry = - hash_search(codegen_ctx->label_index, buf, HASH_ENTER, NULL); - label_entry->pc = vec_size(codegen_ctx->exec_codes->codes); /* NEXT SLOT */ + snprintf(buf, LABEL_LEN, format, lineno, stmt); + label_entry = + hash_search(codegen_ctx->label_index, buf, HASH_ENTER, NULL); + label_entry->pc = vec_size(codegen_ctx->exec_codes->codes); /* NEXT SLOT */ } static void cleanup_exception_context(PLtsql_stmt *src, PLtsql_stmt *dst, CodegenContext *codegen_ctx) { - CompileContext *cmpl_ctx = codegen_ctx->cmpl_ctx; - ScopeContext *scope_context; - DynaVec *src_trycatch_infos, *dst_trycatch_infos; - size_t src_depth, dst_depth; - - scope_context = - hash_search(cmpl_ctx->stmt_scope_context, &src, HASH_FIND, NULL); - src_trycatch_infos = scope_context->nesting_trycatch_infos; - - scope_context = - hash_search(cmpl_ctx->stmt_scope_context, &dst, HASH_FIND, NULL); - dst_trycatch_infos = scope_context->nesting_trycatch_infos; - - src_depth = vec_size(src_trycatch_infos); - dst_depth = vec_size(dst_trycatch_infos); - - /* cleanup context from deepest try catch block */ - if (src_depth > dst_depth) - { - size_t i = src_depth; - for (; i > dst_depth; i--) - { - TryCatchInfo *info = (TryCatchInfo *) vec_at(src_trycatch_infos, i - 1); - PLtsql_stmt *restore; - - /* distinguish try block and catch block, same as try-catch stmt */ - if (info->in_try_block) - restore = (PLtsql_stmt *) create_restore_ctx_full(src->lineno); - else - restore = (PLtsql_stmt *) create_restore_ctx_partial(src->lineno); - add_stmt(codegen_ctx, restore); - } - } + CompileContext *cmpl_ctx = codegen_ctx->cmpl_ctx; + ScopeContext *scope_context; + DynaVec *src_trycatch_infos, + *dst_trycatch_infos; + size_t src_depth, + dst_depth; + + scope_context = + hash_search(cmpl_ctx->stmt_scope_context, &src, HASH_FIND, NULL); + src_trycatch_infos = scope_context->nesting_trycatch_infos; + + scope_context = + hash_search(cmpl_ctx->stmt_scope_context, &dst, HASH_FIND, NULL); + dst_trycatch_infos = scope_context->nesting_trycatch_infos; + + src_depth = vec_size(src_trycatch_infos); + dst_depth = vec_size(dst_trycatch_infos); + + /* cleanup context from deepest try catch block */ + if (src_depth > dst_depth) + { + size_t i = src_depth; + + for (; i > dst_depth; i--) + { + TryCatchInfo *info = (TryCatchInfo *) vec_at(src_trycatch_infos, i - 1); + PLtsql_stmt *restore; + + /* distinguish try block and catch block, same as try-catch stmt */ + if (info->in_try_block) + restore = (PLtsql_stmt *) create_restore_ctx_full(src->lineno); + else + restore = (PLtsql_stmt *) create_restore_ctx_partial(src->lineno); + add_stmt(codegen_ctx, restore); + } + } } static void cleanup_all_exception_context(PLtsql_stmt *src, CodegenContext *codegen_ctx) { - CompileContext *cmpl_ctx = codegen_ctx->cmpl_ctx; - ScopeContext *scope_context; - DynaVec *src_trycatch_infos; - int src_depth; - - scope_context = - hash_search(cmpl_ctx->stmt_scope_context, &src, HASH_FIND, NULL); - src_trycatch_infos = scope_context->nesting_trycatch_infos; - - src_depth = vec_size(src_trycatch_infos); - for (; src_depth > 0; src_depth--) - { - TryCatchInfo *info = (TryCatchInfo *) vec_at(src_trycatch_infos, src_depth - 1); - PLtsql_stmt *restore; - - /* distinguish try block and catch block, same as try-catch stmt */ - if (info->in_try_block) - restore = (PLtsql_stmt *) create_restore_ctx_full(src->lineno); - else - restore = (PLtsql_stmt *) create_restore_ctx_partial(src->lineno); - add_stmt(codegen_ctx, restore); - } + CompileContext *cmpl_ctx = codegen_ctx->cmpl_ctx; + ScopeContext *scope_context; + DynaVec *src_trycatch_infos; + int src_depth; + + scope_context = + hash_search(cmpl_ctx->stmt_scope_context, &src, HASH_FIND, NULL); + src_trycatch_infos = scope_context->nesting_trycatch_infos; + + src_depth = vec_size(src_trycatch_infos); + for (; src_depth > 0; src_depth--) + { + TryCatchInfo *info = (TryCatchInfo *) vec_at(src_trycatch_infos, src_depth - 1); + PLtsql_stmt *restore; + + /* distinguish try block and catch block, same as try-catch stmt */ + if (info->in_try_block) + restore = (PLtsql_stmt *) create_restore_ctx_full(src->lineno); + else + restore = (PLtsql_stmt *) create_restore_ctx_partial(src->lineno); + add_stmt(codegen_ctx, restore); + } } /*********************************************************************************** * VISITOR ACTIONS IMPLEMENTATION **********************************************************************************/ -static bool stmt_default_act(Walker_context *ctx, PLtsql_stmt *stmt) +static bool +stmt_default_act(Walker_context *ctx, PLtsql_stmt *stmt) { - switch(stmt->cmd_type) - { - case PLTSQL_STMT_ASSIGN: - case PLTSQL_STMT_RETURN_QUERY: - case PLTSQL_STMT_EXECSQL: - case PLTSQL_STMT_OPEN: - case PLTSQL_STMT_FETCH: - case PLTSQL_STMT_CLOSE: - case PLTSQL_STMT_COMMIT: - case PLTSQL_STMT_ROLLBACK: - /* TSQL-only statement types follow */ - case PLTSQL_STMT_PRINT: - case PLTSQL_STMT_QUERY_SET: - case PLTSQL_STMT_PUSH_RESULT: - case PLTSQL_STMT_EXEC: - case PLTSQL_STMT_EXEC_BATCH: - case PLTSQL_STMT_EXEC_SP: - case PLTSQL_STMT_DECL_TABLE: - case PLTSQL_STMT_RETURN_TABLE: - case PLTSQL_STMT_DEALLOCATE: - case PLTSQL_STMT_DECL_CURSOR: + switch (stmt->cmd_type) + { + case PLTSQL_STMT_ASSIGN: + case PLTSQL_STMT_RETURN_QUERY: + case PLTSQL_STMT_EXECSQL: + case PLTSQL_STMT_OPEN: + case PLTSQL_STMT_FETCH: + case PLTSQL_STMT_CLOSE: + case PLTSQL_STMT_COMMIT: + case PLTSQL_STMT_ROLLBACK: + /* TSQL-only statement types follow */ + case PLTSQL_STMT_PRINT: + case PLTSQL_STMT_QUERY_SET: + case PLTSQL_STMT_PUSH_RESULT: + case PLTSQL_STMT_EXEC: + case PLTSQL_STMT_EXEC_BATCH: + case PLTSQL_STMT_EXEC_SP: + case PLTSQL_STMT_DECL_TABLE: + case PLTSQL_STMT_RETURN_TABLE: + case PLTSQL_STMT_DEALLOCATE: + case PLTSQL_STMT_DECL_CURSOR: case PLTSQL_STMT_RAISERROR: case PLTSQL_STMT_THROW: case PLTSQL_STMT_USEDB: - case PLTSQL_STMT_GRANTDB: - case PLTSQL_STMT_INSERT_BULK: - case PLTSQL_STMT_SET_EXPLAIN_MODE: - /* TSQL-only executable node */ - case PLTSQL_STMT_SAVE_CTX: - case PLTSQL_STMT_RESTORE_CTX_FULL: - case PLTSQL_STMT_RESTORE_CTX_PARTIAL: - { - CodegenContext *codegen_ctx = (CodegenContext *) ctx->extra_ctx; - add_stmt(codegen_ctx, stmt); - break; - } - case PLTSQL_STMT_INIT: - { - break; /* It holds list of assignments, DO nothing */ - } - default: - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Unsupported statment type %d in codegen", stmt->cmd_type))); - } - return stmt_walker((PLtsql_stmt *) stmt, &general_walker_func, ctx); /* continue traversal */ + case PLTSQL_STMT_GRANTDB: + case PLTSQL_STMT_INSERT_BULK: + case PLTSQL_STMT_SET_EXPLAIN_MODE: + /* TSQL-only executable node */ + case PLTSQL_STMT_SAVE_CTX: + case PLTSQL_STMT_RESTORE_CTX_FULL: + case PLTSQL_STMT_RESTORE_CTX_PARTIAL: + { + CodegenContext *codegen_ctx = (CodegenContext *) ctx->extra_ctx; + + add_stmt(codegen_ctx, stmt); + break; + } + case PLTSQL_STMT_INIT: + { + break; /* It holds list of assignments, DO nothing */ + } + default: + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Unsupported statment type %d in codegen", stmt->cmd_type))); + } + return stmt_walker((PLtsql_stmt *) stmt, &general_walker_func, ctx); /* continue traversal */ } -static bool stmt_block_act(Walker_context *ctx, PLtsql_stmt_block *stmt) +static bool +stmt_block_act(Walker_context *ctx, PLtsql_stmt_block *stmt) { - return stmt_walker((PLtsql_stmt *) stmt, general_walker_func, ctx); + return stmt_walker((PLtsql_stmt *) stmt, general_walker_func, ctx); } /* @@ -325,57 +339,61 @@ static bool stmt_block_act(Walker_context *ctx, PLtsql_stmt_block *stmt) * 7. ELSE_END_LABLE */ -static bool stmt_if_act(Walker_context *ctx, PLtsql_stmt_if *stmt) +static bool +stmt_if_act(Walker_context *ctx, PLtsql_stmt_if *stmt) { - CodegenContext *codegen_ctx = (CodegenContext *) ctx->extra_ctx; - /* create and add GOTO 1*/ - PLtsql_stmt_goto *goto1 = create_goto(stmt->lineno); + CodegenContext *codegen_ctx = (CodegenContext *) ctx->extra_ctx; + + /* create and add GOTO 1 */ + PLtsql_stmt_goto *goto1 = create_goto(stmt->lineno); + + goto1->cond = stmt->cond; - goto1->cond = stmt->cond; + if (stmt->else_body) + snprintf(goto1->target_label, LABEL_LEN, + ELSE_BEGIN_LABEL_FORMAT, stmt->lineno, stmt); + else + snprintf(goto1->target_label, LABEL_LEN, + ELSE_END_LABEL_FORMAT, stmt->lineno, stmt); - if (stmt->else_body) - snprintf(goto1->target_label, LABEL_LEN, - ELSE_BEGIN_LABEL_FORMAT, stmt->lineno, stmt); - else - snprintf(goto1->target_label, LABEL_LEN, - ELSE_END_LABEL_FORMAT, stmt->lineno, stmt); + add_stmt(codegen_ctx, (PLtsql_stmt *) goto1); - add_stmt(codegen_ctx, (PLtsql_stmt *) goto1); + general_walker_func(stmt->then_body, ctx); - general_walker_func(stmt->then_body, ctx); + if (stmt->else_body) + { + PLtsql_stmt_goto *goto2 = create_goto(stmt->lineno); - if (stmt->else_body) - { - PLtsql_stmt_goto *goto2 = create_goto(stmt->lineno); - snprintf(goto2->target_label, LABEL_LEN, - ELSE_END_LABEL_FORMAT, stmt->lineno, stmt); - add_stmt(codegen_ctx, (PLtsql_stmt *) goto2); + snprintf(goto2->target_label, LABEL_LEN, + ELSE_END_LABEL_FORMAT, stmt->lineno, stmt); + add_stmt(codegen_ctx, (PLtsql_stmt *) goto2); - /* register begin of catch block */ - create_and_register_label(codegen_ctx, - ELSE_BEGIN_LABEL_FORMAT, stmt->lineno, stmt); + /* register begin of catch block */ + create_and_register_label(codegen_ctx, + ELSE_BEGIN_LABEL_FORMAT, stmt->lineno, stmt); - general_walker_func(stmt->else_body, ctx); - } + general_walker_func(stmt->else_body, ctx); + } - /* register end of catch block */ - create_and_register_label(codegen_ctx, - ELSE_END_LABEL_FORMAT, stmt->lineno, stmt); - return false; + /* register end of catch block */ + create_and_register_label(codegen_ctx, + ELSE_END_LABEL_FORMAT, stmt->lineno, stmt); + return false; } -static bool stmt_label_act(Walker_context *ctx, PLtsql_stmt_label *stmt) +static bool +stmt_label_act(Walker_context *ctx, PLtsql_stmt_label *stmt) { - /* register label */ - CodegenContext *codegen_ctx = (CodegenContext *) ctx->extra_ctx; - LabelIndexEntry *label_entry = - hash_search(codegen_ctx->label_index, stmt->label, HASH_ENTER, NULL); + /* register label */ + CodegenContext *codegen_ctx = (CodegenContext *) ctx->extra_ctx; + LabelIndexEntry *label_entry = + hash_search(codegen_ctx->label_index, stmt->label, HASH_ENTER, NULL); - label_entry->pc = vec_size(codegen_ctx->exec_codes->codes); /* NEXT SLOT */ - return stmt_walker((PLtsql_stmt* ) stmt, &general_walker_func, ctx); + label_entry->pc = vec_size(codegen_ctx->exec_codes->codes); /* NEXT SLOT */ + return stmt_walker((PLtsql_stmt *) stmt, &general_walker_func, ctx); } -/* +/* * Code generation: * * TRY SAVE_ERR_CTX, GOTO CATCH_BEGIN_LABEL @@ -387,53 +405,54 @@ static bool stmt_label_act(Walker_context *ctx, PLtsql_stmt_label *stmt) * RESTORE_PARTIAL * CATCH_END_LABEL * - * Traverse order: + * Traverse order: * ||| * [1st visit] TRY_CATCH [3nd visit] * // | \\ * STMT1 | STMT2 * | - * [2nd visit] + * [2nd visit] */ -static bool stmt_try_catch_act(Walker_context *ctx, PLtsql_stmt_try_catch *stmt) +static bool +stmt_try_catch_act(Walker_context *ctx, PLtsql_stmt_try_catch *stmt) { - CodegenContext *codegen_ctx = (CodegenContext *) ctx->extra_ctx; - PLtsql_stmt_save_ctx *save = create_save_ctx(stmt->lineno); - PLtsql_stmt_goto *stmt_goto = create_goto(stmt->lineno); - PLtsql_stmt_restore_ctx_full *restore_full = - create_restore_ctx_full(stmt->lineno); - PLtsql_stmt_restore_ctx_partial *restore_partial = - create_restore_ctx_partial(stmt->lineno); + CodegenContext *codegen_ctx = (CodegenContext *) ctx->extra_ctx; + PLtsql_stmt_save_ctx *save = create_save_ctx(stmt->lineno); + PLtsql_stmt_goto *stmt_goto = create_goto(stmt->lineno); + PLtsql_stmt_restore_ctx_full *restore_full = + create_restore_ctx_full(stmt->lineno); + PLtsql_stmt_restore_ctx_partial *restore_partial = + create_restore_ctx_partial(stmt->lineno); - snprintf(save->target_label, LABEL_LEN, - CATCH_BEGIN_LABEL_FORMAT, stmt->lineno, stmt); - add_stmt(codegen_ctx, (PLtsql_stmt *) save); + snprintf(save->target_label, LABEL_LEN, + CATCH_BEGIN_LABEL_FORMAT, stmt->lineno, stmt); + add_stmt(codegen_ctx, (PLtsql_stmt *) save); - general_walker_func(stmt->body, ctx); + general_walker_func(stmt->body, ctx); - snprintf(stmt_goto->target_label, LABEL_LEN, - CATCH_END_LABEL_FORMAT, stmt->lineno, stmt); + snprintf(stmt_goto->target_label, LABEL_LEN, + CATCH_END_LABEL_FORMAT, stmt->lineno, stmt); - /* complete try block */ - add_stmt(codegen_ctx, (PLtsql_stmt *) restore_full); - add_stmt(codegen_ctx, (PLtsql_stmt *) stmt_goto); + /* complete try block */ + add_stmt(codegen_ctx, (PLtsql_stmt *) restore_full); + add_stmt(codegen_ctx, (PLtsql_stmt *) stmt_goto); - /* register begin of catch block */ - create_and_register_label(codegen_ctx, - CATCH_BEGIN_LABEL_FORMAT, stmt->lineno, stmt); + /* register begin of catch block */ + create_and_register_label(codegen_ctx, + CATCH_BEGIN_LABEL_FORMAT, stmt->lineno, stmt); - general_walker_func(stmt->handler, ctx); + general_walker_func(stmt->handler, ctx); - /* complete catch block */ - add_stmt(codegen_ctx, (PLtsql_stmt *) restore_partial); + /* complete catch block */ + add_stmt(codegen_ctx, (PLtsql_stmt *) restore_partial); - /* register end of catch block */ - create_and_register_label(codegen_ctx, - CATCH_END_LABEL_FORMAT, stmt->lineno, stmt); + /* register end of catch block */ + create_and_register_label(codegen_ctx, + CATCH_END_LABEL_FORMAT, stmt->lineno, stmt); - return false; + return false; } /* @@ -449,203 +468,215 @@ static bool stmt_try_catch_act(Walker_context *ctx, PLtsql_stmt_try_catch *stmt) * WHILE_END */ -static bool stmt_while_act(Walker_context *ctx, PLtsql_stmt_while *stmt) +static bool +stmt_while_act(Walker_context *ctx, PLtsql_stmt_while *stmt) { - CodegenContext *codegen_ctx = (CodegenContext *) ctx->extra_ctx; - PLtsql_stmt_goto *stmt_goto = create_goto(stmt->lineno); - LoopContext cur_loop_ctx; - ListCell *s; - - /* initialize and save loop context */ - cur_loop_ctx.stmt = stmt; - stack_push(codegen_ctx->loop_contexts, &cur_loop_ctx); - - /* register loop begin label */ - create_and_register_label(codegen_ctx, - LOOP_BEGIN_LABEL_FORMAT, stmt->lineno, stmt); - - /* add conditional goto */ - stmt_goto->cond = stmt->cond; - snprintf(stmt_goto->target_label, LABEL_LEN, - LOOP_END_LABEL_FORMAT, stmt->lineno, stmt); /* goto loop begin */ - add_stmt(codegen_ctx, (PLtsql_stmt *) stmt_goto); - - /* visit all children */ - foreach(s, stmt->body) - general_walker_func((PLtsql_stmt *) lfirst(s), ctx); - - /* add goto to begin */ - stmt_goto = create_goto(stmt->lineno); - snprintf(stmt_goto->target_label, LABEL_LEN, - LOOP_BEGIN_LABEL_FORMAT, stmt->lineno, stmt); /* goto loop begin */ - add_stmt(codegen_ctx, (PLtsql_stmt *) stmt_goto); - - /* register loop end label */ - create_and_register_label(codegen_ctx, - LOOP_END_LABEL_FORMAT, stmt->lineno, stmt); - - /* pop loop context */ - stack_pop(codegen_ctx->loop_contexts); - - return false; /* continue */ + CodegenContext *codegen_ctx = (CodegenContext *) ctx->extra_ctx; + PLtsql_stmt_goto *stmt_goto = create_goto(stmt->lineno); + LoopContext cur_loop_ctx; + ListCell *s; + + /* initialize and save loop context */ + cur_loop_ctx.stmt = stmt; + stack_push(codegen_ctx->loop_contexts, &cur_loop_ctx); + + /* register loop begin label */ + create_and_register_label(codegen_ctx, + LOOP_BEGIN_LABEL_FORMAT, stmt->lineno, stmt); + + /* add conditional goto */ + stmt_goto->cond = stmt->cond; + snprintf(stmt_goto->target_label, LABEL_LEN, + LOOP_END_LABEL_FORMAT, stmt->lineno, stmt); /* goto loop begin */ + add_stmt(codegen_ctx, (PLtsql_stmt *) stmt_goto); + + /* visit all children */ + foreach(s, stmt->body) + general_walker_func((PLtsql_stmt *) lfirst(s), ctx); + + /* add goto to begin */ + stmt_goto = create_goto(stmt->lineno); + snprintf(stmt_goto->target_label, LABEL_LEN, + LOOP_BEGIN_LABEL_FORMAT, stmt->lineno, stmt); /* goto loop begin */ + add_stmt(codegen_ctx, (PLtsql_stmt *) stmt_goto); + + /* register loop end label */ + create_and_register_label(codegen_ctx, + LOOP_END_LABEL_FORMAT, stmt->lineno, stmt); + + /* pop loop context */ + stack_pop(codegen_ctx->loop_contexts); + + return false; /* continue */ } -static bool stmt_exit_act(Walker_context *ctx, PLtsql_stmt_exit *stmt) +static bool +stmt_exit_act(Walker_context *ctx, PLtsql_stmt_exit *stmt) { - CodegenContext *codegen_ctx = (CodegenContext *) ctx->extra_ctx; - LoopContext *cur_loop_ctx; - PLtsql_stmt_goto *stmt_goto; - PLtsql_stmt_while *stmt_while; - - cur_loop_ctx = (LoopContext *) stack_top(codegen_ctx->loop_contexts); - stmt_while = cur_loop_ctx->stmt; - - stmt_goto = create_goto(stmt->lineno); - if (stmt->is_exit) /* break, goto to loop end */ - snprintf(stmt_goto->target_label, LABEL_LEN, - LOOP_END_LABEL_FORMAT, stmt_while->lineno, stmt_while); /* goto loop end */ - else /* continue, goto to loop begin */ - snprintf(stmt_goto->target_label, LABEL_LEN, - LOOP_BEGIN_LABEL_FORMAT, stmt_while->lineno, stmt_while); /* goto loop begin */ - - /* same as goto */ - cleanup_exception_context((PLtsql_stmt *) stmt, - (PLtsql_stmt *) stmt_while, - codegen_ctx); - - add_stmt(codegen_ctx, (PLtsql_stmt *) stmt_goto); - - return stmt_walker((PLtsql_stmt *)stmt, &general_walker_func, ctx); + CodegenContext *codegen_ctx = (CodegenContext *) ctx->extra_ctx; + LoopContext *cur_loop_ctx; + PLtsql_stmt_goto *stmt_goto; + PLtsql_stmt_while *stmt_while; + + cur_loop_ctx = (LoopContext *) stack_top(codegen_ctx->loop_contexts); + stmt_while = cur_loop_ctx->stmt; + + stmt_goto = create_goto(stmt->lineno); + if (stmt->is_exit) /* break, goto to loop end */ + snprintf(stmt_goto->target_label, LABEL_LEN, + LOOP_END_LABEL_FORMAT, stmt_while->lineno, stmt_while); /* goto loop end */ + else /* continue, goto to loop begin */ + snprintf(stmt_goto->target_label, LABEL_LEN, + LOOP_BEGIN_LABEL_FORMAT, stmt_while->lineno, stmt_while); /* goto loop begin */ + + /* same as goto */ + cleanup_exception_context((PLtsql_stmt *) stmt, + (PLtsql_stmt *) stmt_while, + codegen_ctx); + + add_stmt(codegen_ctx, (PLtsql_stmt *) stmt_goto); + + return stmt_walker((PLtsql_stmt *) stmt, &general_walker_func, ctx); } -static bool stmt_return_act(Walker_context *ctx, PLtsql_stmt_return *stmt) +static bool +stmt_return_act(Walker_context *ctx, PLtsql_stmt_return *stmt) { - CodegenContext *codegen_ctx = (CodegenContext *) ctx->extra_ctx; - PLtsql_stmt_goto *stmt_goto = create_goto(stmt->lineno); + CodegenContext *codegen_ctx = (CodegenContext *) ctx->extra_ctx; + PLtsql_stmt_goto *stmt_goto = create_goto(stmt->lineno); - snprintf(stmt_goto->target_label, LABEL_LEN, END_OF_PROC_FORMAT, 0, ctx); + snprintf(stmt_goto->target_label, LABEL_LEN, END_OF_PROC_FORMAT, 0, ctx); - add_stmt(codegen_ctx, (PLtsql_stmt *) stmt); + add_stmt(codegen_ctx, (PLtsql_stmt *) stmt); - /* same as goto */ - cleanup_all_exception_context((PLtsql_stmt *) stmt, codegen_ctx); - add_stmt(codegen_ctx, (PLtsql_stmt *) stmt_goto); /* end control flow */ + /* same as goto */ + cleanup_all_exception_context((PLtsql_stmt *) stmt, codegen_ctx); + add_stmt(codegen_ctx, (PLtsql_stmt *) stmt_goto); /* end control flow */ - return stmt_walker((PLtsql_stmt *)stmt, &general_walker_func, ctx); + return stmt_walker((PLtsql_stmt *) stmt, &general_walker_func, ctx); } -static bool stmt_goto_act(Walker_context *ctx, PLtsql_stmt_goto *stmt) +static bool +stmt_goto_act(Walker_context *ctx, PLtsql_stmt_goto *stmt) { - CodegenContext *codegen_ctx = (CodegenContext *) ctx->extra_ctx; - CompileContext *cmpl_ctx = codegen_ctx->cmpl_ctx; - PLtsql_stmt *dest_stmt; - - LabelStmtEntry *label_entry = - hash_search(cmpl_ctx->label_stmt_map, stmt->target_label, HASH_FIND, NULL); - dest_stmt = (PLtsql_stmt *) label_entry->stmt; - - /* - * handle dangling exception contexs if any - * if target label is outside of current try-catch block" - * goto inner try-catch block was blocked in analyzer - */ - cleanup_exception_context((PLtsql_stmt *) stmt, dest_stmt, codegen_ctx); - - /* add current goto */ - add_stmt(codegen_ctx, (PLtsql_stmt *) stmt); - - return stmt_walker((PLtsql_stmt*)stmt, &general_walker_func, ctx); + CodegenContext *codegen_ctx = (CodegenContext *) ctx->extra_ctx; + CompileContext *cmpl_ctx = codegen_ctx->cmpl_ctx; + PLtsql_stmt *dest_stmt; + + LabelStmtEntry *label_entry = + hash_search(cmpl_ctx->label_stmt_map, stmt->target_label, HASH_FIND, NULL); + + dest_stmt = (PLtsql_stmt *) label_entry->stmt; + + /* + * handle dangling exception contexs if any if target label is outside of + * current try-catch block" goto inner try-catch block was blocked in + * analyzer + */ + cleanup_exception_context((PLtsql_stmt *) stmt, dest_stmt, codegen_ctx); + + /* add current goto */ + add_stmt(codegen_ctx, (PLtsql_stmt *) stmt); + + return stmt_walker((PLtsql_stmt *) stmt, &general_walker_func, ctx); } /*********************************************************************************** * CODE GENERATION **********************************************************************************/ -static int get_label_index(Walker_context *ctx, const char * label); -void resolve_labels(Walker_context *ctx); +static int get_label_index(Walker_context *ctx, const char *label); +void resolve_labels(Walker_context *ctx); -static int get_label_index(Walker_context *ctx, const char * label) +static int +get_label_index(Walker_context *ctx, const char *label) { - CodegenContext *codegen_ctx = (CodegenContext *) ctx->extra_ctx; - LabelIndexEntry *entry = - hash_search(codegen_ctx->label_index, label, HASH_FIND, NULL); - - if (!entry) - ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Label NOT found %s", label))); - return entry->pc; + CodegenContext *codegen_ctx = (CodegenContext *) ctx->extra_ctx; + LabelIndexEntry *entry = + hash_search(codegen_ctx->label_index, label, HASH_FIND, NULL); + + if (!entry) + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Label NOT found %s", label))); + return entry->pc; } -void resolve_labels(Walker_context *ctx) +void +resolve_labels(Walker_context *ctx) { - CodegenContext *codegen_ctx = (CodegenContext *) ctx->extra_ctx; - ExecCodes *exec_codes = codegen_ctx->exec_codes; - size_t size = vec_size(exec_codes->codes); - size_t i; - - /* Fill missing goto targets - * targe_pc could be only filled partially during tree traversal - * when label is defined after GOTO - */ - for (i = 0; i < size; i++) - { - PLtsql_stmt *stmt = *(PLtsql_stmt **) vec_at(exec_codes->codes, i); - if (stmt->cmd_type == PLTSQL_STMT_GOTO) - { - PLtsql_stmt_goto *stmt_goto = (PLtsql_stmt_goto *) stmt; - stmt_goto->target_pc = get_label_index(ctx, stmt_goto->target_label); - } - else if (stmt->cmd_type == PLTSQL_STMT_SAVE_CTX) - { - PLtsql_stmt_save_ctx *save_err = (PLtsql_stmt_save_ctx *) stmt; - save_err->target_pc = get_label_index(ctx, save_err->target_label); - } - } + CodegenContext *codegen_ctx = (CodegenContext *) ctx->extra_ctx; + ExecCodes *exec_codes = codegen_ctx->exec_codes; + size_t size = vec_size(exec_codes->codes); + size_t i; + + /* + * Fill missing goto targets targe_pc could be only filled partially + * during tree traversal when label is defined after GOTO + */ + for (i = 0; i < size; i++) + { + PLtsql_stmt *stmt = *(PLtsql_stmt **) vec_at(exec_codes->codes, i); + + if (stmt->cmd_type == PLTSQL_STMT_GOTO) + { + PLtsql_stmt_goto *stmt_goto = (PLtsql_stmt_goto *) stmt; + + stmt_goto->target_pc = get_label_index(ctx, stmt_goto->target_label); + } + else if (stmt->cmd_type == PLTSQL_STMT_SAVE_CTX) + { + PLtsql_stmt_save_ctx *save_err = (PLtsql_stmt_save_ctx *) stmt; + + save_err->target_pc = get_label_index(ctx, save_err->target_label); + } + } } -void gen_exec_code(PLtsql_function *func, CompileContext *cmpl_ctx) +void +gen_exec_code(PLtsql_function *func, CompileContext *cmpl_ctx) { - Walker_context *walker; - CodegenContext *codegen_ctx; - MemoryContext oldcontext; + Walker_context *walker; + CodegenContext *codegen_ctx; + MemoryContext oldcontext; - if ((!func) || func->exec_codes) /* cached plan */ - return; + if ((!func) || func->exec_codes) /* cached plan */ + return; - oldcontext = MemoryContextSwitchTo(func->fn_cxt); + oldcontext = MemoryContextSwitchTo(func->fn_cxt); walker = make_codegen_context(cmpl_ctx); codegen_ctx = (CodegenContext *) walker->extra_ctx; - PG_TRY(); - { - ExecCodes *exec_codes; - Oid namespace; - /* general generations */ - stmt_walker((PLtsql_stmt *) func->action, general_walker_func, walker); - create_and_register_label(codegen_ctx, END_OF_PROC_FORMAT, 0, walker); + PG_TRY(); + { + ExecCodes *exec_codes; + Oid namespace; + + /* general generations */ + stmt_walker((PLtsql_stmt *) func->action, general_walker_func, walker); + create_and_register_label(codegen_ctx, END_OF_PROC_FORMAT, 0, walker); - /* post generations */ - resolve_labels(walker); + /* post generations */ + resolve_labels(walker); - /* additional infos */ - namespace = get_func_namespace(func->fn_oid); - exec_codes = codegen_ctx->exec_codes; + /* additional infos */ + namespace = get_func_namespace(func->fn_oid); + exec_codes = codegen_ctx->exec_codes; exec_codes->proc_name = get_func_name(func->fn_oid); - exec_codes->proc_namespace = get_namespace_name(namespace); - func->exec_codes_valid = true; - func->exec_codes = exec_codes; /* ownership transfered */ - } - PG_CATCH(); - { - func->exec_codes_valid = false; - free_exec_codes(codegen_ctx->exec_codes); - codegen_ctx->exec_codes = NULL; - destroy_template_context(walker); - MemoryContextSwitchTo(oldcontext); - PG_RE_THROW(); - } - PG_END_TRY(); - - destroy_template_context(walker); - MemoryContextSwitchTo(oldcontext); + exec_codes->proc_namespace = get_namespace_name(namespace); + func->exec_codes_valid = true; + func->exec_codes = exec_codes; /* ownership transfered */ + } + PG_CATCH(); + { + func->exec_codes_valid = false; + free_exec_codes(codegen_ctx->exec_codes); + codegen_ctx->exec_codes = NULL; + destroy_template_context(walker); + MemoryContextSwitchTo(oldcontext); + PG_RE_THROW(); + } + PG_END_TRY(); + + destroy_template_context(walker); + MemoryContextSwitchTo(oldcontext); } diff --git a/contrib/babelfishpg_tsql/src/codegen.h b/contrib/babelfishpg_tsql/src/codegen.h index f02f61d6d7..c178d768cc 100644 --- a/contrib/babelfishpg_tsql/src/codegen.h +++ b/contrib/babelfishpg_tsql/src/codegen.h @@ -3,6 +3,6 @@ #include "pltsql.h" #include "compile_context.h" -void gen_exec_code(PLtsql_function *func, CompileContext *cmpl_ctx); +void gen_exec_code(PLtsql_function *func, CompileContext *cmpl_ctx); -#endif /* CODEGEN_H */ +#endif /* CODEGEN_H */ diff --git a/contrib/babelfishpg_tsql/src/collation.c b/contrib/babelfishpg_tsql/src/collation.c index 3e2be594ef..e3ce658a92 100644 --- a/contrib/babelfishpg_tsql/src/collation.c +++ b/contrib/babelfishpg_tsql/src/collation.c @@ -23,24 +23,24 @@ #define NOT_FOUND -1 #define SORT_KEY_STR "\357\277\277\0" -Oid server_collation_oid = InvalidOid; +Oid server_collation_oid = InvalidOid; collation_callbacks *collation_callbacks_ptr = NULL; extern bool babelfish_dump_restore; -static Node * pgtsql_expression_tree_mutator(Node *node, void* context); +static Node *pgtsql_expression_tree_mutator(Node *node, void *context); static void init_and_check_collation_callbacks(void); -extern int pattern_fixed_prefix_wrapper(Const *patt, - int ptype, - Oid collation, - Const **prefix, - Selectivity *rest_selec); +extern int pattern_fixed_prefix_wrapper(Const *patt, + int ptype, + Oid collation, + Const **prefix, + Selectivity *rest_selec); /* pattern prefix status for pattern_fixed_prefix_wrapper * Pattern_Prefix_None: no prefix found, this means the first character is a wildcard character * Pattern_Prefix_Exact: the pattern doesn't include any wildcard character * Pattern_Prefix_Partial: the pattern has a constant prefix - */ + */ typedef enum { Pattern_Prefix_None, Pattern_Prefix_Partial, Pattern_Prefix_Exact @@ -53,14 +53,16 @@ PG_FUNCTION_INFO_V1(is_collated_ci_as_internal); /* this function is no longer needed and is only a placeholder for upgrade script */ PG_FUNCTION_INFO_V1(init_server_collation); -Datum init_server_collation(PG_FUNCTION_ARGS) +Datum +init_server_collation(PG_FUNCTION_ARGS) { PG_RETURN_INT32(0); } /* this function is no longer needed and is only a placeholder for upgrade script */ PG_FUNCTION_INFO_V1(init_server_collation_oid); -Datum init_server_collation_oid(PG_FUNCTION_ARGS) +Datum +init_server_collation_oid(PG_FUNCTION_ARGS) { PG_RETURN_INT32(0); } @@ -92,7 +94,8 @@ get_server_collation_oid(PG_FUNCTION_ARGS) } -Datum is_collated_ci_as_internal(PG_FUNCTION_ARGS) +Datum +is_collated_ci_as_internal(PG_FUNCTION_ARGS) { PG_RETURN_DATUM(tsql_is_collated_ci_as_internal(fcinfo)); } @@ -109,13 +112,13 @@ make_op_with_func(Oid opno, Oid opresulttype, bool opretset, Expr *leftop, Expr *rightop, Oid opcollid, Oid inputcollid, Oid oprfuncid) { - OpExpr *expr = (OpExpr*)make_opclause(opno, - opresulttype, - opretset, - leftop, - rightop, - opcollid, - inputcollid); + OpExpr *expr = (OpExpr *) make_opclause(opno, + opresulttype, + opretset, + leftop, + rightop, + opcollid, + inputcollid); expr->opfuncid = oprfuncid; return (Expr *) expr; @@ -132,59 +135,66 @@ make_or_qual(Node *qual1, Node *qual2) return (Node *) make_orclause(list_make2(qual1, qual2)); } -static Node* -transform_funcexpr(Node* node) +static Node * +transform_funcexpr(Node *node) { if (node && IsA(node, FuncExpr)) { - FuncExpr *fe = (FuncExpr *) node; - int collidx_of_cs_as; - - if (fe->funcid == 868 || // strpos - see pg_proc.dat - // fe->funcid == 394 || // string_to_array, 3-arg form - // fe->funcid == 376 || // string_to_array, 2-arg form - fe->funcid == 2073 || // substring - 2-arg form, see pg_proc.dat - fe->funcid == 2074 || // substring - 3-arg form, see pg_proc.dat - - fe->funcid == 2285 || // regexp_replace, flags in 4th arg - fe->funcid == 3397 || // regexp_match (find first match), flags in 3rd arg - fe->funcid == 2764) // regexp_matches, flags in 3rd arg + FuncExpr *fe = (FuncExpr *) node; + int collidx_of_cs_as; + + if (fe->funcid == 868 || //strpos - see pg_proc.dat + /* fe->funcid == 394 || // string_to_array, 3-arg form */ + /* fe->funcid == 376 || // string_to_array, 2-arg form */ + fe->funcid == 2073 || //substring - 2 - arg form, see pg_proc.dat + fe->funcid == 2074 || //substring - 3 - arg form, see pg_proc.dat + + fe->funcid == 2285 || //regexp_replace, flags in 4 th arg + fe->funcid == 3397 || //regexp_match(find first match), flags in 3 rd arg + fe->funcid == 2764) + /* regexp_matches, flags in 3 rd arg */ { coll_info_t coll_info_of_inputcollid = tsql_lookup_collation_table_internal(fe->inputcollid); - Node* leftop = (Node *) linitial(fe->args); - Node* rightop = (Node *) lsecond(fe->args); + Node *leftop = (Node *) linitial(fe->args); + Node *rightop = (Node *) lsecond(fe->args); if (OidIsValid(coll_info_of_inputcollid.oid) && coll_info_of_inputcollid.collateflags == 0x000d /* CI_AS */ ) { - Oid lower_funcid = 870; // lower - Oid result_type = 25; // text + Oid lower_funcid = 870; + + /* lower */ + Oid result_type = 25; + + /* text */ tsql_get_server_collation_oid_internal(true); if (!OidIsValid(server_collation_oid)) return node; - /* Find the CS_AS collation corresponding to the CI_AS collation - * Change the collation of the func op to the CS_AS collation + /* + * Find the CS_AS collation corresponding to the CI_AS + * collation Change the collation of the func op to the CS_AS + * collation */ collidx_of_cs_as = tsql_find_cs_as_collation_internal( - tsql_find_collation_internal(coll_info_of_inputcollid.collname)); + tsql_find_collation_internal(coll_info_of_inputcollid.collname)); if (NOT_FOUND == collidx_of_cs_as) return node; if (fe->funcid == 2285 || fe->funcid == 3397 || fe->funcid == 2764) { - Node* flags = (fe->funcid == 2285) ? lfourth(fe->args) : lthird(fe->args); + Node *flags = (fe->funcid == 2285) ? lfourth(fe->args) : lthird(fe->args); if (!IsA(flags, Const)) return node; else { - char *patt = TextDatumGetCString(((Const *)flags)->constvalue); - int f = 0; + char *patt = TextDatumGetCString(((Const *) flags)->constvalue); + int f = 0; while (patt[f] != '\0') { @@ -194,9 +204,11 @@ transform_funcexpr(Node* node) f++; } - /* If the 'i' flag was specified then the operation is case-insensitive - * and so the ci_as collation may be replaced with the corresponding - * deterministic cs_as collation. If not, return. + /* + * If the 'i' flag was specified then the operation is + * case-insensitive and so the ci_as collation may be + * replaced with the corresponding deterministic cs_as + * collation. If not, return. */ if (patt[f] != 'i') return node; @@ -206,16 +218,21 @@ transform_funcexpr(Node* node) fe->inputcollid = tsql_get_oid_from_collidx(collidx_of_cs_as); if (fe->funcid >= 2285) - return node; // regexp operators have their own way to handle case-insensitivity + return node; + + /* + * regexp operators have their own way to handle case + * -insensitivity + */ - if (!IsA(leftop, FuncExpr) || ((FuncExpr *)leftop)->funcid != lower_funcid) + if (!IsA(leftop, FuncExpr) || ((FuncExpr *) leftop)->funcid != lower_funcid) leftop = (Node *) makeFuncExpr(lower_funcid, result_type, list_make1(leftop), fe->inputcollid, fe->inputcollid, COERCE_EXPLICIT_CALL); - if (!IsA(rightop, FuncExpr) || ((FuncExpr *)rightop)->funcid != lower_funcid) + if (!IsA(rightop, FuncExpr) || ((FuncExpr *) rightop)->funcid != lower_funcid) rightop = (Node *) makeFuncExpr(lower_funcid, result_type, list_make1(rightop), @@ -225,12 +242,12 @@ transform_funcexpr(Node* node) if (list_length(fe->args) == 3) { - Node* thirdop = (Node *) makeFuncExpr(lower_funcid, - result_type, - list_make1(lthird(fe->args)), - fe->inputcollid, - fe->inputcollid, - COERCE_EXPLICIT_CALL); + Node *thirdop = (Node *) makeFuncExpr(lower_funcid, + result_type, + list_make1(lthird(fe->args)), + fe->inputcollid, + fe->inputcollid, + COERCE_EXPLICIT_CALL); fe->args = list_make3(leftop, rightop, thirdop); } @@ -252,38 +269,40 @@ transform_funcexpr(Node* node) * Case 1: if the pattern is a constant stirng * col LIKE PATTERN -> col = PATTERN * Case 2: if the pattern have a constant prefix - * col LIKE PATTERN -> + * col LIKE PATTERN -> * col LIKE PATTERN BETWEEN prefix AND prefix||E'\uFFFF' * Case 3: if the pattern doesn't have a constant prefix * col LIKE PATTERN -> col ILIKE PATTERN */ -static Node* -transform_likenode(Node* node) +static Node * +transform_likenode(Node *node) { if (node && IsA(node, OpExpr)) { - OpExpr *op = (OpExpr *) node; + OpExpr *op = (OpExpr *) node; like_ilike_info_t like_entry = tsql_lookup_like_ilike_table_internal(op->opno); coll_info_t coll_info_of_inputcollid = tsql_lookup_collation_table_internal(op->inputcollid); + /* - * We do not allow CREATE TABLE statements with CHECK constraint where the - * constraint has an ILIKE operator and the collation is ci_as. But during - * dump and restore, this kind of a table definition may be generated. At - * this point we know that any tables being restored that match this pattern - * are generated by pg_dump, and not created by a user. So, it is safe to go - * ahead with replacing the ci_as collation with a corresponding cs_as one - * if an ILIKE node is found during dump and restore. + * We do not allow CREATE TABLE statements with CHECK constraint where + * the constraint has an ILIKE operator and the collation is ci_as. + * But during dump and restore, this kind of a table definition may be + * generated. At this point we know that any tables being restored + * that match this pattern are generated by pg_dump, and not created + * by a user. So, it is safe to go ahead with replacing the ci_as + * collation with a corresponding cs_as one if an ILIKE node is found + * during dump and restore. */ init_and_check_collation_callbacks(); - if ((*collation_callbacks_ptr->has_ilike_node)(node) && babelfish_dump_restore) + if ((*collation_callbacks_ptr->has_ilike_node) (node) && babelfish_dump_restore) { - int collidx_of_cs_as; - + int collidx_of_cs_as; + if (coll_info_of_inputcollid.oid != InvalidOid) { collidx_of_cs_as = tsql_find_cs_as_collation_internal( - tsql_find_collation_internal(coll_info_of_inputcollid.collname)); + tsql_find_collation_internal(coll_info_of_inputcollid.collname)); if (NOT_FOUND == collidx_of_cs_as) { op->inputcollid = DEFAULT_COLLATION_OID; @@ -303,36 +322,38 @@ transform_likenode(Node* node) OidIsValid(coll_info_of_inputcollid.oid) && coll_info_of_inputcollid.collateflags == 0x000d /* CI_AS */ ) { - Node* leftop = (Node *) linitial(op->args); - Node* rightop = (Node *) lsecond(op->args); - Oid ltypeId = exprType(leftop); - Oid rtypeId = exprType(rightop); - char* op_str; - Node* ret; - Const* patt; - Const* prefix; + Node *leftop = (Node *) linitial(op->args); + Node *rightop = (Node *) lsecond(op->args); + Oid ltypeId = exprType(leftop); + Oid rtypeId = exprType(rightop); + char *op_str; + Node *ret; + Const *patt; + Const *prefix; Operator optup; Pattern_Prefix_Status pstatus; - int collidx_of_cs_as; + int collidx_of_cs_as; tsql_get_server_collation_oid_internal(true); if (!OidIsValid(server_collation_oid)) return node; - /* Find the CS_AS collation corresponding to the CI_AS collation - * Change the collation of the ILIKE op to the CS_AS collation + /* + * Find the CS_AS collation corresponding to the CI_AS collation + * Change the collation of the ILIKE op to the CS_AS collation */ collidx_of_cs_as = tsql_find_cs_as_collation_internal( - tsql_find_collation_internal(coll_info_of_inputcollid.collname)); - - - /* A CS_AS collation should always exist unless a Babelfish - * CS_AS collation was dropped or the lookup tables were not - * defined in lexicographic order. Program defensively here - * and just do no transformation in this case, which will - * generate a 'nondeterministic collation not supported' error. + tsql_find_collation_internal(coll_info_of_inputcollid.collname)); + + + /* + * A CS_AS collation should always exist unless a Babelfish CS_AS + * collation was dropped or the lookup tables were not defined in + * lexicographic order. Program defensively here and just do no + * transformation in this case, which will generate a + * 'nondeterministic collation not supported' error. */ if (NOT_FOUND == collidx_of_cs_as) return node; @@ -372,18 +393,21 @@ transform_likenode(Node* node) if (optup == (Operator) NULL) return node; - ret = (Node*)(make_op_with_func(oprid(optup), BOOLOID, false, - (Expr *) leftop, (Expr *) prefix, - InvalidOid, server_collation_oid ,oprfuncid(optup))); + ret = (Node *) (make_op_with_func(oprid(optup), BOOLOID, false, + (Expr *) leftop, (Expr *) prefix, + InvalidOid, server_collation_oid, oprfuncid(optup))); ReleaseSysCache(optup); return ret; } else { - Expr *greater_equal, *less_equal, *concat_expr; - Node* constant_suffix; - Const* highest_sort_key; + Expr *greater_equal, + *less_equal, + *concat_expr; + Node *constant_suffix; + Const *highest_sort_key; + /* construct leftop >= pattern */ optup = compatible_oper(NULL, list_make1(makeString(">=")), ltypeId, ltypeId, true, -1); @@ -391,10 +415,10 @@ transform_likenode(Node* node) return node; greater_equal = make_op_with_func(oprid(optup), BOOLOID, false, (Expr *) leftop, (Expr *) prefix, - InvalidOid, server_collation_oid ,oprfuncid(optup)); + InvalidOid, server_collation_oid, oprfuncid(optup)); ReleaseSysCache(optup); /* construct pattern||E'\uFFFF' */ - highest_sort_key = makeConst(TEXTOID,-1, server_collation_oid, -1, + highest_sort_key = makeConst(TEXTOID, -1, server_collation_oid, -1, PointerGetDatum(cstring_to_text(SORT_KEY_STR)), false, false); optup = compatible_oper(NULL, list_make1(makeString("||")), rtypeId, rtypeId, @@ -414,15 +438,15 @@ transform_likenode(Node* node) less_equal = make_op_with_func(oprid(optup), BOOLOID, false, (Expr *) leftop, (Expr *) concat_expr, InvalidOid, server_collation_oid, oprfuncid(optup)); - constant_suffix = make_and_qual((Node*)greater_equal, (Node*)less_equal); - if(like_entry.is_not_match) + constant_suffix = make_and_qual((Node *) greater_equal, (Node *) less_equal); + if (like_entry.is_not_match) { - constant_suffix = (Node*)make_notclause((Expr*)constant_suffix); + constant_suffix = (Node *) make_notclause((Expr *) constant_suffix); ret = make_or_qual(node, constant_suffix); } else { - constant_suffix = make_and_qual((Node*)greater_equal, (Node*)less_equal); + constant_suffix = make_and_qual((Node *) greater_equal, (Node *) less_equal); ret = make_and_qual(node, constant_suffix); } ReleaseSysCache(optup); @@ -433,21 +457,22 @@ transform_likenode(Node* node) return node; } -Node* pltsql_predicate_transformer(Node *expr) +Node * +pltsql_predicate_transformer(Node *expr) { - if(expr == NULL) + if (expr == NULL) return expr; - if(IsA(expr, OpExpr)) + if (IsA(expr, OpExpr)) { /* Singleton predicate */ return transform_likenode(expr); } else { - /* Nonsingleton predicate, which could either a BoolExpr - * with a list of predicates or a simple List of - * predicates. + /* + * Nonsingleton predicate, which could either a BoolExpr with a list + * of predicates or a simple List of predicates. */ BoolExpr *boolexpr = (BoolExpr *) expr; ListCell *lc; @@ -463,17 +488,18 @@ Node* pltsql_predicate_transformer(Node *expr) if (boolexpr->boolop != AND_EXPR && boolexpr->boolop != OR_EXPR) return expression_tree_mutator( - expr, - pgtsql_expression_tree_mutator, - NULL); + expr, + pgtsql_expression_tree_mutator, + NULL); predicates = boolexpr->args; } else if (IsA(expr, FuncExpr)) { /* - * This is performed even in the postgres dialect to handle babelfish CI_AS - * collations so that regexp operators can work inside plpgsql functions + * This is performed even in the postgres dialect to handle + * babelfish CI_AS collations so that regexp operators can work + * inside plpgsql functions */ expr = expression_tree_mutator(expr, pgtsql_expression_tree_mutator, NULL); return transform_funcexpr(expr); @@ -481,21 +507,23 @@ Node* pltsql_predicate_transformer(Node *expr) else return expr; - /* Process each predicate, and recursively process - * any nested predicate clauses of a toplevel predicate - */ + /* + * Process each predicate, and recursively process any nested + * predicate clauses of a toplevel predicate + */ foreach(lc, predicates) { - Node *qual = (Node *) lfirst(lc); + Node *qual = (Node *) lfirst(lc); + if (is_andclause(qual) || is_orclause(qual)) { new_predicates = lappend(new_predicates, - pltsql_predicate_transformer(qual)); + pltsql_predicate_transformer(qual)); } else if (IsA(qual, OpExpr)) { new_predicates = lappend(new_predicates, - transform_likenode(qual)); + transform_likenode(qual)); } else new_predicates = lappend(new_predicates, qual); @@ -514,22 +542,26 @@ Node* pltsql_predicate_transformer(Node *expr) } static Node * -pgtsql_expression_tree_mutator(Node *node, void* context) +pgtsql_expression_tree_mutator(Node *node, void *context) { if (NULL == node) return node; - if(IsA(node, CaseExpr)) + if (IsA(node, CaseExpr)) { - CaseExpr *caseexpr = (CaseExpr *) node; - if (caseexpr->arg != NULL) // CASE expression WHEN ... + CaseExpr *caseexpr = (CaseExpr *) node; + + if (caseexpr->arg != NULL) + /* CASE expression WHEN... */ { - pltsql_predicate_transformer((Node*)caseexpr->arg); + pltsql_predicate_transformer((Node *) caseexpr->arg); } } - else if (IsA(node, CaseWhen)) //CASE WHEN expr + else if (IsA(node, CaseWhen)) + /* CASE WHEN expr */ { - CaseWhen *casewhen = (CaseWhen *) node; - pltsql_predicate_transformer((Node*)casewhen->expr); + CaseWhen *casewhen = (CaseWhen *) node; + + pltsql_predicate_transformer((Node *) casewhen->expr); } /* Recurse through the operands of node */ @@ -538,16 +570,17 @@ pgtsql_expression_tree_mutator(Node *node, void* context) if (IsA(node, FuncExpr)) { /* - * This is performed even in the postgres dialect to handle babelfish CI_AS - * collations so that regexp operators can work inside plpgsql functions + * This is performed even in the postgres dialect to handle babelfish + * CI_AS collations so that regexp operators can work inside plpgsql + * functions */ node = transform_funcexpr(node); } else if (IsA(node, OpExpr)) { - /* - * Possibly a singleton LIKE predicate: SELECT 'abc' LIKE 'ABC'; - * This is done even in the postgres dialect. + /* + * Possibly a singleton LIKE predicate: SELECT 'abc' LIKE 'ABC'; This + * is done even in the postgres dialect. */ node = transform_likenode(node); } @@ -555,25 +588,27 @@ pgtsql_expression_tree_mutator(Node *node, void* context) return node; } -Node* pltsql_planner_node_transformer(PlannerInfo *root, - Node *expr, - int kind) +Node * +pltsql_planner_node_transformer(PlannerInfo *root, + Node *expr, + int kind) { /* - * Fall out quickly if expression is empty. - */ + * Fall out quickly if expression is empty. + */ if (expr == NULL) return NULL; if (EXPRKIND_TARGET == kind) { - /* If expr is NOT a Boolean expression then recurse through - * its expresion tree - */ + /* + * If expr is NOT a Boolean expression then recurse through its + * expresion tree + */ return expression_tree_mutator( - expr, - pgtsql_expression_tree_mutator, - NULL); + expr, + pgtsql_expression_tree_mutator, + NULL); } return pltsql_predicate_transformer(expr); } @@ -584,14 +619,15 @@ init_and_check_collation_callbacks(void) if (!collation_callbacks_ptr) { collation_callbacks **callbacks_ptr; - callbacks_ptr = (collation_callbacks **) find_rendezvous_variable("collation_callbacks"); + + callbacks_ptr = (collation_callbacks **) find_rendezvous_variable("collation_callbacks"); collation_callbacks_ptr = *callbacks_ptr; /* collation_callbacks_ptr is still not initialised */ if (!collation_callbacks_ptr) ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("collation callbacks pointer is not initialised properly."))); + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("collation callbacks pointer is not initialised properly."))); } } @@ -604,7 +640,7 @@ tsql_get_server_collation_oid_internal(bool missingOk) /* Initialise collation callbacks */ init_and_check_collation_callbacks(); - server_collation_oid = (*collation_callbacks_ptr->get_server_collation_oid_internal)(missingOk); + server_collation_oid = (*collation_callbacks_ptr->get_server_collation_oid_internal) (missingOk); return server_collation_oid; } @@ -614,7 +650,7 @@ tsql_collation_list_internal(PG_FUNCTION_ARGS) /* Initialise collation callbacks */ init_and_check_collation_callbacks(); - return (*collation_callbacks_ptr->collation_list_internal)(fcinfo); + return (*collation_callbacks_ptr->collation_list_internal) (fcinfo); } Datum @@ -623,16 +659,16 @@ tsql_is_collated_ci_as_internal(PG_FUNCTION_ARGS) /* Initialise collation callbacks */ init_and_check_collation_callbacks(); - return (*collation_callbacks_ptr->is_collated_ci_as_internal)(fcinfo); + return (*collation_callbacks_ptr->is_collated_ci_as_internal) (fcinfo); } -bytea* +bytea * tsql_tdscollationproperty_helper(const char *collationaname, const char *property) { /* Initialise collation callbacks */ init_and_check_collation_callbacks(); - return (*collation_callbacks_ptr->tdscollationproperty_helper)(collationaname, property); + return (*collation_callbacks_ptr->tdscollationproperty_helper) (collationaname, property); } int @@ -641,7 +677,7 @@ tsql_collationproperty_helper(const char *collationaname, const char *property) /* Initialise collation callbacks */ init_and_check_collation_callbacks(); - return (*collation_callbacks_ptr->collationproperty_helper)(collationaname, property); + return (*collation_callbacks_ptr->collationproperty_helper) (collationaname, property); } bool @@ -650,7 +686,7 @@ tsql_is_server_collation_CI_AS(void) /* Initialise collation callbacks */ init_and_check_collation_callbacks(); - return (*collation_callbacks_ptr->is_server_collation_CI_AS)(); + return (*collation_callbacks_ptr->is_server_collation_CI_AS) (); } bool @@ -659,7 +695,7 @@ tsql_is_valid_server_collation_name(const char *collationname) /* Initialise collation callbacks */ init_and_check_collation_callbacks(); - return (*collation_callbacks_ptr->is_valid_server_collation_name)(collationname); + return (*collation_callbacks_ptr->is_valid_server_collation_name) (collationname); } int @@ -668,7 +704,7 @@ tsql_find_locale(const char *locale) /* Initialise collation callbacks */ init_and_check_collation_callbacks(); - return (*collation_callbacks_ptr->find_locale)(locale); + return (*collation_callbacks_ptr->find_locale) (locale); } Oid @@ -677,7 +713,7 @@ tsql_get_oid_from_collidx(int collidx) /* Initialise collation callbacks */ init_and_check_collation_callbacks(); - return (*collation_callbacks_ptr->get_oid_from_collidx_internal)(collidx); + return (*collation_callbacks_ptr->get_oid_from_collidx_internal) (collidx); } coll_info_t @@ -686,16 +722,16 @@ tsql_lookup_collation_table_internal(Oid oid) /* Initialise collation callbacks */ init_and_check_collation_callbacks(); - return (*collation_callbacks_ptr->lookup_collation_table_callback)(oid); + return (*collation_callbacks_ptr->lookup_collation_table_callback) (oid); } -like_ilike_info_t +like_ilike_info_t tsql_lookup_like_ilike_table_internal(Oid opno) { /* Initialise collation callbacks */ init_and_check_collation_callbacks(); - return (*collation_callbacks_ptr->lookup_like_ilike_table)(opno); + return (*collation_callbacks_ptr->lookup_like_ilike_table) (opno); } int @@ -704,7 +740,7 @@ tsql_find_cs_as_collation_internal(int collidx) /* Initialise collation callbacks */ init_and_check_collation_callbacks(); - return (*collation_callbacks_ptr->find_cs_as_collation_internal)(collidx); + return (*collation_callbacks_ptr->find_cs_as_collation_internal) (collidx); } int @@ -713,46 +749,49 @@ tsql_find_collation_internal(const char *collation_name) /* Initialise collation callbacks */ init_and_check_collation_callbacks(); - return (*collation_callbacks_ptr->find_collation_internal)(collation_name); + return (*collation_callbacks_ptr->find_collation_internal) (collation_name); } -const char* +const char * tsql_translate_bbf_collation_to_tsql_collation(const char *collname) { /* Initialise collation callbacks */ init_and_check_collation_callbacks(); - return (*collation_callbacks_ptr->translate_bbf_collation_to_tsql_collation)(collname); + return (*collation_callbacks_ptr->translate_bbf_collation_to_tsql_collation) (collname); } bool has_ilike_node_and_ci_as_coll(Node *expr) { - List *queue; - - if(expr == NULL) + List *queue; + + if (expr == NULL) return false; - + queue = list_make1(expr); - while(list_length(queue) > 0) + while (list_length(queue) > 0) { - Node *predicate = (Node *) linitial(queue); + Node *predicate = (Node *) linitial(queue); + queue = list_delete_first(queue); - - if(IsA(predicate, OpExpr)) + + if (IsA(predicate, OpExpr)) { - Oid inputcoll = ((OpExpr*) predicate)->inputcollid; + Oid inputcoll = ((OpExpr *) predicate)->inputcollid; + /* Initialize collation callbacks */ init_and_check_collation_callbacks(); - if ((*collation_callbacks_ptr->has_ilike_node)(predicate) && - DatumGetBool(DirectFunctionCall1Coll(tsql_is_collated_ci_as_internal, inputcoll, ObjectIdGetDatum(inputcoll)))) - return true; + if ((*collation_callbacks_ptr->has_ilike_node) (predicate) && + DatumGetBool(DirectFunctionCall1Coll(tsql_is_collated_ci_as_internal, inputcoll, ObjectIdGetDatum(inputcoll)))) + return true; } else if (IsA(predicate, BoolExpr)) { - BoolExpr *boolexpr = (BoolExpr *) predicate; + BoolExpr *boolexpr = (BoolExpr *) predicate; + queue = list_concat(queue, boolexpr->args); } } diff --git a/contrib/babelfishpg_tsql/src/collation.h b/contrib/babelfishpg_tsql/src/collation.h index 57c507c478..de332cf412 100644 --- a/contrib/babelfishpg_tsql/src/collation.h +++ b/contrib/babelfishpg_tsql/src/collation.h @@ -13,94 +13,96 @@ typedef struct coll_info { - Oid oid; /* oid is only retrievable during runtime, so we have to init to 0 */ + Oid oid; /* oid is only retrievable during runtime, so + * we have to init to 0 */ const char *collname; - int32_t lcid; /* lcid */ - int32_t ver; /* Ver */ - int32_t style; /* Style */ - int32_t sortid; /* Sort id */ - int32_t collateflags; /* Collate flags, changes based on case, accent, kana, width, bin */ - int32_t code_page; /* Code Page */ - pg_enc enc; /* encoding */ + int32_t lcid; /* lcid */ + int32_t ver; /* Ver */ + int32_t style; /* Style */ + int32_t sortid; /* Sort id */ + int32_t collateflags; /* Collate flags, changes based on case, + * accent, kana, width, bin */ + int32_t code_page; /* Code Page */ + pg_enc enc; /* encoding */ } coll_info_t; typedef struct like_ilike_info { - Oid like_oid; /* oid for like operators */ - char * like_op_name; /* the operator name for LIKE */ - char * ilike_op_name; /* the operator name for corresponding LIKE */ - char * op_left_schema; /* the schema of left operand */ - char * op_left_name; /* the name of left operand */ - char * op_right_schema; /* the schema of right operand */ - char * op_right_name; /* the name of right operand */ - bool is_not_match; /* if this is a NOT LIKE operator*/ - Oid ilike_oid; /* oid for corresponding ilike operators */ - Oid ilike_opfuncid; /* oid for corresponding ILIKE func */ + Oid like_oid; /* oid for like operators */ + char *like_op_name; /* the operator name for LIKE */ + char *ilike_op_name; /* the operator name for corresponding LIKE */ + char *op_left_schema; /* the schema of left operand */ + char *op_left_name; /* the name of left operand */ + char *op_right_schema; /* the schema of right operand */ + char *op_right_name; /* the name of right operand */ + bool is_not_match; /* if this is a NOT LIKE operator */ + Oid ilike_oid; /* oid for corresponding ilike operators */ + Oid ilike_opfuncid; /* oid for corresponding ILIKE func */ } like_ilike_info_t; /* match definition in babelfishpg_common:collation.h */ typedef struct collation_callbacks { /* Function pointers set up by the plugin */ - char* (*EncodingConversion)(const char *s, int len, int src_encoding, int dest_encoding, int *encodedByteLen); + char *(*EncodingConversion) (const char *s, int len, int src_encoding, int dest_encoding, int *encodedByteLen); - Oid (*get_server_collation_oid_internal)(bool missingOk); + Oid (*get_server_collation_oid_internal) (bool missingOk); coll_info_t (*lookup_collation_table_callback) (Oid oid); - like_ilike_info_t (*lookup_like_ilike_table)(Oid opno); + like_ilike_info_t (*lookup_like_ilike_table) (Oid opno); - Datum (*collation_list_internal)(PG_FUNCTION_ARGS); + Datum (*collation_list_internal) (PG_FUNCTION_ARGS); - Datum (*is_collated_ci_as_internal)(PG_FUNCTION_ARGS); + Datum (*is_collated_ci_as_internal) (PG_FUNCTION_ARGS); - int (*collationproperty_helper)(const char *collationaname, const char *property); + int (*collationproperty_helper) (const char *collationaname, const char *property); - bytea* (*tdscollationproperty_helper)(const char *collationaname, const char *property); + bytea *(*tdscollationproperty_helper) (const char *collationaname, const char *property); - bool (*is_server_collation_CI_AS)(void); + bool (*is_server_collation_CI_AS) (void); - bool (*is_valid_server_collation_name)(const char *collationname); + bool (*is_valid_server_collation_name) (const char *collationname); - int (*find_locale)(const char *locale); + int (*find_locale) (const char *locale); - Oid (*get_oid_from_collidx_internal)(int collidx); + Oid (*get_oid_from_collidx_internal) (int collidx); - int (*find_cs_as_collation_internal)(int collidx); + int (*find_cs_as_collation_internal) (int collidx); - int (*find_collation_internal)(const char *collation_name); + int (*find_collation_internal) (const char *collation_name); - bool (*has_ilike_node)(Node *expr); + bool (*has_ilike_node) (Node *expr); - const char* (*translate_bbf_collation_to_tsql_collation)(const char *collname); + const char *(*translate_bbf_collation_to_tsql_collation) (const char *collname); } collation_callbacks; extern collation_callbacks *collation_callbacks_ptr; /* Wrappers to call any callback functions from collation_callbacks_ptr. */ -extern Oid tsql_get_server_collation_oid_internal(bool missingOk); +extern Oid tsql_get_server_collation_oid_internal(bool missingOk); extern Datum tsql_collation_list_internal(PG_FUNCTION_ARGS); extern Datum tsql_is_collated_ci_as_internal(PG_FUNCTION_ARGS); -extern int tsql_collationproperty_helper(const char *collationaname, const char *property); -extern bytea* tsql_tdscollationproperty_helper(const char *collationaname, const char *property); +extern int tsql_collationproperty_helper(const char *collationaname, const char *property); +extern bytea *tsql_tdscollationproperty_helper(const char *collationaname, const char *property); extern bool tsql_is_server_collation_CI_AS(void); extern bool tsql_is_valid_server_collation_name(const char *collationname); -extern int tsql_find_locale(const char *locale); -extern Oid tsql_get_oid_from_collidx(int collidx); +extern int tsql_find_locale(const char *locale); +extern Oid tsql_get_oid_from_collidx(int collidx); coll_info_t tsql_lookup_collation_table_internal(Oid oid); like_ilike_info_t tsql_lookup_like_ilike_table_internal(Oid opno); -int tsql_find_cs_as_collation_internal(int collidx); -int tsql_find_collation_internal(const char *collation_name); -extern const char* tsql_translate_bbf_collation_to_tsql_collation(const char *collname); +int tsql_find_cs_as_collation_internal(int collidx); +int tsql_find_collation_internal(const char *collation_name); +extern const char *tsql_translate_bbf_collation_to_tsql_collation(const char *collname); /* Utility functions */ extern bool has_ilike_node_and_ci_as_coll(Node *expr); -extern Node* pltsql_planner_node_transformer(PlannerInfo *root, - Node *expr, - int kind); -extern Node* pltsql_predicate_transformer(Node *expr); +extern Node *pltsql_planner_node_transformer(PlannerInfo *root, + Node *expr, + int kind); +extern Node *pltsql_predicate_transformer(Node *expr); /* Expression kind codes for preprocess_expression */ #define EXPRKIND_QUAL 0 diff --git a/contrib/babelfishpg_tsql/src/collationproperty.c b/contrib/babelfishpg_tsql/src/collationproperty.c index 246ab5733c..e36988bada 100644 --- a/contrib/babelfishpg_tsql/src/collationproperty.c +++ b/contrib/babelfishpg_tsql/src/collationproperty.c @@ -18,26 +18,27 @@ PG_FUNCTION_INFO_V1(collationproperty); -extern coll_info_t coll_infos[]; +extern coll_info_t coll_infos[]; -Datum collationproperty(PG_FUNCTION_ARGS) +Datum +collationproperty(PG_FUNCTION_ARGS) { const char *collationname = text_to_cstring(PG_GETARG_TEXT_P(0)); const char *property = text_to_cstring(PG_GETARG_TEXT_P(1)); - bytea *result64 = NULL; - int result32 = -1; + bytea *result64 = NULL; + int result32 = -1; if (strcasecmp(property, "tdscollation") == 0) { result64 = tsql_tdscollationproperty_helper(collationname, property); - if(result64 != NULL) + if (result64 != NULL) PG_RETURN_BYTEA_P(result64); } - else + else { - result32 = tsql_collationproperty_helper(collationname, property); + result32 = tsql_collationproperty_helper(collationname, property); if (result32 != -1) - PG_RETURN_BYTEA_P((*common_utility_plugin_ptr->convertIntToSQLVariantByteA)(result32)); + PG_RETURN_BYTEA_P((*common_utility_plugin_ptr->convertIntToSQLVariantByteA) (result32)); } PG_RETURN_NULL(); } diff --git a/contrib/babelfishpg_tsql/src/compile_context.c b/contrib/babelfishpg_tsql/src/compile_context.c index a0044d8571..0510cc7edd 100644 --- a/contrib/babelfishpg_tsql/src/compile_context.c +++ b/contrib/babelfishpg_tsql/src/compile_context.c @@ -1,46 +1,49 @@ #include "postgres.h" #include "compile_context.h" -CompileContext *create_compile_context(void) +CompileContext * +create_compile_context(void) { - CompileContext *cmpl_ctx = palloc(sizeof(CompileContext)); - HASHCTL hashCtl; + CompileContext *cmpl_ctx = palloc(sizeof(CompileContext)); + HASHCTL hashCtl; - /* stmt scope map */ - MemSet(&hashCtl, 0, sizeof(hashCtl)); - hashCtl.keysize = sizeof(PLtsql_stmt *); - hashCtl.entrysize = sizeof(ScopeContext); - hashCtl.hcxt = CurrentMemoryContext; - cmpl_ctx->stmt_scope_context = hash_create("Stmt to scope context mapping", - 16, /* initial hashmap size */ - &hashCtl, - HASH_ELEM | HASH_CONTEXT | HASH_BLOBS ); + /* stmt scope map */ + MemSet(&hashCtl, 0, sizeof(hashCtl)); + hashCtl.keysize = sizeof(PLtsql_stmt *); + hashCtl.entrysize = sizeof(ScopeContext); + hashCtl.hcxt = CurrentMemoryContext; + cmpl_ctx->stmt_scope_context = hash_create("Stmt to scope context mapping", + 16, /* initial hashmap size */ + &hashCtl, + HASH_ELEM | HASH_CONTEXT | HASH_BLOBS); - /* label stmt map */ - MemSet(&hashCtl, 0, sizeof(hashCtl)); - hashCtl.keysize = NAMEDATALEN; - hashCtl.entrysize = sizeof(LabelStmtEntry); - hashCtl.hcxt = CurrentMemoryContext; - cmpl_ctx->label_stmt_map = hash_create("Label to stmt mapping", - 16, /* initial hashmap size */ - &hashCtl, - HASH_ELEM | HASH_STRINGS | HASH_CONTEXT ); /* string comp */ - - return cmpl_ctx; + /* label stmt map */ + MemSet(&hashCtl, 0, sizeof(hashCtl)); + hashCtl.keysize = NAMEDATALEN; + hashCtl.entrysize = sizeof(LabelStmtEntry); + hashCtl.hcxt = CurrentMemoryContext; + cmpl_ctx->label_stmt_map = hash_create("Label to stmt mapping", + 16, /* initial hashmap size */ + &hashCtl, + HASH_ELEM | HASH_STRINGS | HASH_CONTEXT); /* string comp */ + + return cmpl_ctx; } -void destroy_compile_context(CompileContext *cmpl_ctx) +void +destroy_compile_context(CompileContext *cmpl_ctx) { - HASH_SEQ_STATUS status; - ScopeContext *scope; - /* destroy scope context */ - hash_seq_init(&status, cmpl_ctx->stmt_scope_context); - while ((scope = (ScopeContext *) hash_seq_search(&status)) != NULL) - { - destroy_vector(scope->nesting_trycatch_infos); - destroy_vector(scope->nesting_loops); - } - hash_destroy(cmpl_ctx->stmt_scope_context); - hash_destroy(cmpl_ctx->label_stmt_map); - pfree(cmpl_ctx); + HASH_SEQ_STATUS status; + ScopeContext *scope; + + /* destroy scope context */ + hash_seq_init(&status, cmpl_ctx->stmt_scope_context); + while ((scope = (ScopeContext *) hash_seq_search(&status)) != NULL) + { + destroy_vector(scope->nesting_trycatch_infos); + destroy_vector(scope->nesting_loops); + } + hash_destroy(cmpl_ctx->stmt_scope_context); + hash_destroy(cmpl_ctx->label_stmt_map); + pfree(cmpl_ctx); } diff --git a/contrib/babelfishpg_tsql/src/compile_context.h b/contrib/babelfishpg_tsql/src/compile_context.h index 10462f4fed..2211d31029 100644 --- a/contrib/babelfishpg_tsql/src/compile_context.h +++ b/contrib/babelfishpg_tsql/src/compile_context.h @@ -8,7 +8,7 @@ /* * Compilation Context - * + * * Note: * Each sub-component should be able to independently manage its own runtiem information. * E.g AnalyzerContext for analyzer, CodegenContext for codegen @@ -18,33 +18,33 @@ typedef struct { - PLtsql_stmt *stmt; /* stmt_try_catch */ - bool in_try_block; /* false if in catch block */ + PLtsql_stmt *stmt; /* stmt_try_catch */ + bool in_try_block; /* false if in catch block */ } TryCatchInfo; typedef struct { - PLtsql_stmt *stmt; - DynaVec *nesting_trycatch_infos; - DynaVec *nesting_loops; + PLtsql_stmt *stmt; + DynaVec *nesting_trycatch_infos; + DynaVec *nesting_loops; } ScopeContext; typedef struct { - char label[NAMEDATALEN]; - PLtsql_stmt_label *stmt; + char label[NAMEDATALEN]; + PLtsql_stmt_label *stmt; } LabelStmtEntry; -typedef struct +typedef struct { - /* stmt wise scope info, stmt -> ScopeContext */ - HTAB *stmt_scope_context; + /* stmt wise scope info, stmt -> ScopeContext */ + HTAB *stmt_scope_context; - /* label to stmt_label */ - HTAB *label_stmt_map; + /* label to stmt_label */ + HTAB *label_stmt_map; } CompileContext; CompileContext *create_compile_context(void); -void destroy_compile_context(CompileContext *context); +void destroy_compile_context(CompileContext *context); #endif diff --git a/contrib/babelfishpg_tsql/src/cursor.c b/contrib/babelfishpg_tsql/src/cursor.c index 05a459a7f4..05dcf05d01 100644 --- a/contrib/babelfishpg_tsql/src/cursor.c +++ b/contrib/babelfishpg_tsql/src/cursor.c @@ -23,19 +23,19 @@ extern void assign_text_var(PLtsql_execstate *estate, PLtsql_var *var, const cha /* cursor handle */ const uint32 CURSOR_HANDLE_INVALID = 0xABCDEF0; /* magic number used in T-SQL */ static uint32 current_cursor_handle; -uint32 get_next_cursor_handle(void); +uint32 get_next_cursor_handle(void); const uint32 CURSOR_PREPARED_HANDLE_START = 1073741824; const uint32 CURSOR_PREPARED_HANDLE_INVALID = 0xFFFFFFFF; -static int current_cursor_prepared_handle; -uint32 get_next_cursor_prepared_handle(void); +static int current_cursor_prepared_handle; +uint32 get_next_cursor_prepared_handle(void); /* functions called in pl_exec */ -bool pltsql_declare_cursor(PLtsql_execstate *estate, PLtsql_var *var, PLtsql_expr* explicit_expr, int cursor_options); -void pltsql_init_anonymous_cursors(PLtsql_execstate *estate); -void pltsql_cleanup_local_cursors(PLtsql_execstate *estate); +bool pltsql_declare_cursor(PLtsql_execstate *estate, PLtsql_var *var, PLtsql_expr *explicit_expr, int cursor_options); +void pltsql_init_anonymous_cursors(PLtsql_execstate *estate); +void pltsql_cleanup_local_cursors(PLtsql_execstate *estate); -char *pltsql_demangle_curname(char *curname); +char *pltsql_demangle_curname(char *curname); /* sp_cursor parameter handling */ static lookup_param_hook_type prev_lookup_param_hook; @@ -43,34 +43,35 @@ static List *sp_cursor_params = NIL; static Node *sp_cursor_find_param(ParseState *pstate, ColumnRef *cref); -void enable_sp_cursor_find_param_hook(void); -void disable_sp_cursor_find_param_hook(void); -void add_sp_cursor_param(char *name); -void reset_sp_cursor_params(void); +void enable_sp_cursor_find_param_hook(void); +void disable_sp_cursor_find_param_hook(void); +void add_sp_cursor_param(char *name); +void reset_sp_cursor_params(void); /* cursor information hashtab */ typedef struct cursorhashent { - char curname[NAMEDATALEN + 1]; + char curname[NAMEDATALEN + 1]; PLtsql_expr *explicit_expr; - uint32 cursor_options; - int16 fetch_status; - int16 last_operation; - uint64 row_count; - int32 cursor_handle; - bool api_cursor; /* only used in cursor_list now. can be deprecated once we supprot global cursor */ - TupleDesc tupdesc; + uint32 cursor_options; + int16 fetch_status; + int16 last_operation; + uint64 row_count; + int32 cursor_handle; + bool api_cursor; /* only used in cursor_list now. can be + * deprecated once we supprot global cursor */ + TupleDesc tupdesc; Tuplestorestate *fetch_buffer; - char *textptr_only_bitmap; + char *textptr_only_bitmap; } CursorHashEnt; static HTAB *CursorHashTable = NULL; typedef struct cursorpreparedhandlehashent { - uint32 handle; - SPIPlanPtr plan; - int cursor_options; + uint32 handle; + SPIPlanPtr plan; + int cursor_options; } CurosrPreparedHandleHashEnt; static HTAB *CursorPreparedHandleHashTable = NULL; @@ -78,32 +79,32 @@ static HTAB *CursorPreparedHandleHashTable = NULL; static MemoryContext CursorHashtabContext = NULL; /* cursor hashtab operations */ -void pltsql_create_cursor_htab(void); -CursorHashEnt *pltsql_insert_cursor_entry(char *curname, PLtsql_expr *explicit_expr, int cursor_options, int* cursor_handle); -void pltsql_delete_cursor_entry(char *curname, bool missing_ok); -void pltsql_get_cursor_definition(char *curname, PLtsql_expr **explicit_expr, int* cursor_options); -void pltsql_update_cursor_fetch_status(char *curname, int fetch_status); -void pltsql_update_cursor_row_count(char *curname, int64 row_count); -void pltsql_update_cursor_last_operation(char *curname, int last_operation); +void pltsql_create_cursor_htab(void); +CursorHashEnt *pltsql_insert_cursor_entry(char *curname, PLtsql_expr *explicit_expr, int cursor_options, int *cursor_handle); +void pltsql_delete_cursor_entry(char *curname, bool missing_ok); +void pltsql_get_cursor_definition(char *curname, PLtsql_expr **explicit_expr, int *cursor_options); +void pltsql_update_cursor_fetch_status(char *curname, int fetch_status); +void pltsql_update_cursor_row_count(char *curname, int64 row_count); +void pltsql_update_cursor_last_operation(char *curname, int last_operation); static const char *LOCAL_CURSOR_INFIX = "##sys_gen##"; -bool is_cursor_datatype(Oid oid); -static Oid tsql_cursor_oid = InvalidOid; -static Oid lookup_tsql_cursor_oid(void); +bool is_cursor_datatype(Oid oid); +static Oid tsql_cursor_oid = InvalidOid; +static Oid lookup_tsql_cursor_oid(void); /* keep the name of last opened cursor name for @@cursor_rows */ static char last_opened_cursor[NAMEDATALEN + 1]; /* implementation function shared between cursor functions and procedures */ -static int cursor_status_impl(PLtsql_var *var); -static int cursor_status_impl2(const char *curname); -static int cursor_rows_impl(const char *curname); -static int cursor_column_count_impl(const char *curname); +static int cursor_status_impl(PLtsql_var *var); +static int cursor_status_impl2(const char *curname); +static int cursor_rows_impl(const char *curname); +static int cursor_column_count_impl(const char *curname); -static int execute_sp_cursoropen_common(int* stmt_handle, int *cursor_handle, const char *stmt, int *pscrollopt, int *pccopt, int *row_count, int nparams, int nBindParams, Oid *boundParamsOidList, Datum *values, const char *nulls, bool prepare, bool save_plan, bool execute); +static int execute_sp_cursoropen_common(int *stmt_handle, int *cursor_handle, const char *stmt, int *pscrollopt, int *pccopt, int *row_count, int nparams, int nBindParams, Oid *boundParamsOidList, Datum *values, const char *nulls, bool prepare, bool save_plan, bool execute); static void validate_sp_cursor_params(int opttype, int rownum, const char *tablename, List *values); -static int validate_and_get_sp_cursoropen_params(int scrollopt, int ccopt); +static int validate_and_get_sp_cursoropen_params(int scrollopt, int ccopt); static void validate_and_get_sp_cursorfetch_params(int *fetchtype_in, int *rownum_in, int *nrows_in, int *fetchtype_out, int *rownum_out, int *nrows_out); static void validate_sp_cursoroption_params(int code, int value); @@ -120,10 +121,11 @@ PG_FUNCTION_INFO_V1(pltsql_get_last_cursor_handle); PG_FUNCTION_INFO_V1(pltsql_get_last_stmt_handle); /* Start of implementation */ -uint32 get_next_cursor_handle() +uint32 +get_next_cursor_handle() { - char curname[NAMEDATALEN]; - uint32 old_handle = current_cursor_handle; + char curname[NAMEDATALEN]; + uint32 old_handle = current_cursor_handle; while (true) { @@ -134,14 +136,15 @@ uint32 get_next_cursor_handle() elog(ERROR, "out of sp cursor handles"); snprintf(curname, NAMEDATALEN, "%u", current_cursor_handle); if (hash_search(CursorHashTable, curname, HASH_FIND, NULL) == NULL) - break; /* found */ + break; /* found */ } return current_cursor_handle; } -uint32 get_next_cursor_prepared_handle() +uint32 +get_next_cursor_prepared_handle() { - uint32 old_handle = current_cursor_prepared_handle; + uint32 old_handle = current_cursor_prepared_handle; while (true) { @@ -151,13 +154,14 @@ uint32 get_next_cursor_prepared_handle() if (unlikely(current_cursor_prepared_handle == old_handle)) elog(ERROR, "out of sp cursor prepared handles"); if (hash_search(CursorPreparedHandleHashTable, ¤t_cursor_prepared_handle, HASH_FIND, NULL) == NULL) - break; /* found */ + break; /* found */ } return current_cursor_prepared_handle; } -bool is_cursor_datatype(Oid oid) +bool +is_cursor_datatype(Oid oid) { if (oid == REFCURSOROID) return true; @@ -171,8 +175,8 @@ bool is_cursor_datatype(Oid oid) static Oid lookup_tsql_cursor_oid() { - Oid nspoid; - Oid typoid; + Oid nspoid; + Oid typoid; nspoid = get_namespace_oid("sys", true); if (nspoid == InvalidOid) @@ -182,45 +186,48 @@ lookup_tsql_cursor_oid() return typoid; } -bool pltsql_declare_cursor(PLtsql_execstate *estate, PLtsql_var *var, PLtsql_expr* explicit_expr, int cursor_options) +bool +pltsql_declare_cursor(PLtsql_execstate *estate, PLtsql_var *var, PLtsql_expr *explicit_expr, int cursor_options) { - char *curname; + char *curname; CursorHashEnt *hentry; - Portal portal; - char mangled_name[NAMEDATALEN]; + Portal portal; + char mangled_name[NAMEDATALEN]; if (!var->isnull) { curname = TextDatumGetCString(var->value); hentry = (CursorHashEnt *) hash_search(CursorHashTable, curname, HASH_FIND, NULL); - if (hentry != NULL) /* already declared */ + if (hentry != NULL) /* already declared */ { portal = SPI_cursor_find(hentry->curname); if (portal != NULL) - return false; /* already opened portal */ + return false; /* already opened portal */ if (hentry->last_operation != 7) - return false; /* not dealloc'd */ + return false; /* not dealloc'd */ pltsql_delete_cursor_entry(curname, false); } } /* - * For local cursor, the same cursor name may be already taken by parent function/procedure - * To avoid conflict, generate a unique name by using var pointer. + * For local cursor, the same cursor name may be already taken by parent + * function/procedure To avoid conflict, generate a unique name by using + * var pointer. * - * SPI proc memory context is used here intentionally. - * It will be destoryed at the end of function/procedure call. - * It has the same lifecycle with LOCAL cursor by its definition. - * When we implement GLOBAL cursor, its lifespan is longer so we have to use different memory context. + * SPI proc memory context is used here intentionally. It will be + * destoryed at the end of function/procedure call. It has the same + * lifecycle with LOCAL cursor by its definition. When we implement GLOBAL + * cursor, its lifespan is longer so we have to use different memory + * context. */ Assert(var->refname != NULL); if (strlen(var->refname) + strlen(LOCAL_CURSOR_INFIX) + 19 > NAMEDATALEN) ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("internal cursor name is too long: %s", var->refname))); + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("internal cursor name is too long: %s", var->refname))); snprintf(mangled_name, NAMEDATALEN, "%s%s%p", var->refname, LOCAL_CURSOR_INFIX, var); @@ -234,24 +241,34 @@ bool pltsql_declare_cursor(PLtsql_execstate *estate, PLtsql_var *var, PLtsql_exp return true; } -void pltsql_init_anonymous_cursors(PLtsql_execstate *estate) +void +pltsql_init_anonymous_cursors(PLtsql_execstate *estate) { - /* This a rountine to handle anonymous (impliicitly declaring cursor via SET @curvar = CURSOR FOR ) */ + /* + * This a rountine to handle anonymous (impliicitly declaring cursor via + * SET @curvar = CURSOR FOR ) + */ - char* curname; - int cursor_options; - int i; + char *curname; + int cursor_options; + int i; - /* find cursor variables, assign cursor name and put cursor information to cursor hash. */ + /* + * find cursor variables, assign cursor name and put cursor information to + * cursor hash. + */ for (i = 0; i < estate->ndatums; ++i) { if (estate->datums[i]->dtype == PLTSQL_DTYPE_VAR) { PLtsql_var *var = (PLtsql_var *) estate->datums[i]; + if (is_cursor_datatype(var->datatype->typoid) && - var->isconst && /* if cursor variable, it means it just refers to another constant cursor. skip it */ - !(var->cursor_options & TSQL_CURSOR_OPT_GLOBAL) && /* GLOBAL cursor is not supported yet */ - var->cursor_options & PGTSQL_CURSOR_ANONYMOUS) + var->isconst && /* if cursor variable, it means it just refers + * to another constant cursor. skip it */ + !(var->cursor_options & TSQL_CURSOR_OPT_GLOBAL) && /* GLOBAL cursor is not + * supported yet */ + var->cursor_options & PGTSQL_CURSOR_ANONYMOUS) { Assert(var->isnull); @@ -259,7 +276,10 @@ void pltsql_init_anonymous_cursors(PLtsql_execstate *estate) assign_text_var(estate, var, var->refname); curname = TextDatumGetCString(var->value); - /* remove PGTSQL_ANONYMOUS_CURSOR from cursor option since the entry can be shared among with refcursor */ + /* + * remove PGTSQL_ANONYMOUS_CURSOR from cursor option since the + * entry can be shared among with refcursor + */ cursor_options = (var->cursor_options & ~PGTSQL_CURSOR_ANONYMOUS); pltsql_insert_cursor_entry(curname, var->cursor_explicit_expr, cursor_options, NULL); } @@ -267,11 +287,12 @@ void pltsql_init_anonymous_cursors(PLtsql_execstate *estate) } } -void pltsql_cleanup_local_cursors(PLtsql_execstate *estate) +void +pltsql_cleanup_local_cursors(PLtsql_execstate *estate) { - Portal portal; - char *curname; - int i; + Portal portal; + char *curname; + int i; /* close local cursor made by this estate */ for (i = 0; i < estate->ndatums; ++i) @@ -279,15 +300,21 @@ void pltsql_cleanup_local_cursors(PLtsql_execstate *estate) if (estate->datums[i]->dtype == PLTSQL_DTYPE_VAR) { PLtsql_var *var = (PLtsql_var *) estate->datums[i]; + if (is_cursor_datatype(var->datatype->typoid) && - var->isconst && /* if cursor variable, it means it just refers to another constant cursor. skip it */ - !var->isnull && - !(var->cursor_options & TSQL_CURSOR_OPT_GLOBAL)) + var->isconst && /* if cursor variable, it means it just refers + * to another constant cursor. skip it */ + !var->isnull && + !(var->cursor_options & TSQL_CURSOR_OPT_GLOBAL)) { curname = TextDatumGetCString(var->value); portal = SPI_cursor_find(curname); - if (portal) { - if (portal->portalPinned) /* LOCAL cursor should be closed/deallocated at the end of block. unpin portal if already pinned */ + if (portal) + { + if (portal->portalPinned) /* LOCAL cursor should be + * closed/deallocated at the + * end of block. unpin portal + * if already pinned */ UnpinPortal(portal); SPI_cursor_close(portal); @@ -298,12 +325,13 @@ void pltsql_cleanup_local_cursors(PLtsql_execstate *estate) } } -char *pltsql_demangle_curname(char *curname) +char * +pltsql_demangle_curname(char *curname) { - char *infix_substr; - char *p; - char *p2; - Size len; + char *infix_substr; + char *p; + char *p2; + Size len; if (curname == NULL) return NULL; @@ -311,7 +339,10 @@ char *pltsql_demangle_curname(char *curname) infix_substr = NULL; p = curname; - /* cursor name given from user may contain LOCAL_CURSOR_INFIX. find the last LOCAL_CURSOR_INFIX */ + /* + * cursor name given from user may contain LOCAL_CURSOR_INFIX. find the + * last LOCAL_CURSOR_INFIX + */ while ((p2 = strstr(p, LOCAL_CURSOR_INFIX)) != NULL) { infix_substr = p2; @@ -319,7 +350,7 @@ char *pltsql_demangle_curname(char *curname) } if (infix_substr == NULL) - return curname; /* can't find LOCAL_CURSOR_INFIX */ + return curname; /* can't find LOCAL_CURSOR_INFIX */ len = infix_substr - curname; return pnstrdup(curname, len); @@ -339,16 +370,17 @@ char *pltsql_demangle_curname(char *curname) Node * sp_cursor_find_param(ParseState *pstate, ColumnRef *cref) { - ParamRef *pref; - char *colname; - ListCell *cell; - int i = 1; - int param_no = 0; - Node *result; + ParamRef *pref; + char *colname; + ListCell *cell; + int i = 1; + int param_no = 0; + Node *result; if (prev_lookup_param_hook) { - Node *found = (*prev_lookup_param_hook) (pstate, cref); + Node *found = (*prev_lookup_param_hook) (pstate, cref); + if (found) return found; } @@ -363,6 +395,7 @@ sp_cursor_find_param(ParseState *pstate, ColumnRef *cref) foreach(cell, sp_cursor_params) { const char *param_name = lfirst(cell); + if (pg_strcasecmp(colname, param_name) == 0) { param_no = i; @@ -372,7 +405,7 @@ sp_cursor_find_param(ParseState *pstate, ColumnRef *cref) } if (param_no == 0) - return NULL; /* not found */ + return NULL; /* not found */ pref = makeNode(ParamRef); pref->number = param_no; @@ -384,6 +417,7 @@ sp_cursor_find_param(ParseState *pstate, ColumnRef *cref) */ if (pstate->p_paramref_hook != NULL) result = pstate->p_paramref_hook(pstate, pref); + else result = NULL; @@ -396,33 +430,38 @@ sp_cursor_find_param(ParseState *pstate, ColumnRef *cref) return result; } -void enable_sp_cursor_find_param_hook() +void +enable_sp_cursor_find_param_hook() { prev_lookup_param_hook = lookup_param_hook; lookup_param_hook = sp_cursor_find_param; } -void disable_sp_cursor_find_param_hook() +void +disable_sp_cursor_find_param_hook() { lookup_param_hook = prev_lookup_param_hook; prev_lookup_param_hook = NULL; } -void add_sp_cursor_param(char *name) +void +add_sp_cursor_param(char *name) { sp_cursor_params = lappend(sp_cursor_params, name); } -void reset_sp_cursor_params() +void +reset_sp_cursor_params() { sp_cursor_params = NIL; } -void pltsql_create_cursor_htab() +void +pltsql_create_cursor_htab() { HASHCTL ctl; - if (CursorHashtabContext == NULL) /* intialize memory context */ + if (CursorHashtabContext == NULL) /* intialize memory context */ { CursorHashtabContext = AllocSetContextCreateInternal(NULL, "PLtsql Cursor hashtab Memory Context", ALLOCSET_DEFAULT_SIZES); } @@ -433,7 +472,7 @@ void pltsql_create_cursor_htab() ctl.entrysize = sizeof(CursorHashEnt); ctl.hcxt = CursorHashtabContext; - CursorHashTable = hash_create("T-SQL cursor information", 16 /*PORTALS_PER_USER*/, &ctl, HASH_ELEM | HASH_STRINGS | HASH_CONTEXT); + CursorHashTable = hash_create("T-SQL cursor information", 16 /* PORTALS_PER_USER */ , &ctl, HASH_ELEM | HASH_STRINGS | HASH_CONTEXT); current_cursor_handle = CURSOR_HANDLE_INVALID; @@ -443,15 +482,16 @@ void pltsql_create_cursor_htab() ctl.entrysize = sizeof(CurosrPreparedHandleHashEnt); ctl.hcxt = CursorHashtabContext; - CursorPreparedHandleHashTable = hash_create("T-SQL cursor prepared handle", 16 /*PORTALS_PER_USER*/, &ctl, HASH_ELEM | HASH_BLOBS | HASH_CONTEXT); + CursorPreparedHandleHashTable = hash_create("T-SQL cursor prepared handle", 16 /* PORTALS_PER_USER */ , &ctl, HASH_ELEM | HASH_BLOBS | HASH_CONTEXT); current_cursor_prepared_handle = CURSOR_PREPARED_HANDLE_START; } -CursorHashEnt *pltsql_insert_cursor_entry(char *curname, PLtsql_expr *explicit_expr, int cursor_options, int* cursor_handle) +CursorHashEnt * +pltsql_insert_cursor_entry(char *curname, PLtsql_expr *explicit_expr, int cursor_options, int *cursor_handle) { CursorHashEnt *hentry; - bool found; + bool found; hentry = (CursorHashEnt *) hash_search(CursorHashTable, curname, HASH_ENTER, &found); if (found) @@ -464,9 +504,10 @@ CursorHashEnt *pltsql_insert_cursor_entry(char *curname, PLtsql_expr *explicit_e hentry->fetch_status = -9; hentry->row_count = 0; hentry->last_operation = 0; - if (cursor_handle) /* use given cursor_handle. mostly api cursor */ + if (cursor_handle) /* use given cursor_handle. mostly api cursor */ hentry->cursor_handle = *cursor_handle; - else /* assign a new cursor handle. mostly language cursor */ + else /* assign a new cursor handle. mostly language + * cursor */ hentry->cursor_handle = get_next_cursor_handle(); hentry->api_cursor = false; hentry->tupdesc = NULL; @@ -476,7 +517,8 @@ CursorHashEnt *pltsql_insert_cursor_entry(char *curname, PLtsql_expr *explicit_e return hentry; } -void pltsql_delete_cursor_entry(char *curname, bool missing_ok) +void +pltsql_delete_cursor_entry(char *curname, bool missing_ok) { CursorHashEnt *hentry; @@ -504,7 +546,8 @@ void pltsql_delete_cursor_entry(char *curname, bool missing_ok) elog(WARNING, "trying to delete cursor name that does not exist"); } -void pltsql_get_cursor_definition(char *curname, PLtsql_expr **explicit_expr, int* cursor_options) +void +pltsql_get_cursor_definition(char *curname, PLtsql_expr **explicit_expr, int *cursor_options) { CursorHashEnt *hentry; @@ -521,7 +564,8 @@ void pltsql_get_cursor_definition(char *curname, PLtsql_expr **explicit_expr, in } } -void pltsql_update_cursor_fetch_status(char *curname, int fetch_status) +void +pltsql_update_cursor_fetch_status(char *curname, int fetch_status) { CursorHashEnt *hentry; @@ -530,7 +574,8 @@ void pltsql_update_cursor_fetch_status(char *curname, int fetch_status) hentry->fetch_status = fetch_status; } -void pltsql_update_cursor_row_count(char *curname, int64 row_count) +void +pltsql_update_cursor_row_count(char *curname, int64 row_count) { CursorHashEnt *hentry; @@ -539,7 +584,8 @@ void pltsql_update_cursor_row_count(char *curname, int64 row_count) hentry->row_count = row_count; } -void pltsql_update_cursor_last_operation(char *curname, int last_operation) +void +pltsql_update_cursor_last_operation(char *curname, int last_operation) { CursorHashEnt *hentry; @@ -548,7 +594,7 @@ void pltsql_update_cursor_last_operation(char *curname, int last_operation) hentry->last_operation = last_operation; /* keep the last opened cursor for @@cursor_rows */ - if (last_operation == 1) /* open */ + if (last_operation == 1) /* open */ { last_opened_cursor[0] = '\0'; strncat(last_opened_cursor, curname, NAMEDATALEN); @@ -569,9 +615,9 @@ Datum cursor_status(PG_FUNCTION_ARGS) { PLtsql_execstate *estate; - char *curtype; - char *refname; - int i; + char *curtype; + char *refname; + int i; /* get current tsql estate */ estate = get_current_tsql_estate(); @@ -600,6 +646,7 @@ cursor_status(PG_FUNCTION_ARGS) if (estate->datums[i]->dtype == PLTSQL_DTYPE_VAR) { PLtsql_var *var = (PLtsql_var *) estate->datums[i]; + if (is_cursor_datatype(var->datatype->typoid) && strcasecmp(var->refname, refname) == 0) { /* ignore cursor not matching with cursor source */ @@ -617,9 +664,10 @@ cursor_status(PG_FUNCTION_ARGS) PG_RETURN_INT32(-3); } -static int cursor_status_impl(PLtsql_var *var) +static int +cursor_status_impl(PLtsql_var *var) { - char *curname; + char *curname; if (var->isnull) { @@ -630,10 +678,11 @@ static int cursor_status_impl(PLtsql_var *var) return cursor_status_impl2(curname); } -static int cursor_status_impl2(const char *curname) +static int +cursor_status_impl2(const char *curname) { CursorHashEnt *hentry; - Portal portal; + Portal portal; hentry = (CursorHashEnt *) hash_search(CursorHashTable, curname, HASH_FIND, NULL); if (hentry == NULL) @@ -641,7 +690,7 @@ static int cursor_status_impl2(const char *curname) (errcode(ERRCODE_INTERNAL_ERROR), errmsg("cursor_status() cannot find cursor entry"))); - if (hentry->last_operation == 7) /* dealloc'd */ + if (hentry->last_operation == 7) /* dealloc'd */ return -3; portal = SPI_cursor_find(curname); @@ -653,20 +702,22 @@ static int cursor_status_impl2(const char *curname) else { /* - * Note: - * For STATIC and KEYSET CURSOR, TSQL CURSOR_STATUS() can return 0 if result set is empty - * even though cursor is not fetched yet. It is thought that it's because T-SQL store the - * result set (full or key only) to temporary storage when cursor is opened. - * PG doesn't behave like that for INSENSTIVE (=STATIC) cursor (maybe by virtue of its MVCC) - * Hence, always return 1 here for now. It will be discussed further with DBE, and documented if needed. + * Note: For STATIC and KEYSET CURSOR, TSQL CURSOR_STATUS() can return + * 0 if result set is empty even though cursor is not fetched yet. It + * is thought that it's because T-SQL store the result set (full or + * key only) to temporary storage when cursor is opened. PG doesn't + * behave like that for INSENSTIVE (=STATIC) cursor (maybe by virtue + * of its MVCC) Hence, always return 1 here for now. It will be + * discussed further with DBE, and documented if needed. */ return 1; } } -static int cursor_rows_impl(const char *curname) +static int +cursor_rows_impl(const char *curname) { - Portal portal; + Portal portal; portal = SPI_cursor_find(curname); if (portal == NULL) @@ -677,17 +728,19 @@ static int cursor_rows_impl(const char *curname) else { /* - * Note: PG cursor is INSENSITIVE (=STATIC) cursor but its implemenation doesn't store - * the result into temporary storage other than T-SQL does. - * We don't know the # of rows. So return -1 here as same as DYNAMIC cursor does. + * Note: PG cursor is INSENSITIVE (=STATIC) cursor but its + * implemenation doesn't store the result into temporary storage other + * than T-SQL does. We don't know the # of rows. So return -1 here as + * same as DYNAMIC cursor does. */ return -1; } } -static int cursor_column_count_impl(const char *curname) +static int +cursor_column_count_impl(const char *curname) { - Portal portal; + Portal portal; portal = SPI_cursor_find(curname); if (portal == NULL || portal->tupDesc == NULL) @@ -706,15 +759,15 @@ Datum cursor_list(PG_FUNCTION_ARGS) { ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; + TupleDesc tupdesc; Tuplestorestate *tupstore; MemoryContext per_query_ctx; MemoryContext oldcontext; CursorHashEnt *hentry; HASH_SEQ_STATUS hash_seq; PLtsql_execstate *estate; - int cursor_scope_required; - int i; + int cursor_scope_required; + int i; cursor_scope_required = PG_GETARG_INT32(0); if (cursor_scope_required < 1 || cursor_scope_required > 3) @@ -771,7 +824,10 @@ cursor_list(PG_FUNCTION_ARGS) TupleDescInitEntry(tupdesc, (AttrNumber) 14, "cursor_handle", INT4OID, -1, 0); - /* Hidden attributes used in sp_describe_cursor. Will not be projected to user. */ + /* + * Hidden attributes used in sp_describe_cursor. Will not be projected to + * user. + */ TupleDescInitEntry(tupdesc, (AttrNumber) 15, "cursor_source", INT2OID, -1, 0); @@ -798,24 +854,26 @@ cursor_list(PG_FUNCTION_ARGS) if (estate->datums[i]->dtype == PLTSQL_DTYPE_VAR) { PLtsql_var *var = (PLtsql_var *) estate->datums[i]; + if (is_cursor_datatype(var->datatype->typoid) - && !var->isnull - && !(var->cursor_options & PGTSQL_CURSOR_ANONYMOUS)) + && !var->isnull + && !(var->cursor_options & PGTSQL_CURSOR_ANONYMOUS)) { - char *curname; + char *curname; Datum values[15]; bool nulls[15]; - int cursor_scope; + int cursor_scope; MemSet(nulls, 0, sizeof(nulls)); curname = TextDatumGetCString(var->value); hentry = (CursorHashEnt *) hash_search(CursorHashTable, curname, HASH_FIND, NULL); - if (hentry == NULL) /* This can happen for PG internal cursor. skip it */ + if (hentry == NULL) /* This can happen for PG internal cursor. + * skip it */ continue; - cursor_scope = 1; /* cursor_scope: always LOCAL for now */ + cursor_scope = 1; /* cursor_scope: always LOCAL for now */ if (!(cursor_scope & cursor_scope_required)) continue; @@ -824,8 +882,8 @@ cursor_list(PG_FUNCTION_ARGS) values[1] = CStringGetTextDatum(pltsql_demangle_curname(curname)); values[2] = cursor_scope; values[3] = cursor_status_impl(var); - values[4] = 1; /* model: always STATIC for now */ - values[5] = 1; /* concurreny: always READ_ONLY for now */ + values[4] = 1; /* model: always STATIC for now */ + values[5] = 1; /* concurreny: always READ_ONLY for now */ values[6] = (var->cursor_options & CURSOR_OPT_NO_SCROLL) ? 0 : 1; values[7] = (SPI_cursor_find(curname) == NULL) ? 0 : 1; /* open status */ values[8] = cursor_rows_impl(curname); @@ -834,7 +892,7 @@ cursor_list(PG_FUNCTION_ARGS) values[11] = hentry->row_count; values[12] = hentry->last_operation; values[13] = hentry->cursor_handle; /* cursor handle */ - values[14] = var->isconst ? values[2] : 3; /* cursor source */ + values[14] = var->isconst ? values[2] : 3; /* cursor source */ tuplestore_putvalues(tupstore, tupdesc, values, nulls); } @@ -846,13 +904,13 @@ cursor_list(PG_FUNCTION_ARGS) while ((hentry = hash_seq_search(&hash_seq)) != NULL) { - Datum values[15]; - bool nulls[15]; - int cursor_scope; + Datum values[15]; + bool nulls[15]; + int cursor_scope; MemSet(nulls, 0, sizeof(nulls)); - cursor_scope = 2; /* cursor_scope: always GLOBAL for api cursor */ + cursor_scope = 2; /* cursor_scope: always GLOBAL for api cursor */ if (!(cursor_scope & cursor_scope_required)) continue; @@ -860,12 +918,14 @@ cursor_list(PG_FUNCTION_ARGS) if (!hentry->api_cursor) continue; - values[0] = CStringGetTextDatum("NULL"); /* reference name */ - values[1] = CStringGetTextDatum("NULL"); /* cursor name. TODO: handle renaming via sp_cursoroption */ + values[0] = CStringGetTextDatum("NULL"); /* reference name */ + values[1] = CStringGetTextDatum("NULL"); /* cursor name. TODO: + * handle renaming via + * sp_cursoroption */ values[2] = cursor_scope; values[3] = cursor_status_impl2(hentry->curname); - values[4] = 1; /* model: always STATIC for now */ - values[5] = 1; /* concurreny: always READ_ONLY for now */ + values[4] = 1; /* model: always STATIC for now */ + values[5] = 1; /* concurreny: always READ_ONLY for now */ values[6] = (hentry->cursor_options & CURSOR_OPT_NO_SCROLL) ? 0 : 1; values[7] = (SPI_cursor_find(hentry->curname) == NULL) ? 0 : 1; /* open status */ values[8] = cursor_rows_impl(hentry->curname); @@ -874,7 +934,7 @@ cursor_list(PG_FUNCTION_ARGS) values[11] = hentry->row_count; values[12] = hentry->last_operation; values[13] = hentry->cursor_handle; /* cursor handle */ - values[14] = cursor_scope; /* cursor source */ + values[14] = cursor_scope; /* cursor source */ tuplestore_putvalues(tupstore, tupdesc, values, nulls); } @@ -927,9 +987,12 @@ init_tsql_cursor_hash_tab(PG_FUNCTION_ARGS) #define SP_CURSOR_SCROLLOPT_FAST_FORWARD_ACCEPTABLE 0x100000 #define SP_CURSOR_CCOPT_READ_ONLY 0x0001 -#define SP_CURSOR_CCOPT_SCROLL_LOCKS 0x0002 /* previously known as LOCKCC */ -#define SP_CURSOR_CCOPT_OPTIMISTIC1 0x0004 /* previously known as OPTCC */ -#define SP_CURSOR_CCOPT_OPTIMISTIC2 0x0008 /* previously known as OPTCCVAL */ +#define SP_CURSOR_CCOPT_SCROLL_LOCKS 0x0002 /* previously known as + * LOCKCC */ +#define SP_CURSOR_CCOPT_OPTIMISTIC1 0x0004 /* previously known as + * OPTCC */ +#define SP_CURSOR_CCOPT_OPTIMISTIC2 0x0008 /* previously known as + * OPTCCVAL */ #define SP_CURSOR_CCOPT_ALLOW_DIRECT 0x2000 #define SP_CURSOR_CCOPT_UPDT_IN_PLACE 0x4000 #define SP_CURSOR_CCOPT_CHECK_ACCEPTED_OPTS 0x8000 @@ -957,17 +1020,21 @@ init_tsql_cursor_hash_tab(PG_FUNCTION_ARGS) #define SP_CURSOR_OPTION_CODE_ROWCOUNT 0x6 -int execute_sp_cursor(int cursor_handle, int opttype, int rownum, const char *tablename, List* values) +int +execute_sp_cursor(int cursor_handle, int opttype, int rownum, const char *tablename, List *values) { - int rc; - char curname[NAMEDATALEN]; + int rc; + char curname[NAMEDATALEN]; CursorHashEnt *hentry; - Portal portal; + Portal portal; DestReceiver *receiver; TupleTableSlot *slot; MemoryContext savedPortalCxt; - /* Connect to SPI manager. should be handled in the same way with pltsql_inline_handler() */ + /* + * Connect to SPI manager. should be handled in the same way with + * pltsql_inline_handler() + */ savedPortalCxt = PortalContext; if (PortalContext == NULL) PortalContext = MessageContext; @@ -1006,41 +1073,50 @@ int execute_sp_cursor(int cursor_handle, int opttype, int rownum, const char *ta return 0; } -int execute_sp_cursoropen(int *cursor_handle, const char *stmt, int *pscrollopt, int *pccopt, int *row_count, int nparams, int nBindParams, Oid *boundParamsOidList, Datum *values, const char *nulls) +int +execute_sp_cursoropen(int *cursor_handle, const char *stmt, int *pscrollopt, int *pccopt, int *row_count, int nparams, int nBindParams, Oid *boundParamsOidList, Datum *values, const char *nulls) { - return execute_sp_cursoropen_common(NULL, cursor_handle, stmt, pscrollopt, pccopt, row_count, nparams, nBindParams, boundParamsOidList, values, nulls, true/*prepare*/, false/*save_plan*/, true/*execute*/); + return execute_sp_cursoropen_common(NULL, cursor_handle, stmt, pscrollopt, pccopt, row_count, nparams, nBindParams, boundParamsOidList, values, nulls, true /* prepare */ , false /* save_plan */ , true /* execute */ ); } /* old interface to be compatabile with TDS */ -int execute_sp_cursoropen_old(int *cursor_handle, const char *stmt, int *pscrollopt, int *pccopt, int *row_count, int nparams, Datum *values, const char *nulls) +int +execute_sp_cursoropen_old(int *cursor_handle, const char *stmt, int *pscrollopt, int *pccopt, int *row_count, int nparams, Datum *values, const char *nulls) { - return execute_sp_cursoropen_common(NULL, cursor_handle, stmt, pscrollopt, pccopt, row_count, nparams, 0, NULL, values, nulls, true/*prepare*/, false/*save_plan*/, true/*execute*/); + return execute_sp_cursoropen_common(NULL, cursor_handle, stmt, pscrollopt, pccopt, row_count, nparams, 0, NULL, values, nulls, true /* prepare */ , false /* save_plan */ , true /* execute */ ); } -int execute_sp_cursorprepare(int *stmt_handle, const char *stmt, int options, int *pscrollopt, int *pccopt, int nBindParams, Oid *boundParamsOidList) +int +execute_sp_cursorprepare(int *stmt_handle, const char *stmt, int options, int *pscrollopt, int *pccopt, int nBindParams, Oid *boundParamsOidList) { /* TODO: options handling */ - return execute_sp_cursoropen_common(stmt_handle, NULL, stmt, pscrollopt, pccopt, NULL, 0, nBindParams, boundParamsOidList, NULL, NULL, true/*prepare*/, true/*save_plan*/, false/*execute*/); + return execute_sp_cursoropen_common(stmt_handle, NULL, stmt, pscrollopt, pccopt, NULL, 0, nBindParams, boundParamsOidList, NULL, NULL, true /* prepare */ , true /* save_plan */ , false /* execute */ ); } -int execute_sp_cursorexecute(int stmt_handle, int *cursor_handle, int *pscrollopt, int *pccopt, int *rowcount, int nparams, Datum *values, const char *nulls) +int +execute_sp_cursorexecute(int stmt_handle, int *cursor_handle, int *pscrollopt, int *pccopt, int *rowcount, int nparams, Datum *values, const char *nulls) { - return execute_sp_cursoropen_common(&stmt_handle, cursor_handle, NULL, pscrollopt, pccopt, rowcount, nparams, 0, NULL, values, nulls, false/*prepare*/, false/*save_plan*/, true/*execute*/); + return execute_sp_cursoropen_common(&stmt_handle, cursor_handle, NULL, pscrollopt, pccopt, rowcount, nparams, 0, NULL, values, nulls, false /* prepare */ , false /* save_plan */ , true /* execute */ ); } -int execute_sp_cursorprepexec(int *stmt_handle, int *cursor_handle, const char *stmt, int options, int *pscrollopt, int *pccopt, int *row_count, int nparams, int nBindParams, Oid *boundParamsOidList, Datum *values, const char *nulls) +int +execute_sp_cursorprepexec(int *stmt_handle, int *cursor_handle, const char *stmt, int options, int *pscrollopt, int *pccopt, int *row_count, int nparams, int nBindParams, Oid *boundParamsOidList, Datum *values, const char *nulls) { - return execute_sp_cursoropen_common(stmt_handle, cursor_handle, stmt, pscrollopt, pccopt, row_count, nparams, nBindParams, boundParamsOidList, values, nulls, true/*prepare*/, true/*save_plan*/, true/*execute*/); + return execute_sp_cursoropen_common(stmt_handle, cursor_handle, stmt, pscrollopt, pccopt, row_count, nparams, nBindParams, boundParamsOidList, values, nulls, true /* prepare */ , true /* save_plan */ , true /* execute */ ); } -int execute_sp_cursorunprepare(int stmt_handle) +int +execute_sp_cursorunprepare(int stmt_handle) { - int rc; + int rc; MemoryContext savedPortalCxt; CurosrPreparedHandleHashEnt *phentry; - bool found; + bool found; - /* Connect to SPI manager. should be handled in the same way with pltsql_inline_handler() */ + /* + * Connect to SPI manager. should be handled in the same way with + * pltsql_inline_handler() + */ savedPortalCxt = PortalContext; if (PortalContext == NULL) PortalContext = MessageContext; @@ -1055,7 +1131,7 @@ int execute_sp_cursorunprepare(int stmt_handle) if (phentry->plan) { SPI_freeplan(phentry->plan); - phentry->plan= NULL; + phentry->plan = NULL; } hash_search(CursorPreparedHandleHashTable, &stmt_handle, HASH_REMOVE, &found); @@ -1067,22 +1143,26 @@ int execute_sp_cursorunprepare(int stmt_handle) return 0; } -int execute_sp_cursorfetch(int cursor_handle, int *pfetchtype, int *prownum, int *pnrows) +int +execute_sp_cursorfetch(int cursor_handle, int *pfetchtype, int *prownum, int *pnrows) { - int rc; - char curname[NAMEDATALEN]; + int rc; + char curname[NAMEDATALEN]; CursorHashEnt *hentry; - Portal portal; - int fetchtype; - int rownum; - int nrows; + Portal portal; + int fetchtype; + int rownum; + int nrows; DestReceiver *receiver; TupleTableSlot *slot; - int rno; + int rno; MemoryContext oldcontext; MemoryContext savedPortalCxt; - /* Connect to SPI manager. should be handled in the same way with pltsql_inline_handler() */ + /* + * Connect to SPI manager. should be handled in the same way with + * pltsql_inline_handler() + */ savedPortalCxt = PortalContext; if (PortalContext == NULL) PortalContext = MessageContext; @@ -1156,7 +1236,11 @@ int execute_sp_cursorfetch(int cursor_handle, int *pfetchtype, int *prownum, int if (SPI_result != 0) elog(ERROR, "error in SPI_scroll_cursor_fetch: %d", SPI_result); - /* In case of FETCH_FIRST/FETCH_LAST with 0 nrows, we just moved cursor and no actual fetch is called. SPI_tuptable can be NULL. skip storing the result */ + /* + * In case of FETCH_FIRST/FETCH_LAST with 0 nrows, we just moved cursor + * and no actual fetch is called. SPI_tuptable can be NULL. skip storing + * the result + */ if (SPI_tuptable) { /* store result in fetch buffer */ @@ -1187,7 +1271,7 @@ int execute_sp_cursorfetch(int cursor_handle, int *pfetchtype, int *prownum, int /* If AUTO_CLOSE is set and we fetched all the result, close the cursor */ if ((hentry->cursor_options & TSQL_CURSOR_OPT_AUTO_CLOSE) && - portal->atEnd) + portal->atEnd) { execute_sp_cursorclose(cursor_handle); } @@ -1200,16 +1284,20 @@ int execute_sp_cursorfetch(int cursor_handle, int *pfetchtype, int *prownum, int #define BITMAPSIZE(natts) (((natts-1)/8)+1) -int execute_sp_cursoroption(int cursor_handle, int code, int value) +int +execute_sp_cursoroption(int cursor_handle, int code, int value) { - int rc; - char curname[NAMEDATALEN]; + int rc; + char curname[NAMEDATALEN]; CursorHashEnt *hentry; - Portal portal; + Portal portal; MemoryContext oldcontext; MemoryContext savedPortalCxt; - /* Connect to SPI manager. should be handled in the same way with pltsql_inline_handler() */ + /* + * Connect to SPI manager. should be handled in the same way with + * pltsql_inline_handler() + */ savedPortalCxt = PortalContext; if (PortalContext == NULL) PortalContext = MessageContext; @@ -1233,49 +1321,51 @@ int execute_sp_cursoroption(int cursor_handle, int code, int value) switch (code) { case SP_CURSOR_OPTION_CODE_TEXTPTR_ONLY: - { - if (hentry->textptr_only_bitmap == NULL) { - oldcontext = MemoryContextSwitchTo(CursorHashtabContext); - hentry->textptr_only_bitmap = (char *) palloc0(BITMAPSIZE(portal->tupDesc->natts)); - MemoryContextSwitchTo(oldcontext); - } + if (hentry->textptr_only_bitmap == NULL) + { + oldcontext = MemoryContextSwitchTo(CursorHashtabContext); + hentry->textptr_only_bitmap = (char *) palloc0(BITMAPSIZE(portal->tupDesc->natts)); + MemoryContextSwitchTo(oldcontext); + } - if (value == 0) /* ALL */ - { - memset(hentry->textptr_only_bitmap, 0xff, BITMAPSIZE(portal->tupDesc->natts)); - } - else if (value > 0 && value <= portal->tupDesc->natts) - { - int idx = value-1; - hentry->textptr_only_bitmap[idx/8] |= (0x1 << (idx & 7)); + if (value == 0) /* ALL */ + { + memset(hentry->textptr_only_bitmap, 0xff, BITMAPSIZE(portal->tupDesc->natts)); + } + else if (value > 0 && value <= portal->tupDesc->natts) + { + int idx = value - 1; + + hentry->textptr_only_bitmap[idx / 8] |= (0x1 << (idx & 7)); + } + else + elog(ERROR, "cursoroption value %d is out of range", value); + break; } - else - elog(ERROR, "cursoroption value %d is out of range", value); - break; - } case SP_CURSOR_OPTION_CODE_TEXTDATA: - { - if (hentry->textptr_only_bitmap == NULL) { - oldcontext = MemoryContextSwitchTo(CursorHashtabContext); - hentry->textptr_only_bitmap = (char *) palloc0(BITMAPSIZE(portal->tupDesc->natts)); - MemoryContextSwitchTo(oldcontext); - } + if (hentry->textptr_only_bitmap == NULL) + { + oldcontext = MemoryContextSwitchTo(CursorHashtabContext); + hentry->textptr_only_bitmap = (char *) palloc0(BITMAPSIZE(portal->tupDesc->natts)); + MemoryContextSwitchTo(oldcontext); + } - if (value == 0) /* ALL */ - { - memset(hentry->textptr_only_bitmap, 0x00, BITMAPSIZE(portal->tupDesc->natts)); - } - else if (value > 0 && value <= portal->tupDesc->natts) - { - int idx = value-1; - hentry->textptr_only_bitmap[idx/8] &= ~(0x1 << (idx & 7)); + if (value == 0) /* ALL */ + { + memset(hentry->textptr_only_bitmap, 0x00, BITMAPSIZE(portal->tupDesc->natts)); + } + else if (value > 0 && value <= portal->tupDesc->natts) + { + int idx = value - 1; + + hentry->textptr_only_bitmap[idx / 8] &= ~(0x1 << (idx & 7)); + } + else + elog(ERROR, "cursoroption value %d is out of range", value); + break; } - else - elog(ERROR, "cursoroption value %d is out of range", value); - break; - } default: Assert(0); } @@ -1286,21 +1376,26 @@ int execute_sp_cursoroption(int cursor_handle, int code, int value) return 0; } -int execute_sp_cursoroption2(int cursor_handle, int code, const char *value) +int +execute_sp_cursoroption2(int cursor_handle, int code, const char *value) { /* TODO: handled along with updable cursor */ return 0; } -int execute_sp_cursorclose(int cursor_handle) +int +execute_sp_cursorclose(int cursor_handle) { - int rc; - char curname[NAMEDATALEN]; + int rc; + char curname[NAMEDATALEN]; CursorHashEnt *hentry; - Portal portal; + Portal portal; MemoryContext savedPortalCxt; - /* Connect to SPI manager. should be handled in the same way with pltsql_inline_handler() */ + /* + * Connect to SPI manager. should be handled in the same way with + * pltsql_inline_handler() + */ savedPortalCxt = PortalContext; if (PortalContext == NULL) PortalContext = MessageContext; @@ -1341,21 +1436,24 @@ int execute_sp_cursorclose(int cursor_handle) * sp_cursorprepexec: prepare + save_plan + exectue */ static int -execute_sp_cursoropen_common(int* stmt_handle, int *cursor_handle, const char *stmt, int *pscrollopt, int *pccopt, int *row_count, int nparams, int nBindParams, Oid *boundParamsOidList, Datum *values, const char *nulls, bool prepare, bool save_plan, bool execute) +execute_sp_cursoropen_common(int *stmt_handle, int *cursor_handle, const char *stmt, int *pscrollopt, int *pccopt, int *row_count, int nparams, int nBindParams, Oid *boundParamsOidList, Datum *values, const char *nulls, bool prepare, bool save_plan, bool execute) { - int rc; - int scrollopt; - int ccopt; - int cursor_options; - bool found; - SPIPlanPtr plan; + int rc; + int scrollopt; + int ccopt; + int cursor_options; + bool found; + SPIPlanPtr plan; CurosrPreparedHandleHashEnt *phentry; CursorHashEnt *hentry; - Portal portal; + Portal portal; MemoryContext oldcontext; MemoryContext savedPortalCxt; - /* Connect to SPI manager. should be handled in the same way with pltsql_inline_handler() */ + /* + * Connect to SPI manager. should be handled in the same way with + * pltsql_inline_handler() + */ savedPortalCxt = PortalContext; if (PortalContext == NULL) PortalContext = MessageContext; @@ -1373,13 +1471,14 @@ execute_sp_cursoropen_common(int* stmt_handle, int *cursor_handle, const char *s /* prepare plan and insert a cursor entry */ plan = SPI_prepare_cursor(stmt, nBindParams, boundParamsOidList, cursor_options); if (plan == NULL) - return 1; /* procedure failed */ + return 1; /* procedure failed */ if (save_plan) { *stmt_handle = get_next_cursor_prepared_handle(); phentry = (CurosrPreparedHandleHashEnt *) hash_search(CursorPreparedHandleHashTable, stmt_handle, HASH_ENTER, &found); - Assert(!found); /* already checked in get_next_cursor_prepared_handle() */ + Assert(!found); /* already checked in + * get_next_cursor_prepared_handle() */ phentry->handle = *stmt_handle; phentry->plan = plan; @@ -1388,7 +1487,7 @@ execute_sp_cursoropen_common(int* stmt_handle, int *cursor_handle, const char *s SPI_keepplan(plan); } } - else /* !prepare */ + else /* !prepare */ { phentry = (CurosrPreparedHandleHashEnt *) hash_search(CursorPreparedHandleHashTable, stmt_handle, HASH_FIND, NULL); if (phentry == NULL) @@ -1404,13 +1503,13 @@ execute_sp_cursoropen_common(int* stmt_handle, int *cursor_handle, const char *s if (execute) { - bool read_only; - char curname[NAMEDATALEN]; - bool snapshot_pushed = false; + bool read_only; + char curname[NAMEDATALEN]; + bool snapshot_pushed = false; if (SPI_getargcount(plan) != nparams) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("the numeber of arguments in plan mismatches with inputs"))); + errmsg("the numeber of arguments in plan mismatches with inputs"))); read_only = (cursor_options & TSQL_CURSOR_OPT_READ_ONLY); @@ -1428,8 +1527,10 @@ execute_sp_cursoropen_common(int* stmt_handle, int *cursor_handle, const char *s if (read_only && !ActiveSnapshotSet()) { /* - * Other than SPI_execute, SPI_cursor_open expects there is already an active snapshot in read-only mode. - * If sp_cursoropen is used in SQL batch, there maybe no active snapshot because we don't use normal PG path. + * Other than SPI_execute, SPI_cursor_open expects there is + * already an active snapshot in read-only mode. If + * sp_cursoropen is used in SQL batch, there maybe no active + * snapshot because we don't use normal PG path. */ PushActiveSnapshot(GetTransactionSnapshot()); snapshot_pushed = true; @@ -1445,7 +1546,8 @@ execute_sp_cursoropen_common(int* stmt_handle, int *cursor_handle, const char *s /* * row_count can be ignored if AUTO_FETCH is not specified. - * Currently we don't support AUTO_FETCH so we do not need to handle row_count + * Currently we don't support AUTO_FETCH so we do not need to + * handle row_count */ Assert(row_count == NULL || (scrollopt & SP_CURSOR_SCROLLOPT_AUTO_FETCH) == 0); } @@ -1473,17 +1575,18 @@ execute_sp_cursoropen_common(int* stmt_handle, int *cursor_handle, const char *s if ((rc = SPI_finish()) != SPI_OK_FINISH) elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc)); - return 0; // success + return 0; + /* success */ } static int validate_and_get_sp_cursoropen_params(int scrollopt, int ccopt) { - int curoptions = 0; + int curoptions = 0; /* - * As of now, only READ ONLY cursors are supported. Scroll locks, optimistic - * and update-in-place cursors are not yet supported. + * As of now, only READ ONLY cursors are supported. Scroll locks, + * optimistic and update-in-place cursors are not yet supported. */ if ((ccopt & SP_CURSOR_CCOPT_READ_ONLY) == 0) { @@ -1497,9 +1600,10 @@ validate_and_get_sp_cursoropen_params(int scrollopt, int ccopt) curoptions |= TSQL_CURSOR_OPT_READ_ONLY; - /* Also, allow-direct cursors are not supported, but we'll allow it to be - * executed as normal cursor. So, clear the flag unconditionally so that we - * can send the correct scrollopt OUT parameter value. + /* + * Also, allow-direct cursors are not supported, but we'll allow it to be + * executed as normal cursor. So, clear the flag unconditionally so that + * we can send the correct scrollopt OUT parameter value. */ scrollopt &= ~SP_CURSOR_CCOPT_ALLOW_DIRECT; @@ -1515,10 +1619,10 @@ validate_and_get_sp_cursoropen_params(int scrollopt, int ccopt) /* TODO: cursor sensitivity option handling */ /* - * We're always going to fetch in binary format. - * Also, cursor opened via sp_cursoropen is global. - * We will set OPT_HOLD to make the portal accessible even if transaction is committed. - * Portal should be released via sp_cursorclose() + * We're always going to fetch in binary format. Also, cursor opened via + * sp_cursoropen is global. We will set OPT_HOLD to make the portal + * accessible even if transaction is committed. Portal should be released + * via sp_cursorclose() */ curoptions = CURSOR_OPT_BINARY | CURSOR_OPT_HOLD; @@ -1527,7 +1631,7 @@ validate_and_get_sp_cursoropen_params(int scrollopt, int ccopt) curoptions |= CURSOR_OPT_NO_SCROLL; } else if ((ccopt & SP_CURSOR_SCROLLOPT_CHECK_ACCEPTED_TYPES) && - (ccopt & SP_CURSOR_SCROLLOPT_FORWARD_ONLY_ACCEPTABLE)) + (ccopt & SP_CURSOR_SCROLLOPT_FORWARD_ONLY_ACCEPTABLE)) { curoptions |= CURSOR_OPT_NO_SCROLL; } @@ -1577,11 +1681,13 @@ validate_and_get_sp_cursorfetch_params(int *fetchtype_in, int *rownum_in, int *n case SP_CURSOR_FETCH_LAST: case SP_CURSOR_FETCH_ABSOLUTE: break; - /* - * The following cursor options are not supported in postgres. Although - * postgres supports the relative cursor fetch option, but the behaviour - * in TDS protocol is very different from postgres. - */ + + /* + * The following cursor options are not supported in postgres. + * Although postgres supports the relative cursor fetch + * option, but the behaviour in TDS protocol is very different + * from postgres. + */ case SP_CURSOR_FETCH_RELATIVE: case SP_CURSOR_FETCH_REFRESH: case SP_CURSOR_FETCH_INFO: @@ -1605,13 +1711,13 @@ validate_and_get_sp_cursorfetch_params(int *fetchtype_in, int *rownum_in, int *n if (rownum_in != NULL) { /* - * Rownum is used to specify the row position for the ABSOLUTE and INFO - * fetchtype. And, it serves as the row offset for the fetchtype bit - * value RELATIVE. It is ignored for all other values. + * Rownum is used to specify the row position for the ABSOLUTE and + * INFO fetchtype. And, it serves as the row offset for the fetchtype + * bit value RELATIVE. It is ignored for all other values. */ if (*fetchtype_in != SP_CURSOR_FETCH_ABSOLUTE && - *fetchtype_in != SP_CURSOR_FETCH_RELATIVE && - *fetchtype_in != SP_CURSOR_FETCH_INFO) + *fetchtype_in != SP_CURSOR_FETCH_RELATIVE && + *fetchtype_in != SP_CURSOR_FETCH_INFO) *rownum_out = -1; else *rownum_out = *rownum_in; @@ -1631,10 +1737,10 @@ validate_and_get_sp_cursorfetch_params(int *fetchtype_in, int *rownum_in, int *n if (*nrows_in == 0) { if (*fetchtype_in == SP_CURSOR_FETCH_NEXT || - *fetchtype_in == SP_CURSOR_FETCH_PREV || - *fetchtype_in == SP_CURSOR_FETCH_ABSOLUTE || - *fetchtype_in == SP_CURSOR_FETCH_RELATIVE || - *fetchtype_in == SP_CURSOR_FETCH_PREV_NOADJUST) + *fetchtype_in == SP_CURSOR_FETCH_PREV || + *fetchtype_in == SP_CURSOR_FETCH_ABSOLUTE || + *fetchtype_in == SP_CURSOR_FETCH_RELATIVE || + *fetchtype_in == SP_CURSOR_FETCH_PREV_NOADJUST) elog(ERROR, "invalid nrow value 0 for cursor type %X", *fetchtype_in); } @@ -1647,29 +1753,33 @@ validate_and_get_sp_cursorfetch_params(int *fetchtype_in, int *rownum_in, int *n } } -static void validate_sp_cursoroption_params(int code, int value) +static void +validate_sp_cursoroption_params(int code, int value) { if ((code == SP_CURSOR_OPTION_CODE_SCROLLOPT) || - (code == SP_CURSOR_OPTION_CODE_CCOPT) || - (code == SP_CURSOR_OPTION_CODE_ROWCOUNT)) + (code == SP_CURSOR_OPTION_CODE_CCOPT) || + (code == SP_CURSOR_OPTION_CODE_ROWCOUNT)) elog(ERROR, "cursoroption code %X not supported", code); } Datum pltsql_cursor_show_textptr_only_column_indexes(PG_FUNCTION_ARGS) { - uint32 cursor_handle; - char curname[NAMEDATALEN]; + uint32 cursor_handle; + char curname[NAMEDATALEN]; CursorHashEnt *hentry; - Portal portal; + Portal portal; StringInfoData buffer; - int i, j, k; + int i, + j, + k; cursor_handle = PG_GETARG_INT32(0); snprintf(curname, NAMEDATALEN, "%u", cursor_handle); hentry = (CursorHashEnt *) hash_search(CursorHashTable, curname, HASH_FIND, NULL); - if (hentry == NULL) { + if (hentry == NULL) + { elog(ERROR, "cursor_handle %u does not exist", cursor_handle); } @@ -1686,7 +1796,7 @@ pltsql_cursor_show_textptr_only_column_indexes(PG_FUNCTION_ARGS) k = 1; initStringInfo(&buffer); - for (i = 0; itupDesc->natts); ++i) + for (i = 0; i < BITMAPSIZE(portal->tupDesc->natts); ++i) { for (j = 0; j < 8; ++j, k++) { diff --git a/contrib/babelfishpg_tsql/src/databasepropertyex.c b/contrib/babelfishpg_tsql/src/databasepropertyex.c index ab9cd24748..a12c65dd9f 100644 --- a/contrib/babelfishpg_tsql/src/databasepropertyex.c +++ b/contrib/babelfishpg_tsql/src/databasepropertyex.c @@ -20,13 +20,16 @@ PG_FUNCTION_INFO_V1(databasepropertyex); -Datum databasepropertyex(PG_FUNCTION_ARGS) { - VarChar *vch = NULL; - int64_t intVal = 0; +Datum +databasepropertyex(PG_FUNCTION_ARGS) +{ + VarChar *vch = NULL; + int64_t intVal = 0; const char *dbname = text_to_cstring(PG_GETARG_TEXT_P(0)); const char *property = text_to_cstring(PG_GETARG_TEXT_P(1)); - Oid dboid = get_db_id(dbname); - if(dboid == InvalidOid) + Oid dboid = get_db_id(dbname); + + if (dboid == InvalidOid) { PG_RETURN_NULL(); } @@ -34,20 +37,22 @@ Datum databasepropertyex(PG_FUNCTION_ARGS) { if (strcasecmp(property, "Collation") == 0) { const char *server_collation_name = GetConfigOption("babelfishpg_tsql.server_collation_name", false, false); + if (server_collation_name) - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(server_collation_name, strlen(server_collation_name), -1); + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (server_collation_name, strlen(server_collation_name), -1); } else if (strcasecmp(property, "ComparisonStyle") == 0) { - // TOOD:[BABEL-1015] + /* TOOD:[BABEL-1015] */ intVal = 0; } else if (strcasecmp(property, "Edition") == 0) { const char *ret = "Standard"; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); } - //TODO[BABEL-247] + /* TODO[BABEL-247] */ else if (strcasecmp(property, "IsAnsiNullDefault") == 0) { intVal = 0; @@ -102,7 +107,7 @@ Datum databasepropertyex(PG_FUNCTION_ARGS) { } else if (strcasecmp(property, "IsInStandBy") == 0) { - if(RecoveryInProgress()) + if (RecoveryInProgress()) intVal = 1; else intVal = 0; @@ -129,7 +134,7 @@ Datum databasepropertyex(PG_FUNCTION_ARGS) { } else if (strcasecmp(property, "IsQuotedIdentifiersEnabled") == 0) { - //TODO:[BABEL-245] + /* TODO:[BABEL-245] */ intVal = 0; } else if (strcasecmp(property, "IsPublished") == 0) @@ -150,7 +155,7 @@ Datum databasepropertyex(PG_FUNCTION_ARGS) { } else if (strcasecmp(property, "IsTornPageDetectionEnabled") == 0) { - if(fullPageWrites) + if (fullPageWrites) intVal = 1; else intVal = 0; @@ -194,12 +199,14 @@ Datum databasepropertyex(PG_FUNCTION_ARGS) { else if (strcasecmp(property, "Status") == 0) { const char *ret = "ONLINE"; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); } else if (strcasecmp(property, "Updateability") == 0) { const char *ret = "READ_WRITE"; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); } else if (strcasecmp(property, "UserAccess") == 0) { @@ -208,7 +215,8 @@ Datum databasepropertyex(PG_FUNCTION_ARGS) { else if (strcasecmp(property, "Version") == 0) { const char *ret = PG_VERSION; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); } else { @@ -216,10 +224,12 @@ Datum databasepropertyex(PG_FUNCTION_ARGS) { PG_RETURN_NULL(); } - if (vch != NULL) { - PG_RETURN_BYTEA_P((*common_utility_plugin_ptr->convertVarcharToSQLVariantByteA)(vch, PG_GET_COLLATION())); - } else { - PG_RETURN_BYTEA_P((*common_utility_plugin_ptr->convertIntToSQLVariantByteA)(intVal)); + if (vch != NULL) + { + PG_RETURN_BYTEA_P((*common_utility_plugin_ptr->convertVarcharToSQLVariantByteA) (vch, PG_GET_COLLATION())); + } + else + { + PG_RETURN_BYTEA_P((*common_utility_plugin_ptr->convertIntToSQLVariantByteA) (intVal)); } } - diff --git a/contrib/babelfishpg_tsql/src/datatype_info.h b/contrib/babelfishpg_tsql/src/datatype_info.h index 7be652a6f9..9d1b5c40af 100644 --- a/contrib/babelfishpg_tsql/src/datatype_info.h +++ b/contrib/babelfishpg_tsql/src/datatype_info.h @@ -6,34 +6,35 @@ #define DATATYPE_INFO_TABLE_ROWS 37 -typedef struct DatatypeInfo { +typedef struct DatatypeInfo +{ const char *type_name; /* data_type is OdbcVer and procedure dependent */ - int data_type_2; - int data_type_3; - int data_type_2_100; - int data_type_3_100; - uint64 precision; + int data_type_2; + int data_type_3; + int data_type_2_100; + int data_type_3_100; + uint64 precision; const char *literal_prefix; const char *literal_suffix; const char *create_params; - int nullable; - int case_sensitive; - int searchable; - int unsigned_attribute; - int money; - int auto_increment; + int nullable; + int case_sensitive; + int searchable; + int unsigned_attribute; + int money; + int auto_increment; const char *local_type_name; - int minimum_scale; - int maximum_scale; - int sql_data_type; - int sql_datetime_sub; - int num_prec_radix; - int interval_precision; - int usertype; - int length; - int ss_data_type; + int minimum_scale; + int maximum_scale; + int sql_data_type; + int sql_datetime_sub; + int num_prec_radix; + int interval_precision; + int usertype; + int length; + int ss_data_type; const char *pg_type_name; } DatatypeInfo; @@ -45,448 +46,448 @@ typedef struct DatatypeInfo { static const DatatypeInfo datatype_info_table[DATATYPE_INFO_TABLE_ROWS] = { { "datetimeoffset", - -9, -9, -155, -155, + -9, -9, -155, -155, 34, "'", "'", "scale ", - 1, 0, 3, NULLVAL, 0, NULLVAL, + 1, 0, 3, NULLVAL, 0, NULLVAL, "datetimeoffset", - 0, 7, -155, 0, NULLVAL, NULLVAL, 0, 68, 0, + 0, 7, -155, 0, NULLVAL, NULLVAL, 0, 68, 0, "datetimeoffset" }, { "time", - -9, -9, -154, -154, + -9, -9, -154, -154, 16, "'", "'", "scale ", - 1, 0, 3, NULLVAL, 0, NULLVAL, + 1, 0, 3, NULLVAL, 0, NULLVAL, "time", - 0, 7, -154, 0, NULLVAL, NULLVAL, 0, 32, 0, + 0, 7, -154, 0, NULLVAL, NULLVAL, 0, 32, 0, "time" }, { "xml", - -10, -10, -152, -152, + -10, -10, -152, -152, 0, "N'", "'", NULLVAL_STR, - 1, 1, 0, NULLVAL, 0, NULLVAL, + 1, 1, 0, NULLVAL, 0, NULLVAL, "xml", - NULLVAL, NULLVAL, -152, NULLVAL, NULLVAL, NULLVAL, 0, 2147483646, 0, + NULLVAL, NULLVAL, -152, NULLVAL, NULLVAL, NULLVAL, 0, 2147483646, 0, "xml" }, { "sql_variant", - -150, -150, -150, -150, + -150, -150, -150, -150, 8000, NULLVAL_STR, NULLVAL_STR, NULLVAL_STR, - 1, 0, 2, NULLVAL, 0, NULLVAL, + 1, 0, 2, NULLVAL, 0, NULLVAL, "sql_variant", - 0, 0, -150, NULLVAL, 10, NULLVAL, 0, 8000, 39, + 0, 0, -150, NULLVAL, 10, NULLVAL, 0, 8000, 39, "sql_variant" }, { "uniqueidentifier", - -11, -11, -11, -11, + -11, -11, -11, -11, 36, "'", "'", NULLVAL_STR, - 1, 0, 2, NULLVAL, 0, NULLVAL, + 1, 0, 2, NULLVAL, 0, NULLVAL, "uniqueidentifier", - NULLVAL, NULLVAL, -11, NULLVAL, NULLVAL, NULLVAL, 0, 16, 37, + NULLVAL, NULLVAL, -11, NULLVAL, NULLVAL, NULLVAL, 0, 16, 37, "uniqueidentifier" }, { "ntext", - -10, -10, -10, -10, + -10, -10, -10, -10, 1073741823, "N'", "'", NULLVAL_STR, - 1, 1, 1, NULLVAL, 0, NULLVAL, + 1, 1, 1, NULLVAL, 0, NULLVAL, "ntext", - NULLVAL, NULLVAL, -10, NULLVAL, NULLVAL, NULLVAL, 0, 2147483646, 35, + NULLVAL, NULLVAL, -10, NULLVAL, NULLVAL, NULLVAL, 0, 2147483646, 35, NULLVAL_STR }, { "nvarchar", - -9, -9, -9, -9, + -9, -9, -9, -9, 4000, "N'", "'", "max length ", - 1, 1, 3, NULLVAL, 0, NULLVAL, + 1, 1, 3, NULLVAL, 0, NULLVAL, "nvarchar", - NULLVAL, NULLVAL, -9, NULLVAL, NULLVAL, NULLVAL, 0, 2, 39, + NULLVAL, NULLVAL, -9, NULLVAL, NULLVAL, NULLVAL, 0, 2, 39, NULLVAL_STR }, { "sysname", - -9, -9, -9, -9, + -9, -9, -9, -9, 128, "N'", "'", NULLVAL_STR, - 0, 1, 3, NULLVAL, 0, NULLVAL, + 0, 1, 3, NULLVAL, 0, NULLVAL, "sysname", - NULLVAL, NULLVAL, -9, NULLVAL, NULLVAL, NULLVAL, 18, 256, 39, + NULLVAL, NULLVAL, -9, NULLVAL, NULLVAL, NULLVAL, 18, 256, 39, NULLVAL_STR }, { "nchar", - -8, -8, -8, -8, + -8, -8, -8, -8, 4000, "N'", "'", "length ", - 1, 1, 3, NULLVAL, 0, NULLVAL, + 1, 1, 3, NULLVAL, 0, NULLVAL, "nchar", - NULLVAL, NULLVAL, -8, NULLVAL, NULLVAL, NULLVAL, 0, 2, 39, + NULLVAL, NULLVAL, -8, NULLVAL, NULLVAL, NULLVAL, 0, 2, 39, NULLVAL_STR }, { "bit", - -7, -7, -7, -7, + -7, -7, -7, -7, 1, NULLVAL_STR, NULLVAL_STR, NULLVAL_STR, - 1, 0, 2, NULLVAL, 0, NULLVAL, + 1, 0, 2, NULLVAL, 0, NULLVAL, "bit", - 0, 0, -7, NULLVAL, NULLVAL, NULLVAL, 16, 1, 50, + 0, 0, -7, NULLVAL, NULLVAL, NULLVAL, 16, 1, 50, "bit" }, { "tinyint", - -6, -6, -6, -6, + -6, -6, -6, -6, 3, NULLVAL_STR, NULLVAL_STR, NULLVAL_STR, - 1, 0, 2, 1, 0, 0, + 1, 0, 2, 1, 0, 0, "tinyint", - 0, 0, -6, NULLVAL, 10, NULLVAL, 5, 1, 38, + 0, 0, -6, NULLVAL, 10, NULLVAL, 5, 1, 38, NULLVAL_STR }, { "tinyint identity", - -6, -6, -6, -6, + -6, -6, -6, -6, 3, NULLVAL_STR, NULLVAL_STR, NULLVAL_STR, - 0, 0, 2, 1, 0, 1, + 0, 0, 2, 1, 0, 1, "tinyint identity", - 0, 0, -6, NULLVAL, 10, NULLVAL, 5, 1, 38, + 0, 0, -6, NULLVAL, 10, NULLVAL, 5, 1, 38, NULLVAL_STR }, { "bigint", - -5, -5, -5, -5, + -5, -5, -5, -5, 19, NULLVAL_STR, NULLVAL_STR, NULLVAL_STR, - 1, 0, 2, 0, 0, 0, + 1, 0, 2, 0, 0, 0, "bigint", - 0, 0, -5, NULLVAL, 10, NULLVAL, 0, 8, 108, + 0, 0, -5, NULLVAL, 10, NULLVAL, 0, 8, 108, "int8" }, { "bigint identity", - -5, -5, -5, -5, + -5, -5, -5, -5, 19, NULLVAL_STR, NULLVAL_STR, NULLVAL_STR, - 0, 0, 2, 0, 0, 1, + 0, 0, 2, 0, 0, 1, "bigint identity", - 0, 0, -5, NULLVAL, 10, NULLVAL, 0, 8, 108, + 0, 0, -5, NULLVAL, 10, NULLVAL, 0, 8, 108, NULLVAL_STR }, { "image", - -4, -4, -4, -4, + -4, -4, -4, -4, 2147483647, "0x", NULLVAL_STR, NULLVAL_STR, - 1, 0, 0, NULLVAL, 0, NULLVAL, + 1, 0, 0, NULLVAL, 0, NULLVAL, "image", - NULLVAL, NULLVAL, -4, NULLVAL, NULLVAL, NULLVAL, 20, 2147483647, 4, + NULLVAL, NULLVAL, -4, NULLVAL, NULLVAL, NULLVAL, 20, 2147483647, 4, NULLVAL_STR }, { "varbinary", - -3, -3, -3, -3, + -3, -3, -3, -3, 8000, "0x", NULLVAL_STR, "max length ", - 1, 0, 2, NULLVAL, 0, NULLVAL, + 1, 0, 2, NULLVAL, 0, NULLVAL, "varbinary", - NULLVAL, NULLVAL, -3, NULLVAL, NULLVAL, NULLVAL, 4, 1, 37, + NULLVAL, NULLVAL, -3, NULLVAL, NULLVAL, NULLVAL, 4, 1, 37, NULLVAL_STR }, { "binary", - -2, -2, -2, -2, + -2, -2, -2, -2, 8000, "0x", NULLVAL_STR, "length ", - 1, 0, 2, NULLVAL, 0, NULLVAL, + 1, 0, 2, NULLVAL, 0, NULLVAL, "binary", - NULLVAL, NULLVAL, -2, NULLVAL, NULLVAL, NULLVAL, 3, 1, 37, + NULLVAL, NULLVAL, -2, NULLVAL, NULLVAL, NULLVAL, 3, 1, 37, NULLVAL_STR }, { "timestamp", - -2, -2, -2, -2, + -2, -2, -2, -2, 8, "0x", NULLVAL_STR, NULLVAL_STR, - 0, 0, 2, NULLVAL, 0, NULLVAL, + 0, 0, 2, NULLVAL, 0, NULLVAL, "timestamp", - NULLVAL, NULLVAL, -2, NULLVAL, NULLVAL, NULLVAL, 80, 8, 45, + NULLVAL, NULLVAL, -2, NULLVAL, NULLVAL, NULLVAL, 80, 8, 45, "timestamp" }, { "text", - -1, -1, -1, -1, + -1, -1, -1, -1, 2147483647, "'", "'", NULLVAL_STR, - 1, 1, 1, NULLVAL, 0, NULLVAL, + 1, 1, 1, NULLVAL, 0, NULLVAL, "text", - NULLVAL, NULLVAL, -1, NULLVAL, NULLVAL, NULLVAL, 19, 2147483647, 35, + NULLVAL, NULLVAL, -1, NULLVAL, NULLVAL, NULLVAL, 19, 2147483647, 35, NULLVAL_STR }, { "char", - 1, 1, 1, 1, + 1, 1, 1, 1, 8000, "'", "'", "length ", - 1, 1, 3, NULLVAL, 0, NULLVAL, + 1, 1, 3, NULLVAL, 0, NULLVAL, "char", - NULLVAL, NULLVAL, 1, NULLVAL, NULLVAL, NULLVAL, 1, 1, 39, + NULLVAL, NULLVAL, 1, NULLVAL, NULLVAL, NULLVAL, 1, 1, 39, "bpchar" }, { "numeric", - 2, 2, 2, 2, + 2, 2, 2, 2, 38, NULLVAL_STR, NULLVAL_STR, "precision,scale ", - 1, 0, 2, 0, 0, 0, + 1, 0, 2, 0, 0, 0, "numeric", - 0, 38, 2, NULLVAL, 10, NULLVAL, 10, 20, 108, + 0, 38, 2, NULLVAL, 10, NULLVAL, 10, 20, 108, "numeric" }, { "numeric() identity", - 2, 2, 2, 2, + 2, 2, 2, 2, 38, NULLVAL_STR, NULLVAL_STR, "precision ", - 0, 0, 2, 0, 0, 1, + 0, 0, 2, 0, 0, 1, "numeric() identity", - 0, 0, 2, NULLVAL, 10, NULLVAL, 10, 20, 108, + 0, 0, 2, NULLVAL, 10, NULLVAL, 10, 20, 108, NULLVAL_STR }, { "decimal", - 3, 3, 3, 3, + 3, 3, 3, 3, 38, NULLVAL_STR, NULLVAL_STR, "precision,scale ", - 1, 0, 2, 0, 0, 0, + 1, 0, 2, 0, 0, 0, "decimal", - 0, 38, 3, NULLVAL, 10, NULLVAL, 24, 20, 106, + 0, 38, 3, NULLVAL, 10, NULLVAL, 24, 20, 106, NULLVAL_STR }, { "money", - 3, 3, 3, 3, + 3, 3, 3, 3, 19, "$", NULLVAL_STR, NULLVAL_STR, - 1, 0, 2, 0, 1, 0, + 1, 0, 2, 0, 1, 0, "money", - 4, 4, 3, NULLVAL, 10, NULLVAL, 11, 21, 110, + 4, 4, 3, NULLVAL, 10, NULLVAL, 11, 21, 110, NULLVAL_STR }, { "smallmoney", - 3, 3, 3, 3, + 3, 3, 3, 3, 10, "$", NULLVAL_STR, NULLVAL_STR, - 1, 0, 2, 0, 1, 0, + 1, 0, 2, 0, 1, 0, "smallmoney", - 4, 4, 3, NULLVAL, 10, NULLVAL, 21, 12, 110, + 4, 4, 3, NULLVAL, 10, NULLVAL, 21, 12, 110, NULLVAL_STR }, { "decimal() identity", - 3, 3, 3, 3, + 3, 3, 3, 3, 38, NULLVAL_STR, NULLVAL_STR, "precision ", - 0, 0, 2, 0, 0, 1, + 0, 0, 2, 0, 0, 1, "decimal() identity", - 0, 0, 3, NULLVAL, 10, NULLVAL, 24, 20, 106, + 0, 0, 3, NULLVAL, 10, NULLVAL, 24, 20, 106, NULLVAL_STR }, { "int", - 4, 4, 4, 4, + 4, 4, 4, 4, 10, NULLVAL_STR, NULLVAL_STR, NULLVAL_STR, - 1, 0, 2, 0, 0, 0, + 1, 0, 2, 0, 0, 0, "int", - 0, 0, 4, NULLVAL, 10, NULLVAL, 7, 4, 38, + 0, 0, 4, NULLVAL, 10, NULLVAL, 7, 4, 38, "int4" }, { "int identity", - 4, 4, 4, 4, + 4, 4, 4, 4, 10, NULLVAL_STR, NULLVAL_STR, NULLVAL_STR, - 0, 0, 2, 0, 0, 1, + 0, 0, 2, 0, 0, 1, "int identity", - 0, 0, 4, NULLVAL, 10, NULLVAL, 7, 4, 38, + 0, 0, 4, NULLVAL, 10, NULLVAL, 7, 4, 38, "" }, { "smallint", - 5, 5, 5, 5, + 5, 5, 5, 5, 5, NULLVAL_STR, NULLVAL_STR, NULLVAL_STR, - 1, 0, 2, 0, 0, 0, + 1, 0, 2, 0, 0, 0, "smallint", - 0, 0, 5, NULLVAL, 10, NULLVAL, 6, 2, 38, + 0, 0, 5, NULLVAL, 10, NULLVAL, 6, 2, 38, "int2" }, { "smallint identity", - 5, 5, 5, 5, + 5, 5, 5, 5, 5, NULLVAL_STR, NULLVAL_STR, NULLVAL_STR, - 0, 0, 2, 0, 0, 1, + 0, 0, 2, 0, 0, 1, "smallint identity", - 0, 0, 5, NULLVAL, 10, NULLVAL, 6, 2, 38, + 0, 0, 5, NULLVAL, 10, NULLVAL, 6, 2, 38, NULLVAL_STR }, { "float", - 6, 6, 6, 6, + 6, 6, 6, 6, 53, NULLVAL_STR, NULLVAL_STR, NULLVAL_STR, - 1, 0, 2, 0, 0, 0, + 1, 0, 2, 0, 0, 0, "float", - NULLVAL, NULLVAL, 6, NULLVAL, 2, NULLVAL, 8, 8, 109, + NULLVAL, NULLVAL, 6, NULLVAL, 2, NULLVAL, 8, 8, 109, "float8" }, { "real", - 7, 7, 7, 7, + 7, 7, 7, 7, 24, NULLVAL_STR, NULLVAL_STR, NULLVAL_STR, - 1, 0, 2, 0, 0, 0, + 1, 0, 2, 0, 0, 0, "real", - NULLVAL, NULLVAL, 7, NULLVAL, 2, NULLVAL, 23, 4, 109, + NULLVAL, NULLVAL, 7, NULLVAL, 2, NULLVAL, 23, 4, 109, "float4" }, { "varchar", - 12, 12, 12, 12, + 12, 12, 12, 12, 8000, "'", "'", "max length ", - 1, 1, 3, NULLVAL, 0, NULLVAL, + 1, 1, 3, NULLVAL, 0, NULLVAL, "varchar", - NULLVAL, NULLVAL, 12, NULLVAL, NULLVAL, NULLVAL, 2, 1, 39, + NULLVAL, NULLVAL, 12, NULLVAL, NULLVAL, NULLVAL, 2, 1, 39, NULLVAL_STR }, { "date", - -9, -9, 9, 91, + -9, -9, 9, 91, 10, "'", "'", NULLVAL_STR, - 1, 0, 3, NULLVAL, 0, NULLVAL, + 1, 0, 3, NULLVAL, 0, NULLVAL, "date", - NULLVAL, 0, 9, 1, NULLVAL, NULLVAL, 0, 20, 0, + NULLVAL, 0, 9, 1, NULLVAL, NULLVAL, 0, 20, 0, "date" }, { "datetime2", - -9, -9, 11, 93, + -9, -9, 11, 93, 27, "'", "'", "scale ", - 1, 0, 3, NULLVAL, 0, NULLVAL, + 1, 0, 3, NULLVAL, 0, NULLVAL, "datetime2", - 0, 7, 9, 3, NULLVAL, NULLVAL, 0, 54, 0, + 0, 7, 9, 3, NULLVAL, NULLVAL, 0, 54, 0, "datetime2" }, { "datetime", - 11, 93, 11, 93, + 11, 93, 11, 93, 23, "'", "'", NULLVAL_STR, - 1, 0, 3, NULLVAL, 0, NULLVAL, + 1, 0, 3, NULLVAL, 0, NULLVAL, "datetime", - 3, 3, 9, 3, NULLVAL, NULLVAL, 12, 16, 111, + 3, 3, 9, 3, NULLVAL, NULLVAL, 12, 16, 111, "datetime" }, { "smalldatetime", - 11, 93, 11, 93, + 11, 93, 11, 93, 16, "'", "'", NULLVAL_STR, - 1, 0, 3, NULLVAL, 0, NULLVAL, + 1, 0, 3, NULLVAL, 0, NULLVAL, "smalldatetime", - 0, 0, 9, 3, NULLVAL, NULLVAL, 22, 16, 111, + 0, 0, 9, 3, NULLVAL, NULLVAL, 22, 16, 111, "smalldatetime" } }; -#endif /* DATATYPE_INFO_TABLE */ +#endif /* DATATYPE_INFO_TABLE */ diff --git a/contrib/babelfishpg_tsql/src/dbcmds.c b/contrib/babelfishpg_tsql/src/dbcmds.c index 84d184fcb0..45e86ca511 100644 --- a/contrib/babelfishpg_tsql/src/dbcmds.c +++ b/contrib/babelfishpg_tsql/src/dbcmds.c @@ -42,7 +42,7 @@ #include "pltsql.h" static bool have_createdb_privilege(void); -static List *gen_createdb_subcmds(const char *schema, +static List *gen_createdb_subcmds(const char *schema, const char *dbo, const char *db_owner, const char *guest, @@ -52,14 +52,14 @@ static List *gen_dropdb_subcmds(const char *schema, const char *dbo, List *db_users, const char *guest_schema); -static Oid do_create_bbf_db(const char *dbname, List *options, const char *owner); +static Oid do_create_bbf_db(const char *dbname, List *options, const char *owner); static void create_bbf_db_internal(const char *dbname, List *options, const char *owner, int16 dbid); static void drop_related_bbf_namespace_entries(int16 dbid); static bool have_createdb_privilege(void) { - bool result = false; + bool result = false; HeapTuple utup; /* Superusers can always do everything */ @@ -70,6 +70,7 @@ have_createdb_privilege(void) if (HeapTupleIsValid(utup)) { result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreatedb; + ReleaseSysCache(utup); } return result; @@ -78,19 +79,19 @@ have_createdb_privilege(void) /* * Generate subcmds for CREATE DATABASE. Note 'guest' can be NULL. */ -static List * +static List * gen_createdb_subcmds(const char *schema, const char *dbo, const char *db_owner, const char *guest, const char *guest_schema) { - StringInfoData query; - List *res; - List *logins = NIL; - Node *stmt; - int i = 0; - int expected_stmt_num; - - /* - * To avoid SQL injection, we generate statement parsetree with dummy values - * and update them later + StringInfoData query; + List *res; + List *logins = NIL; + Node *stmt; + int i = 0; + int expected_stmt_num; + + /* + * To avoid SQL injection, we generate statement parsetree with dummy + * values and update them later */ initStringInfo(&query); @@ -131,7 +132,7 @@ gen_createdb_subcmds(const char *schema, const char *dbo, const char *db_owner, /* Replace dummy elements in parsetree with real values */ stmt = parsetree_nth_stmt(res, i++); update_CreateRoleStmt(stmt, db_owner, NULL, NULL); - + stmt = parsetree_nth_stmt(res, i++); update_CreateRoleStmt(stmt, dbo, NULL, db_owner); @@ -146,6 +147,7 @@ gen_createdb_subcmds(const char *schema, const char *dbo, const char *db_owner, if (list_length(logins) > 0) { AccessPriv *tmp = makeNode(AccessPriv); + tmp->priv_name = pstrdup(guest); tmp->cols = NIL; @@ -185,20 +187,20 @@ gen_dropdb_subcmds(const char *schema, List *db_users, const char *guest_schema) { - StringInfoData query; - List *stmt_list; - ListCell *elem; - Node *stmt; - int expected_stmts = 5; - int i = 0; + StringInfoData query; + List *stmt_list; + ListCell *elem; + Node *stmt; + int expected_stmts = 5; + int i = 0; initStringInfo(&query); appendStringInfo(&query, "DROP SCHEMA dummy CASCADE; "); appendStringInfo(&query, "DROP SCHEMA dummy CASCADE; "); /* First drop guest user and custom users if they exist */ - foreach (elem, db_users) + foreach(elem, db_users) { - char *user_name = (char *) lfirst(elem); + char *user_name = (char *) lfirst(elem); if (strcmp(user_name, db_owner) != 0 && strcmp(user_name, dbo) != 0) { @@ -226,9 +228,9 @@ gen_dropdb_subcmds(const char *schema, stmt = parsetree_nth_stmt(stmt_list, i++); update_DropStmt(stmt, guest_schema); - foreach (elem, db_users) + foreach(elem, db_users) { - char *user_name = (char *) lfirst(elem); + char *user_name = (char *) lfirst(elem); if (strcmp(user_name, db_owner) != 0 && strcmp(user_name, dbo) != 0) { @@ -254,16 +256,18 @@ gen_dropdb_subcmds(const char *schema, Oid create_bbf_db(ParseState *pstate, const CreatedbStmt *stmt) { - ListCell *option; + ListCell *option; const char *owner = GetUserNameFromId(GetSessionUserId(), false); /* Check options */ foreach(option, stmt->options) { DefElem *defel = (DefElem *) lfirst(option); + if (strcmp(defel->defname, "collate") == 0) { const char *server_collation_name = GetConfigOption("babelfishpg_tsql.server_collation_name", false, false); + if (server_collation_name && strcmp(server_collation_name, defGetString(defel))) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), @@ -280,8 +284,8 @@ create_bbf_db(ParseState *pstate, const CreatedbStmt *stmt) return do_create_bbf_db(stmt->dbname, stmt->options, owner); } -/* - * To guard the rare case that we have used up all the possible sequence values +/* + * To guard the rare case that we have used up all the possible sequence values * and it wraps around, check if the next seq value is used by an existing DB. * Also, we reserved four IDs 1-4 for native databases, 1,2 and 4 are created when * initializing babelfishpg_tsql (master, tempdb, and msdb, respectively), 3 is just a placeholder that @@ -290,11 +294,14 @@ create_bbf_db(ParseState *pstate, const CreatedbStmt *stmt) * If we can't find one after looping the entire range of sequence values * (1 to 32767), we should bail out. */ -static int16 getAvailDbid(void) { - int16 dbid; - int16 start = 0; +static int16 +getAvailDbid(void) +{ + int16 dbid; + int16 start = 0; - do { + do + { dbid = DirectFunctionCall1(nextval, CStringGetTextDatum("sys.babelfish_db_seq")); if (start == 0) start = dbid; @@ -317,13 +324,17 @@ static int16 getAvailDbid(void) { int16 getDbidForLogicalDbRestore(Oid relid) { - const char *prev_current_user; + const char *prev_current_user; int16 dbid; /* Get new DB ID. Need sysadmin to do that. */ prev_current_user = GetUserNameFromId(GetUserId(), false); bbf_set_current_user("sysadmin"); - /* For sysdatabases table we need to generate new dbid for the database we are currently restoring. */ + + /* + * For sysdatabases table we need to generate new dbid for the database we + * are currently restoring. + */ if (relid == sysdatabases_oid) { if ((dbid = getAvailDbid()) == InvalidDbid) @@ -331,15 +342,17 @@ getDbidForLogicalDbRestore(Oid relid) (errcode(ERRCODE_INVALID_DATABASE_DEFINITION), errmsg("cannot find an available ID for new database."))); } + /* - * For all the other catalog tables which contain dbid column, get dbid using current value of the - * babelfish_db_seq sequence. It is ok to fetch current value of the sequence here since we already - * have generated new dbid while inserting into sysdatabases catalog. + * For all the other catalog tables which contain dbid column, get dbid + * using current value of the babelfish_db_seq sequence. It is ok to fetch + * current value of the sequence here since we already have generated new + * dbid while inserting into sysdatabases catalog. */ else { - RangeVar *sequence = makeRangeVarFromNameList(stringToQualifiedNameList("sys.babelfish_db_seq")); - Oid seqid = RangeVarGetRelid(sequence, NoLock, false); + RangeVar *sequence = makeRangeVarFromNameList(stringToQualifiedNameList("sys.babelfish_db_seq")); + Oid seqid = RangeVarGetRelid(sequence, NoLock, false); dbid = DirectFunctionCall1(currval_oid, seqid); } @@ -351,14 +364,14 @@ getDbidForLogicalDbRestore(Oid relid) static Oid do_create_bbf_db(const char *dbname, List *options, const char *owner) { - int16 dbid; - const char *prev_current_user; + int16 dbid; + const char *prev_current_user; if (DbidIsValid(get_db_id(dbname))) ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_DATABASE), - errmsg("Database '%s' already exists. Choose a different database name.", - dbname))); + (errcode(ERRCODE_DUPLICATE_DATABASE), + errmsg("Database '%s' already exists. Choose a different database name.", + dbname))); /* Get new DB ID. Need sysadmin to do that. */ prev_current_user = GetUserNameFromId(GetUserId(), false); @@ -377,23 +390,23 @@ do_create_bbf_db(const char *dbname, List *options, const char *owner) static void create_bbf_db_internal(const char *dbname, List *options, const char *owner, int16 dbid) { - int16 old_dbid; - char *old_dbname; - Oid datdba; - Datum *new_record; - bool *new_record_nulls; + int16 old_dbid; + char *old_dbname; + Oid datdba; + Datum *new_record; + bool *new_record_nulls; Relation sysdatabase_rel; HeapTuple tuple; - List *parsetree_list; - ListCell *parsetree_item; - const char *dbo_scm; - const char *dbo_role; - const char *db_owner_role; - const char *guest_scm; - NameData default_collation; - const char *guest; - const char *prev_current_user; - int stmt_number = 0; + List *parsetree_list; + ListCell *parsetree_item; + const char *dbo_scm; + const char *dbo_role; + const char *db_owner_role; + const char *guest_scm; + NameData default_collation; + const char *guest; + const char *prev_current_user; + int stmt_number = 0; /* TODO: Extract options */ @@ -401,9 +414,10 @@ create_bbf_db_internal(const char *dbname, List *options, const char *owner, int if (!HeapTupleIsValid(tuple)) { const char *server_collation_name = GetConfigOption("babelfishpg_tsql.server_collation_name", false, false); + ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("OID corresponding to collation \"%s\" does not exist", server_collation_name))); + errmsg("OID corresponding to collation \"%s\" does not exist", server_collation_name))); } default_collation = ((Form_pg_collation) GETSTRUCT(tuple))->collname; ReleaseSysCache(tuple); @@ -412,10 +426,11 @@ create_bbf_db_internal(const char *dbname, List *options, const char *owner, int if (SINGLE_DB == get_migration_mode() && dbid > 4) { const char *user_dbname = get_one_user_db_name(); + if (user_dbname) - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_DATABASE), - errmsg("Only one user database allowed under single-db mode. User database \"%s\" already exists", + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_DATABASE), + errmsg("Only one user database allowed under single-db mode. User database \"%s\" already exists", user_dbname))); } @@ -447,13 +462,13 @@ create_bbf_db_internal(const char *dbname, List *options, const char *owner, int if (OidIsValid(get_role_oid(dbo_role, true))) ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("role \"%s\" already exists", dbo_role))); + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("role \"%s\" already exists", dbo_role))); if (OidIsValid(get_role_oid(db_owner_role, true))) ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("role \"%s\" already exists", db_owner_role))); + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("role \"%s\" already exists", db_owner_role))); /* For simplicity, do not allow bbf db name clides with pg dbnames */ /* TODO: add another check in orignal createdb */ @@ -496,7 +511,7 @@ create_bbf_db_internal(const char *dbname, List *options, const char *owner, int old_dbid = get_cur_db_id(); old_dbname = get_cur_db_name(); - set_cur_db(dbid, dbname); /* temporarily set current dbid as the new id */ + set_cur_db(dbid, dbname); /* temporarily set current dbid as the new id */ PG_TRY(); { @@ -514,7 +529,7 @@ create_bbf_db_internal(const char *dbname, List *options, const char *owner, int wrapper->stmt_location = 0; stmt_number++; - if(guest && list_length(parsetree_list) == stmt_number) + if (guest && list_length(parsetree_list) == stmt_number) wrapper->stmt_len = 19; else wrapper->stmt_len = 18; @@ -539,7 +554,10 @@ create_bbf_db_internal(const char *dbname, List *options, const char *owner, int add_to_bbf_authid_user_ext(db_owner_role, "db_owner", dbname, NULL, NULL, true, true, false); if (guest) { - /* For master, tempdb and msdb databases, the guest user will be enabled by default */ + /* + * For master, tempdb and msdb databases, the guest user will be + * enabled by default + */ if (strcmp(dbname, "master") == 0 || strcmp(dbname, "tempdb") == 0 || strcmp(dbname, "msdb") == 0) add_to_bbf_authid_user_ext(guest, "guest", dbname, NULL, NULL, false, true, false); else @@ -562,22 +580,22 @@ create_bbf_db_internal(const char *dbname, List *options, const char *owner, int void drop_bbf_db(const char *dbname, bool missing_ok, bool force_drop) { - volatile Relation sysdatabase_rel; - HeapTuple tuple; - Form_sysdatabases bbf_db; - int16 dbid; - const char *schema_name; - const char *db_owner_role; - const char *dbo_role; - const char *guest_schema_name; - List *db_users_list; - List *parsetree_list; - ListCell *parsetree_item; - const char *prev_current_user; + volatile Relation sysdatabase_rel; + HeapTuple tuple; + Form_sysdatabases bbf_db; + int16 dbid; + const char *schema_name; + const char *db_owner_role; + const char *dbo_role; + const char *guest_schema_name; + List *db_users_list; + List *parsetree_list; + ListCell *parsetree_item; + const char *prev_current_user; if ((strlen(dbname) == 6 && (strncmp(dbname, "master", 6) == 0)) || - ((strlen(dbname) == 6 && strncmp(dbname, "tempdb", 6) == 0)) || - (strlen(dbname) == 4 && (strncmp(dbname, "msdb", 4) == 0))) + ((strlen(dbname) == 6 && strncmp(dbname, "tempdb", 6) == 0)) || + (strlen(dbname) == 4 && (strncmp(dbname, "msdb", 4) == 0))) { if (!force_drop) ereport(ERROR, @@ -588,7 +606,7 @@ drop_bbf_db(const char *dbname, bool missing_ok, bool force_drop) /* Check if the DB exist */ sysdatabase_rel = table_open(sysdatabases_oid, RowExclusiveLock); - tuple = SearchSysCache1(SYSDATABASENAME, CStringGetTextDatum(dbname)); + tuple = SearchSysCache1(SYSDATABASENAME, CStringGetTextDatum(dbname)); if (!HeapTupleIsValid(tuple)) { @@ -625,15 +643,18 @@ drop_bbf_db(const char *dbname, bool missing_ok, bool force_drop) PG_TRY(); { - Oid roleid = GetSessionUserId(); + Oid roleid = GetSessionUserId(); const char *login = GetUserNameFromId(roleid, false); - bool login_is_db_owner = 0 == strncmp(login, get_owner_of_db(dbname), NAMEDATALEN); - + bool login_is_db_owner = 0 == strncmp(login, get_owner_of_db(dbname), NAMEDATALEN); + if (!(has_privs_of_role(roleid, get_role_oid("sysadmin", false)) || login_is_db_owner)) aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_DATABASE, dbname); - /* Get a session-level exclusive lock on the new logical db we are trying to drop */ + /* + * Get a session-level exclusive lock on the new logical db we are + * trying to drop + */ if (!TryLockLogicalDatabaseForSession(dbid, ExclusiveLock)) ereport(ERROR, (errcode(ERRCODE_CHECK_VIOLATION), @@ -641,7 +662,7 @@ drop_bbf_db(const char *dbname, bool missing_ok, bool force_drop) " in another session", dbname))); CatalogTupleDelete(sysdatabase_rel, &tuple->t_self); - ReleaseSysCache(tuple); + ReleaseSysCache(tuple); table_close(sysdatabase_rel, RowExclusiveLock); @@ -714,45 +735,47 @@ drop_bbf_db(const char *dbname, bool missing_ok, bool force_drop) } PG_FUNCTION_INFO_V1(create_builtin_dbs); -Datum create_builtin_dbs(PG_FUNCTION_ARGS) -{ - const char *sql_dialect_value_old; - const char *tsql_dialect = "tsql"; - const char *sa_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); +Datum +create_builtin_dbs(PG_FUNCTION_ARGS) +{ + const char *sql_dialect_value_old; + const char *tsql_dialect = "tsql"; + const char *sa_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); sql_dialect_value_old = GetConfigOption("babelfishpg_tsql.sql_dialect", true, true); PG_TRY(); { set_config_option("babelfishpg_tsql.sql_dialect", tsql_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); do_create_bbf_db("master", NULL, sa_name); do_create_bbf_db("tempdb", NULL, sa_name); do_create_bbf_db("msdb", NULL, sa_name); set_config_option("babelfishpg_tsql.sql_dialect", sql_dialect_value_old, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); } PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", sql_dialect_value_old, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); } PG_END_TRY(); PG_RETURN_INT32(0); } -// This function is only being used for the purposes of the upgrade script to add the msdb database -// It was first added in babelfishpg_tsql--1.2.0--1.3.0.sql +/* This function is only being used for the purposes of the upgrade script to add the msdb database */ +/* It was first added in babelfishpg_tsql--1.2.0--1.3.0.sql */ PG_FUNCTION_INFO_V1(create_msdb_if_not_exists); -Datum create_msdb_if_not_exists(PG_FUNCTION_ARGS) -{ - const char *sql_dialect_value_old; - const char *tsql_dialect = "tsql"; - const char *sa_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); +Datum +create_msdb_if_not_exists(PG_FUNCTION_ARGS) +{ + const char *sql_dialect_value_old; + const char *tsql_dialect = "tsql"; + const char *sa_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); if (get_db_name(4) != NULL || DbidIsValid(get_db_id("msdb"))) PG_RETURN_INT32(0); @@ -762,18 +785,18 @@ Datum create_msdb_if_not_exists(PG_FUNCTION_ARGS) PG_TRY(); { set_config_option("babelfishpg_tsql.sql_dialect", tsql_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); create_bbf_db_internal("msdb", NULL, sa_name, 4); set_config_option("babelfishpg_tsql.sql_dialect", sql_dialect_value_old, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); } PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", sql_dialect_value_old, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); } PG_END_TRY(); @@ -782,24 +805,25 @@ Datum create_msdb_if_not_exists(PG_FUNCTION_ARGS) #define DROP_DB_BATCH_SIZE 32 PG_FUNCTION_INFO_V1(drop_all_dbs); -Datum drop_all_dbs(PG_FUNCTION_ARGS) +Datum +drop_all_dbs(PG_FUNCTION_ARGS) { - Relation sysdatabase_rel; - TableScanDesc scan; - HeapTuple tuple; - char* dbnames[DROP_DB_BATCH_SIZE]; - bool is_null; - bool all_db_dropped = false; - const char *sql_dialect_value_old; - const char *tsql_dialect = "tsql"; + Relation sysdatabase_rel; + TableScanDesc scan; + HeapTuple tuple; + char *dbnames[DROP_DB_BATCH_SIZE]; + bool is_null; + bool all_db_dropped = false; + const char *sql_dialect_value_old; + const char *tsql_dialect = "tsql"; sql_dialect_value_old = GetConfigOption("babelfishpg_tsql.sql_dialect", true, true); PG_TRY(); { set_config_option("babelfishpg_tsql.sql_dialect", tsql_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); /* drop built-in DBs */ drop_bbf_db("master", false, true); drop_bbf_db("tempdb", false, true); @@ -808,16 +832,18 @@ Datum drop_all_dbs(PG_FUNCTION_ARGS) /* drop user created DBs */ while (!all_db_dropped) { - int i = 0, j; + int i = 0, + j; sysdatabase_rel = table_open(sysdatabases_oid, RowExclusiveLock); scan = table_beginscan_catalog(sysdatabase_rel, 0, NULL); tuple = heap_getnext(scan, ForwardScanDirection); - while (HeapTupleIsValid(tuple) && i < DROP_DB_BATCH_SIZE) + while (HeapTupleIsValid(tuple) && i < DROP_DB_BATCH_SIZE) { - Datum name = heap_getattr(tuple, Anum_sysdatabaese_name, - sysdatabase_rel->rd_att, &is_null); + Datum name = heap_getattr(tuple, Anum_sysdatabaese_name, + sysdatabase_rel->rd_att, &is_null); + dbnames[i] = TextDatumGetCString(name); i++; @@ -825,7 +851,7 @@ Datum drop_all_dbs(PG_FUNCTION_ARGS) } table_endscan(scan); table_close(sysdatabase_rel, RowExclusiveLock); - + for (j = 0; j < i; j++) drop_bbf_db(dbnames[j], false, true); @@ -833,14 +859,14 @@ Datum drop_all_dbs(PG_FUNCTION_ARGS) all_db_dropped = true; } set_config_option("babelfishpg_tsql.sql_dialect", sql_dialect_value_old, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); } PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", sql_dialect_value_old, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RE_THROW(); } @@ -852,11 +878,11 @@ Datum drop_all_dbs(PG_FUNCTION_ARGS) List * grant_guest_to_logins(StringInfoData *query) { - Relation login_rel; - TableScanDesc scan; - HeapTuple tuple; - bool is_null; - List *logins = NIL; + Relation login_rel; + TableScanDesc scan; + HeapTuple tuple; + bool is_null; + List *logins = NIL; login_rel = table_open(get_authid_login_ext_oid(), AccessShareLock); scan = table_beginscan_catalog(login_rel, 0, NULL); @@ -864,16 +890,17 @@ grant_guest_to_logins(StringInfoData *query) while (HeapTupleIsValid(tuple)) { - Datum rolname = heap_getattr(tuple, - LOGIN_EXT_ROLNAME+1, - login_rel->rd_att, - &is_null); + Datum rolname = heap_getattr(tuple, + LOGIN_EXT_ROLNAME + 1, + login_rel->rd_att, + &is_null); const char *name = NameStr(*(DatumGetName(rolname))); - Oid roleid = get_role_oid(name, false); + Oid roleid = get_role_oid(name, false); if (!role_is_sa(roleid)) { - RoleSpec *tmp = makeNode(RoleSpec); + RoleSpec *tmp = makeNode(RoleSpec); + tmp->roletype = ROLESPEC_CSTRING; tmp->location = -1; tmp->rolename = pstrdup(name); @@ -893,21 +920,21 @@ grant_guest_to_logins(StringInfoData *query) static void drop_related_bbf_namespace_entries(int16 dbid) { - Relation namespace_rel; - AttrNumber attnum; - TableScanDesc scan; - ScanKeyData key[1]; - HeapTuple tuple; + Relation namespace_rel; + AttrNumber attnum; + TableScanDesc scan; + ScanKeyData key[1]; + HeapTuple tuple; namespace_rel = table_open(namespace_ext_oid, RowExclusiveLock); attnum = (AttrNumber) attnameAttNum(namespace_rel, "dbid", false); if (attnum == InvalidAttrNumber) - ereport(ERROR, + ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column \"dbid\" of relation \"%s\" does not exist", RelationGetRelationName(namespace_rel)))); - ScanKeyInit(&key[0], + ScanKeyInit(&key[0], attnum, BTEqualStrategyNumber, F_INT2EQ, Int16GetDatum(dbid)); @@ -924,23 +951,23 @@ drop_related_bbf_namespace_entries(int16 dbid) table_close(namespace_rel, RowExclusiveLock); } -/* +/* * Helper function to get the owner from a given database name * Caller is responsible for validating that the given database exists */ const char * get_owner_of_db(const char *dbname) { - char *owner = NULL; - HeapTuple tuple; - Form_sysdatabases sysdb; + char *owner = NULL; + HeapTuple tuple; + Form_sysdatabases sysdb; tuple = SearchSysCache1(SYSDATABASENAME, CStringGetTextDatum(dbname)); if (!HeapTupleIsValid(tuple)) - ereport(ERROR, + ereport(ERROR, (errcode(ERRCODE_UNDEFINED_DATABASE), - errmsg("database \"%s\" does not exist", dbname))); + errmsg("database \"%s\" does not exist", dbname))); sysdb = ((Form_sysdatabases) GETSTRUCT(tuple)); owner = NameStr(sysdb->owner); @@ -956,40 +983,43 @@ create_schema_if_not_exists(const uint16 dbid, const char *schemaname, const char *owner_role) { - StringInfoData query; - List *parsetree_list; - Oid datdba; - const char *prev_current_user; - uint16 old_dbid; - const char *old_dbname, *phys_schema_name, *phys_role; + StringInfoData query; + List *parsetree_list; + Oid datdba; + const char *prev_current_user; + uint16 old_dbid; + const char *old_dbname, + *phys_schema_name, + *phys_role; /* - * During upgrade, the migration mode is reset to single-db so - * we cannot call get_physical_user_name() directly. - * Detect whether the original migration was single-db or multi-db. - */ + * During upgrade, the migration mode is reset to single-db so we cannot + * call get_physical_user_name() directly. Detect whether the original + * migration was single-db or multi-db. + */ MigrationMode baseline_mode = is_user_database_singledb(dbname) ? SINGLE_DB : MULTI_DB; + phys_schema_name = get_physical_schema_name_by_mode((char *) dbname, schemaname, baseline_mode); if (SearchSysCacheExists1(NAMESPACENAME, PointerGetDatum(phys_schema_name))) { ereport(LOG, - (errcode(ERRCODE_DUPLICATE_SCHEMA), - errmsg("schema \"%s\" already exists, skipping", phys_schema_name))); + (errcode(ERRCODE_DUPLICATE_SCHEMA), + errmsg("schema \"%s\" already exists, skipping", phys_schema_name))); return; } /* - * guest role prepends dbname regardless if single-db or multi-db. - * If for some reason guest role does not exist, then that is a bigger problem. - * We skip creating the guest schema entirely instead of crashing though. - */ + * guest role prepends dbname regardless if single-db or multi-db. If for + * some reason guest role does not exist, then that is a bigger problem. + * We skip creating the guest schema entirely instead of crashing though. + */ phys_role = get_physical_user_name((char *) dbname, (char *) owner_role); if (!OidIsValid(get_role_oid(phys_role, true))) { ereport(LOG, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("role \"%s\" does not exist", phys_role))); + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("role \"%s\" does not exist", phys_role))); return; } @@ -1013,7 +1043,8 @@ create_schema_if_not_exists(const uint16 dbid, PG_TRY(); { PlannedStmt *wrapper; - Node *stmt = ((RawStmt *) linitial(parsetree_list))->stmt; + Node *stmt = ((RawStmt *) linitial(parsetree_list))->stmt; + update_CreateSchemaStmt(stmt, phys_schema_name, phys_role); wrapper = makeNode(PlannedStmt); @@ -1024,13 +1055,13 @@ create_schema_if_not_exists(const uint16 dbid, wrapper->stmt_len = 0; ProcessUtility(wrapper, - query.data, - false, - PROCESS_UTILITY_SUBCOMMAND, - NULL, - NULL, - None_Receiver, - NULL); + query.data, + false, + PROCESS_UTILITY_SUBCOMMAND, + NULL, + NULL, + None_Receiver, + NULL); /* make sure later steps can see the object created here */ CommandCounterIncrement(); @@ -1052,38 +1083,39 @@ create_schema_if_not_exists(const uint16 dbid, * the guest schema for each database if the database does not have the guest schema yet. */ PG_FUNCTION_INFO_V1(create_guest_schema_for_all_dbs); -Datum create_guest_schema_for_all_dbs(PG_FUNCTION_ARGS) +Datum +create_guest_schema_for_all_dbs(PG_FUNCTION_ARGS) { - Relation sysdatabase_rel; - TableScanDesc scan; - HeapTuple tuple; - const char *sql_dialect_value_old; - const char *tsql_dialect = "tsql"; - Form_sysdatabases bbf_db; - const char *dbname; - bool creating_extension_backup = creating_extension; + Relation sysdatabase_rel; + TableScanDesc scan; + HeapTuple tuple; + const char *sql_dialect_value_old; + const char *tsql_dialect = "tsql"; + Form_sysdatabases bbf_db; + const char *dbname; + bool creating_extension_backup = creating_extension; sql_dialect_value_old = GetConfigOption("babelfishpg_tsql.sql_dialect", true, true); PG_TRY(); { set_config_option("babelfishpg_tsql.sql_dialect", tsql_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); /* - * Since this is part of upgrade script, PG assumes we would like to set - * the babelfish extension depend on this new schema. This is not true - * so we tell PG not to set any dependency for us. - * Check recordDependencyOnCurrentExtension() for more information. - */ + * Since this is part of upgrade script, PG assumes we would like to + * set the babelfish extension depend on this new schema. This is not + * true so we tell PG not to set any dependency for us. Check + * recordDependencyOnCurrentExtension() for more information. + */ creating_extension = false; sysdatabase_rel = table_open(sysdatabases_oid, RowExclusiveLock); scan = table_beginscan_catalog(sysdatabase_rel, 0, NULL); tuple = heap_getnext(scan, ForwardScanDirection); - while (HeapTupleIsValid(tuple)) + while (HeapTupleIsValid(tuple)) { bbf_db = (Form_sysdatabases) GETSTRUCT(tuple); dbname = text_to_cstring(&(bbf_db->name)); @@ -1097,17 +1129,17 @@ Datum create_guest_schema_for_all_dbs(PG_FUNCTION_ARGS) creating_extension = creating_extension_backup; set_config_option("babelfishpg_tsql.sql_dialect", sql_dialect_value_old, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); } PG_FINALLY(); { creating_extension = creating_extension_backup; set_config_option("babelfishpg_tsql.sql_dialect", sql_dialect_value_old, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); } PG_END_TRY(); PG_RETURN_INT32(0); -} \ No newline at end of file +} diff --git a/contrib/babelfishpg_tsql/src/dbcmds.h b/contrib/babelfishpg_tsql/src/dbcmds.h index 20cc1d1eeb..ace5e862cb 100644 --- a/contrib/babelfishpg_tsql/src/dbcmds.h +++ b/contrib/babelfishpg_tsql/src/dbcmds.h @@ -2,7 +2,7 @@ #define DBCMDS_H #include "nodes/parsenodes.h" -extern Oid create_bbf_db(ParseState *pstate, const CreatedbStmt *stmt); +extern Oid create_bbf_db(ParseState *pstate, const CreatedbStmt *stmt); extern void drop_bbf_db(const char *dbname, bool missing_ok, bool force_drop); extern const char *get_owner_of_db(const char *dbname); extern List *grant_guest_to_logins(StringInfoData *query); diff --git a/contrib/babelfishpg_tsql/src/dynastack.c b/contrib/babelfishpg_tsql/src/dynastack.c index 043c606829..81f39c12ba 100644 --- a/contrib/babelfishpg_tsql/src/dynastack.c +++ b/contrib/babelfishpg_tsql/src/dynastack.c @@ -1,43 +1,52 @@ #include "dynavec.h" #include "dynastack.h" -DynaStack *create_stack(size_t elem_size) +DynaStack * +create_stack(size_t elem_size) { - return (DynaStack *) create_vector(elem_size); + return (DynaStack *) create_vector(elem_size); } -DynaStack *create_stack2(size_t elem_size, size_t init_num_elems) +DynaStack * +create_stack2(size_t elem_size, size_t init_num_elems) { - return (DynaStack *) create_vector2(elem_size, init_num_elems); + return (DynaStack *) create_vector2(elem_size, init_num_elems); } -void destroy_stack(DynaStack *stack) +void +destroy_stack(DynaStack *stack) { - destroy_vector((DynaVec *) stack); + destroy_vector((DynaVec *) stack); } -void *stack_top(DynaStack *stack) +void * +stack_top(DynaStack *stack) { - DynaVec *vec = (DynaVec *) stack; - return vec_back(vec); + DynaVec *vec = (DynaVec *) stack; + + return vec_back(vec); } -void stack_pop(DynaStack *stack) +void +stack_pop(DynaStack *stack) { - vec_pop_back((DynaVec *) stack); + vec_pop_back((DynaVec *) stack); } -void stack_push(DynaStack *stack, const void *elem_ptr) +void +stack_push(DynaStack *stack, const void *elem_ptr) { - vec_push_back((DynaVec *) stack, elem_ptr); + vec_push_back((DynaVec *) stack, elem_ptr); } -bool stack_is_empty(DynaStack *stack) +bool +stack_is_empty(DynaStack *stack) { - return stack->size == 0; + return stack->size == 0; } -size_t stack_size(const DynaStack *stack) +size_t +stack_size(const DynaStack *stack) { - return vec_size((const DynaVec *) stack); + return vec_size((const DynaVec *) stack); } diff --git a/contrib/babelfishpg_tsql/src/dynastack.h b/contrib/babelfishpg_tsql/src/dynastack.h index 4ddfac5988..3cfd5bee87 100644 --- a/contrib/babelfishpg_tsql/src/dynastack.h +++ b/contrib/babelfishpg_tsql/src/dynastack.h @@ -11,15 +11,15 @@ typedef DynaVec DynaStack; * STACK APIS ******************************************************************/ -DynaStack *create_stack(size_t elem_size); -DynaStack *create_stack2(size_t elem_size, size_t init_num_elems); -void destroy_stack(DynaStack *stack); +DynaStack *create_stack(size_t elem_size); +DynaStack *create_stack2(size_t elem_size, size_t init_num_elems); +void destroy_stack(DynaStack *stack); -void *stack_top(DynaStack *stack); -void stack_pop(DynaStack *stack); -void stack_push(DynaStack *stack, const void *elem_ptr); -bool stack_is_empty(DynaStack *stack); -size_t stack_size(const DynaStack *stack); +void *stack_top(DynaStack *stack); +void stack_pop(DynaStack *stack); +void stack_push(DynaStack *stack, const void *elem_ptr); +bool stack_is_empty(DynaStack *stack); +size_t stack_size(const DynaStack *stack); -#endif /* DYNASTACK_H */ +#endif /* DYNASTACK_H */ diff --git a/contrib/babelfishpg_tsql/src/dynavec.c b/contrib/babelfishpg_tsql/src/dynavec.c index 9703e85e46..c00dc8b41c 100644 --- a/contrib/babelfishpg_tsql/src/dynavec.c +++ b/contrib/babelfishpg_tsql/src/dynavec.c @@ -9,94 +9,108 @@ static void vec_expand(DynaVec *); * EXTERNAL APIS **********************************************************************************/ -DynaVec *create_vector(size_t elem_size) +DynaVec * +create_vector(size_t elem_size) { - return create_vector2(elem_size, DEFAULT_INIT_NUM_ELEMS); + return create_vector2(elem_size, DEFAULT_INIT_NUM_ELEMS); } -DynaVec *create_vector2(size_t elem_size, size_t init_num_elems) +DynaVec * +create_vector2(size_t elem_size, size_t init_num_elems) { - DynaVec *new_vec = palloc(sizeof(DynaVec)); - size_t total_bytes = elem_size * init_num_elems; - new_vec->data = palloc0(total_bytes); - new_vec->capacity = total_bytes; - new_vec->size = 0; - new_vec->elem_size = elem_size; - return new_vec; + DynaVec *new_vec = palloc(sizeof(DynaVec)); + size_t total_bytes = elem_size * init_num_elems; + + new_vec->data = palloc0(total_bytes); + new_vec->capacity = total_bytes; + new_vec->size = 0; + new_vec->elem_size = elem_size; + return new_vec; } -DynaVec *create_vector3(size_t elem_size, size_t init_num_elems, void *init_val) +DynaVec * +create_vector3(size_t elem_size, size_t init_num_elems, void *init_val) { - void *value; - int i; - DynaVec *vec = create_vector2(elem_size, init_num_elems); - - /* Initialization */ - for (i=0; i< init_num_elems; i++) - { - value = vec_at(vec, i); - memcpy(value, init_val, elem_size); - } - return vec; + void *value; + int i; + DynaVec *vec = create_vector2(elem_size, init_num_elems); + + /* Initialization */ + for (i = 0; i < init_num_elems; i++) + { + value = vec_at(vec, i); + memcpy(value, init_val, elem_size); + } + return vec; } -DynaVec *create_vector_copy(DynaVec *src) +DynaVec * +create_vector_copy(DynaVec *src) { - DynaVec *vec = create_vector2(src->elem_size, vec_size(src)); - /* simply copy data from src vector */ - memcpy(vec->data, src->data, src->size); - vec->size = src->size; - return vec; + DynaVec *vec = create_vector2(src->elem_size, vec_size(src)); + + /* simply copy data from src vector */ + memcpy(vec->data, src->data, src->size); + vec->size = src->size; + return vec; } -void destroy_vector(DynaVec *vec) +void +destroy_vector(DynaVec *vec) { - pfree(vec->data); - vec->data = NULL; - vec->capacity = 0; - vec->size = 0; - pfree(vec); + pfree(vec->data); + vec->data = NULL; + vec->capacity = 0; + vec->size = 0; + pfree(vec); } -void vec_push_back(DynaVec *vec, const void *elem_ptr) +void +vec_push_back(DynaVec *vec, const void *elem_ptr) { - if ((vec->capacity - vec->size) < vec->elem_size) - vec_expand(vec); - memcpy(vec->data + vec->size, elem_ptr, vec->elem_size); - vec->size += vec->elem_size; + if ((vec->capacity - vec->size) < vec->elem_size) + vec_expand(vec); + memcpy(vec->data + vec->size, elem_ptr, vec->elem_size); + vec->size += vec->elem_size; } -void vec_pop_back(DynaVec *vec) +void +vec_pop_back(DynaVec *vec) { - if (vec->size > 0) - vec->size -= vec->elem_size; + if (vec->size > 0) + vec->size -= vec->elem_size; } -void *vec_at(const DynaVec *vec, size_t index) +void * +vec_at(const DynaVec *vec, size_t index) { - return (vec->data + (index * vec->elem_size)); + return (vec->data + (index * vec->elem_size)); } -void *vec_back(const DynaVec *vec) +void * +vec_back(const DynaVec *vec) { - if (vec->size < vec->elem_size) - return NULL; - return vec_at(vec, (vec->size/vec->elem_size -1)); + if (vec->size < vec->elem_size) + return NULL; + return vec_at(vec, (vec->size / vec->elem_size - 1)); } -size_t vec_size(const DynaVec *vec) +size_t +vec_size(const DynaVec *vec) { - return (vec->size / vec->elem_size); + return (vec->size / vec->elem_size); } /*********************************************************************************** * INTERNAL FUNCTIONS **********************************************************************************/ -static void vec_expand(DynaVec *vec) +static void +vec_expand(DynaVec *vec) { - size_t cur_cap = vec->capacity; - size_t new_cap = cur_cap * 2; - vec->data = repalloc(vec->data, new_cap); - vec->capacity = new_cap; + size_t cur_cap = vec->capacity; + size_t new_cap = cur_cap * 2; + + vec->data = repalloc(vec->data, new_cap); + vec->capacity = new_cap; } diff --git a/contrib/babelfishpg_tsql/src/dynavec.h b/contrib/babelfishpg_tsql/src/dynavec.h index 990a799014..6b8d0a07b9 100644 --- a/contrib/babelfishpg_tsql/src/dynavec.h +++ b/contrib/babelfishpg_tsql/src/dynavec.h @@ -8,34 +8,38 @@ typedef struct { - char *data; - size_t capacity; /* capacity in bytes */ - size_t size; /* size in bytes */ - size_t elem_size; /* size of element in bytes */ + char *data; + size_t capacity; /* capacity in bytes */ + size_t size; /* size in bytes */ + size_t elem_size; /* size of element in bytes */ } DynaVec; /*********************************************************************************** - * VECTOR APIS + * VECTOR APIS **********************************************************************************/ /* create vector with default init size */ -DynaVec *create_vector(size_t elem_size); +DynaVec *create_vector(size_t elem_size); + /* with configurable init size */ -DynaVec *create_vector2(size_t elem_size, size_t init_num_elems); +DynaVec *create_vector2(size_t elem_size, size_t init_num_elems); + /* with configurable init size and elements are initialized with init_val */ -DynaVec *create_vector3(size_t elem_size, size_t init_num_elems, void *init_val); +DynaVec *create_vector3(size_t elem_size, size_t init_num_elems, void *init_val); + /* copy content from existing vector */ -DynaVec *create_vector_copy(DynaVec *src); +DynaVec *create_vector_copy(DynaVec *src); -void destroy_vector(DynaVec *); +void destroy_vector(DynaVec *); /* * Please feel free to extended APIs. * Refer to std::vector semantic */ -void vec_push_back(DynaVec *vec, const void *elem_ptr); -void vec_pop_back(DynaVec *vec); -void *vec_at(const DynaVec *vec, size_t index); /* NOTICE: No Boundary Check */ -void *vec_back(const DynaVec *vec); -size_t vec_size(const DynaVec *vec); /* Number of elements in vector */ +void vec_push_back(DynaVec *vec, const void *elem_ptr); +void vec_pop_back(DynaVec *vec); +void *vec_at(const DynaVec *vec, size_t index); /* NOTICE: No Boundary + * Check */ +void *vec_back(const DynaVec *vec); +size_t vec_size(const DynaVec *vec); /* Number of elements in vector */ -#endif /* DYNAVEC_H */ +#endif /* DYNAVEC_H */ diff --git a/contrib/babelfishpg_tsql/src/err_handler.c b/contrib/babelfishpg_tsql/src/err_handler.c index cfb06551d2..91cdad3554 100644 --- a/contrib/babelfishpg_tsql/src/err_handler.c +++ b/contrib/babelfishpg_tsql/src/err_handler.c @@ -13,14 +13,14 @@ PG_FUNCTION_INFO_V1(babel_list_mapped_error_deprecated_in_2_2_0); /* * Certain tsql error code can behave differently depending on when it is - * raised or what operations were being executed. + * raised or what operations were being executed. * For example, tsql error code 547 can behave in 2 different ways: * 1. Error code 547 will behave as if it is statement terminating error if * It is raised when DML was being executed. * 2. Same error code will behave as transaction aborting error for any other cases. - * - * Scenario described in point no. 1 is happening probably because another tsql error - * token (i.e. 3621) also being raised after original token. But Babelfish does not + * + * Scenario described in point no. 1 is happening probably because another tsql error + * token (i.e. 3621) also being raised after original token. But Babelfish does not * have support to raise multiple token. * * So, This function override_txn_behaviour could be used to override behaviour of @@ -31,37 +31,43 @@ PG_FUNCTION_INFO_V1(babel_list_mapped_error_deprecated_in_2_2_0); * flag & CUR_BATCH_ABORTING_ERROR (0x02) --> current batch terminating * flag & TXN_ABORTING_ERROR (0x04) --> transaction aborting * flag & IGNORE_XACT_ERROR (0x08) --> ignore xact_abort - */ -uint8_t + */ +uint8_t override_txn_behaviour(PLtsql_stmt *stmt) { - uint8_t override_flag = 0; + uint8_t override_flag = 0; if (!stmt) return 0; + /* - * If tsql error code 547 is raised while executing DML statement - * then error code should behave as if it is statement terminating - * error. + * If tsql error code 547 is raised while executing DML statement then + * error code should behave as if it is statement terminating error. */ if (latest_error_code == SQL_ERROR_547 && stmt->cmd_type == PLTSQL_STMT_EXECSQL) { PLtsql_expr *expr = ((PLtsql_stmt_execsql *) stmt)->sqlstmt; + if (expr && expr->plan) { - ListCell *lc; - /* Below loop will iterate one time only for every statement in the batch. */ + ListCell *lc; + + /* + * Below loop will iterate one time only for every statement in + * the batch. + */ foreach(lc, SPI_plan_get_plan_sources(expr->plan)) { CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc); + if (plansource && plansource->commandTag && (plansource->commandTag == CMDTAG_INSERT || - plansource->commandTag == CMDTAG_UPDATE || - plansource->commandTag == CMDTAG_DELETE)) - { - override_flag |= IGNORABLE_ERROR; - } + plansource->commandTag == CMDTAG_UPDATE || + plansource->commandTag == CMDTAG_DELETE)) + { + override_flag |= IGNORABLE_ERROR; + } } } } @@ -69,11 +75,12 @@ override_txn_behaviour(PLtsql_stmt *stmt) } /* error could be ignored within exec_stmt_execsql */ -bool is_ignorable_error(int pg_error_code, uint8_t override_flag) +bool +is_ignorable_error(int pg_error_code, uint8_t override_flag) { /* - * Check if override transactional behaviour flag is set, - * And use the same to determine the transactional behaviour. + * Check if override transactional behaviour flag is set, And use the same + * to determine the transactional behaviour. */ if (override_flag) { @@ -83,11 +90,11 @@ bool is_ignorable_error(int pg_error_code, uint8_t override_flag) return false; } - /* - * As of now, Trying do classification based on SQL error code. - * If it does not work then doing classification based on pg_error_code. + /* + * As of now, Trying do classification based on SQL error code. If it does + * not work then doing classification based on pg_error_code. */ - switch(latest_error_code) + switch (latest_error_code) { case SQL_ERROR_232: case SQL_ERROR_3902: @@ -124,31 +131,32 @@ bool is_ignorable_error(int pg_error_code, uint8_t override_flag) case SQL_ERROR_8145: case SQL_ERROR_8146: case SQL_ERROR_213: - { - elog(DEBUG1, "TSQL TXN is_ignorable_error %d", latest_error_code); - return true; - } + { + elog(DEBUG1, "TSQL TXN is_ignorable_error %d", latest_error_code); + return true; + } default: break; } - switch(pg_error_code) - { + switch (pg_error_code) + { case ERRCODE_PLTSQL_RAISERROR: - { - elog(DEBUG1, "TSQL TXN is_ignorable_error raise error %d", latest_error_code); - return true; - } - default: - return false; - } + { + elog(DEBUG1, "TSQL TXN is_ignorable_error raise error %d", latest_error_code); + return true; + } + default: + return false; + } } /* Tsql errors which terminate only the batch where error was raised */ -bool is_current_batch_aborting_error(int pg_error_code, uint8_t override_flag) +bool +is_current_batch_aborting_error(int pg_error_code, uint8_t override_flag) { /* - * Check if override transactional behaviour flag is set, - * And use the same to determine the transactional behaviour. + * Check if override transactional behaviour flag is set, And use the same + * to determine the transactional behaviour. */ if (override_flag) { @@ -158,31 +166,32 @@ bool is_current_batch_aborting_error(int pg_error_code, uint8_t override_flag) return false; } - /* - * As of now, Trying do classification based on SQL error code. - * If it does not work then doing classification based on pg_error_code. + /* + * As of now, Trying do classification based on SQL error code. If it does + * not work then doing classification based on pg_error_code. */ - switch(latest_error_code) + switch (latest_error_code) { case SQL_ERROR_306: case SQL_ERROR_477: case SQL_ERROR_1752: case SQL_ERROR_10793: - { - elog(DEBUG1, "TSQL TXN is_current_batch_aborting_error %d", latest_error_code); - return true; - } + { + elog(DEBUG1, "TSQL TXN is_current_batch_aborting_error %d", latest_error_code); + return true; + } default: return false; } } /* Tsql errors which lead to batch abort and transaction rollback */ -bool is_batch_txn_aborting_error(int pg_error_code, uint8_t override_flag) +bool +is_batch_txn_aborting_error(int pg_error_code, uint8_t override_flag) { /* - * Check if override transactional behaviour flag is set, - * And use the same to determine the transactional behaviour. + * Check if override transactional behaviour flag is set, And use the same + * to determine the transactional behaviour. */ if (override_flag) { @@ -192,11 +201,11 @@ bool is_batch_txn_aborting_error(int pg_error_code, uint8_t override_flag) return false; } - /* - * As of now, Trying do classification based on SQL error code. - * If it does not work then doing classification based on pg_error_code. + /* + * As of now, Trying do classification based on SQL error code. If it does + * not work then doing classification based on pg_error_code. */ - switch(latest_error_code) + switch (latest_error_code) { case SQL_ERROR_628: case SQL_ERROR_3723: @@ -238,21 +247,22 @@ bool is_batch_txn_aborting_error(int pg_error_code, uint8_t override_flag) case SQL_ERROR_9451: case SQL_ERROR_11701: case SQL_ERROR_3616: - case SQL_ERROR_911: - { - elog(DEBUG1, "TSQL TXN is_batch_txn_aborting_error %d", latest_error_code); - return true; - } + case SQL_ERROR_911: + { + elog(DEBUG1, "TSQL TXN is_batch_txn_aborting_error %d", latest_error_code); + return true; + } default: return false; } } -bool ignore_xact_abort_error(int pg_error_code, uint8_t override_flag) +bool +ignore_xact_abort_error(int pg_error_code, uint8_t override_flag) { /* - * Check if override transactional behaviour flag is set, - * And use the same to determine the transactional behaviour. + * Check if override transactional behaviour flag is set, And use the same + * to determine the transactional behaviour. */ if (override_flag) { @@ -262,11 +272,11 @@ bool ignore_xact_abort_error(int pg_error_code, uint8_t override_flag) return false; } - /* - * As of now, Trying do classification based on SQL error code. - * If it does not work then doing classification based on pg_error_code. + /* + * As of now, Trying do classification based on SQL error code. If it does + * not work then doing classification based on pg_error_code. */ - switch(latest_error_code) + switch (latest_error_code) { case SQL_ERROR_3701: case SQL_ERROR_129: @@ -287,14 +297,14 @@ bool ignore_xact_abort_error(int pg_error_code, uint8_t override_flag) case SQL_ERROR_487: case SQL_ERROR_153: case SQL_ERROR_11709: - { - elog(DEBUG1, "TSQL TXN ignore_xact_abort_error %d", latest_error_code); - return true; - } + { + elog(DEBUG1, "TSQL TXN ignore_xact_abort_error %d", latest_error_code); + return true; + } default: break; } - switch(pg_error_code) + switch (pg_error_code) { case ERRCODE_PLTSQL_RAISERROR: return true; @@ -306,9 +316,10 @@ bool ignore_xact_abort_error(int pg_error_code, uint8_t override_flag) /* * Compile time errors which abort transactions by default */ -bool is_txn_aborting_compilation_error(int sql_error_code) +bool +is_txn_aborting_compilation_error(int sql_error_code) { - switch(sql_error_code) + switch (sql_error_code) { default: break; @@ -320,18 +331,19 @@ bool is_txn_aborting_compilation_error(int sql_error_code) * Compile time error which abort transactions when xact_abort * is set to ON */ -bool is_xact_abort_txn_compilation_error(int sql_error_code) +bool +is_xact_abort_txn_compilation_error(int sql_error_code) { - switch(sql_error_code) + switch (sql_error_code) { case SQL_ERROR_2747: case SQL_ERROR_8159: case SQL_ERROR_11717: case SQL_ERROR_16948: - { - elog(DEBUG1, "TSQL TXN is_xact_abort_txn_compilation_error %d", latest_error_code); - return true; - } + { + elog(DEBUG1, "TSQL TXN is_xact_abort_txn_compilation_error %d", latest_error_code); + return true; + } default: break; } @@ -339,34 +351,39 @@ bool is_xact_abort_txn_compilation_error(int sql_error_code) } /* translate PG error code to error code */ -bool get_tsql_error_code(ErrorData *edata, int *last_error) +bool +get_tsql_error_code(ErrorData *edata, int *last_error) { - /* xxx: if (*pltsql_protocol_plugin_ptr)->get_tsql_error is initialised then use it - * directly. If it is not initialised or in other words, babelfishpg_tds is not loaded - * then use older approach. - * But we need to handle error neatly when only babelfishpg_tsql is loaded. We will address that case - * as part of BABEL-1204. - */ + /* + * xxx: if (*pltsql_protocol_plugin_ptr)->get_tsql_error is initialised + * then use it directly. If it is not initialised or in other words, + * babelfishpg_tds is not loaded then use older approach. But we need to + * handle error neatly when only babelfishpg_tsql is loaded. We will + * address that case as part of BABEL-1204. + */ *last_error = ERRCODE_PLTSQL_ERROR_NOT_MAPPED; - if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->get_tsql_error) - { - int tsql_error_sev, tsql_error_state; - return (*pltsql_protocol_plugin_ptr)->get_tsql_error (edata, - last_error, - &tsql_error_sev, - &tsql_error_state, - "babelfishpg_tsql"); - } + if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->get_tsql_error) + { + int tsql_error_sev, + tsql_error_state; + + return (*pltsql_protocol_plugin_ptr)->get_tsql_error(edata, + last_error, + &tsql_error_sev, + &tsql_error_state, + "babelfishpg_tsql"); + } return false; } static int get_err_lineno(const char *context) { - int lineno = -1; + int lineno = -1; const char *pattern1 = "line "; const char *pattern2 = " at"; - char *start, *end; + char *start, + *end; if ((start = strstr(context, pattern1))) { @@ -379,14 +396,14 @@ get_err_lineno(const char *context) return lineno; } -/* +/* * Do error mapping to get the mapped error info, including error number, error * severity and error state. */ static void do_error_mapping(PLtsql_estate_err *err) { - if (!(*pltsql_protocol_plugin_ptr) || + if (!(*pltsql_protocol_plugin_ptr) || !(*pltsql_protocol_plugin_ptr)->get_tsql_error) return; @@ -398,7 +415,7 @@ do_error_mapping(PLtsql_estate_err *err) "babelfishpg_tsql"); } -/* +/* * If there is no error in current estate, try to check previous estates one by * one, in case we are inside a previous estate's CATCH block. */ @@ -422,17 +439,18 @@ Datum babel_list_mapped_error_deprecated_in_2_2_0(PG_FUNCTION_ARGS) { /* To hold the list of supported SQL error code */ - int *list = NULL; + int *list = NULL; /* SRF related things to keep enough state between calls */ FuncCallContext *funcctx; - int call_cntr; - int max_calls; + int call_cntr; + int max_calls; /* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL()) { - MemoryContext oldcontext; + MemoryContext oldcontext; + funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->get_mapped_error_list) @@ -465,11 +483,11 @@ babel_list_mapped_error(PG_FUNCTION_ARGS) ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; Tuplestorestate *tupstore; TupleDesc tupdesc; - int call_cntr = 0; - MemoryContext oldcontext; - MemoryContext per_query_ctx; - Oid nspoid = get_namespace_oid("sys", false); - Oid sys_varcharoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, CStringGetDatum("nvarchar"), ObjectIdGetDatum(nspoid)); + int call_cntr = 0; + MemoryContext oldcontext; + MemoryContext per_query_ctx; + Oid nspoid = get_namespace_oid("sys", false); + Oid sys_varcharoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, CStringGetDatum("nvarchar"), ObjectIdGetDatum(nspoid)); /* check to see if caller supports us returning a tuplestore */ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) @@ -529,8 +547,8 @@ babel_list_mapped_error(PG_FUNCTION_ARGS) return (Datum) 0; } -/* - * ERROR_*() functions +/* + * ERROR_*() functions */ PG_FUNCTION_INFO_V1(pltsql_error_line); PG_FUNCTION_INFO_V1(pltsql_error_message); @@ -543,7 +561,7 @@ Datum pltsql_error_line(PG_FUNCTION_ARGS) { PLtsql_execstate *estate; - int lineno = -1; + int lineno = -1; if (exec_state_call_stack == NULL) PG_RETURN_NULL(); @@ -555,8 +573,8 @@ pltsql_error_line(PG_FUNCTION_ARGS) PG_RETURN_NULL(); /* - * TODO: This function is just a temporary workaround for error line number. - * We should cache line number as soon as an error is raised. + * TODO: This function is just a temporary workaround for error line + * number. We should cache line number as soon as an error is raised. */ lineno = get_err_lineno(estate->cur_error->error->context); @@ -571,7 +589,7 @@ pltsql_error_message(PG_FUNCTION_ARGS) { PLtsql_execstate *estate; StringInfoData temp; - void *message = NULL; + void *message = NULL; if (exec_state_call_stack == NULL) PG_RETURN_NULL(); @@ -584,7 +602,7 @@ pltsql_error_message(PG_FUNCTION_ARGS) initStringInfo(&temp); appendStringInfoString(&temp, estate->cur_error->error->message); - message = (*common_utility_plugin_ptr->tsql_varchar_input)(temp.data, temp.len, -1); + message = (*common_utility_plugin_ptr->tsql_varchar_input) (temp.data, temp.len, -1); pfree(temp.data); @@ -617,7 +635,7 @@ pltsql_error_procedure(PG_FUNCTION_ARGS) { PLtsql_execstate *estate; StringInfoData temp; - void *procedure = NULL; + void *procedure = NULL; if (exec_state_call_stack == NULL) PG_RETURN_NULL(); @@ -630,7 +648,7 @@ pltsql_error_procedure(PG_FUNCTION_ARGS) initStringInfo(&temp); appendStringInfoString(&temp, estate->cur_error->procedure); - procedure = (*common_utility_plugin_ptr->tsql_varchar_input)(temp.data, temp.len, -1); + procedure = (*common_utility_plugin_ptr->tsql_varchar_input) (temp.data, temp.len, -1); pfree(temp.data); diff --git a/contrib/babelfishpg_tsql/src/err_handler.h b/contrib/babelfishpg_tsql/src/err_handler.h index 44c3588b04..dfd505dda8 100644 --- a/contrib/babelfishpg_tsql/src/err_handler.h +++ b/contrib/babelfishpg_tsql/src/err_handler.h @@ -4,7 +4,7 @@ #include "pltsql.h" #include "postgres.h" -/* +/* * Below macros are useful in building flag to override the behaviour of certain tsql * error code for certain situation. */ @@ -13,17 +13,18 @@ #define TXN_ABORTING_ERROR 0x04 //transaction aborting #define IGNORE_XACT_ERROR 0x08 //ignore xact_abort flag -extern int CurrentLineNumber; /* Holds the Line No. of the current query being executed. */ -bool is_ignorable_error(int pg_error_code, uint8_t override_flag); -bool get_tsql_error_code(ErrorData *edata, int *last_error); -bool is_current_batch_aborting_error(int pg_error_code, uint8_t override_flag); -bool is_batch_txn_aborting_error(int pg_error_code, uint8_t override_flag); -bool ignore_xact_abort_error(int pg_error_code, uint8_t override_flag); -bool is_txn_aborting_compilation_error(int sql_error_code); -bool is_xact_abort_txn_compilation_error(int sql_error_code); +extern int CurrentLineNumber; /* Holds the Line No. of the current query + * being executed. */ +bool is_ignorable_error(int pg_error_code, uint8_t override_flag); +bool get_tsql_error_code(ErrorData *edata, int *last_error); +bool is_current_batch_aborting_error(int pg_error_code, uint8_t override_flag); +bool is_batch_txn_aborting_error(int pg_error_code, uint8_t override_flag); +bool ignore_xact_abort_error(int pg_error_code, uint8_t override_flag); +bool is_txn_aborting_compilation_error(int sql_error_code); +bool is_xact_abort_txn_compilation_error(int sql_error_code); /* Function to override behaviour of any error code for different situation.*/ -uint8_t override_txn_behaviour(PLtsql_stmt *stmt); +uint8_t override_txn_behaviour(PLtsql_stmt *stmt); #endif diff --git a/contrib/babelfishpg_tsql/src/format.c b/contrib/babelfishpg_tsql/src/format.c index a70f413028..5ad464c5a3 100644 --- a/contrib/babelfishpg_tsql/src/format.c +++ b/contrib/babelfishpg_tsql/src/format.c @@ -32,7 +32,7 @@ #include "catalog/pg_collation.h" -size_t CULTURE_COUNT = sizeof(datetimeformats)/sizeof(datetimeformat); +size_t CULTURE_COUNT = sizeof(datetimeformats) / sizeof(datetimeformat); PG_FUNCTION_INFO_V1(format_datetime); PG_FUNCTION_INFO_V1(format_numeric); @@ -43,15 +43,15 @@ PG_FUNCTION_INFO_V1(format_numeric); Datum format_datetime(PG_FUNCTION_ARGS) { - Datum arg_value; - Oid arg_type_oid; - const char *format_pattern; - const char *culture; - const char *data_type; - int fmt_res = 0; - const char *data_str; - StringInfo buf; - VarChar *result; + Datum arg_value; + Oid arg_type_oid; + const char *format_pattern; + const char *culture; + const char *data_type; + int fmt_res = 0; + const char *data_str; + StringInfo buf; + VarChar *result; if (PG_ARGISNULL(0)) PG_RETURN_NULL(); @@ -129,22 +129,23 @@ format_datetime(PG_FUNCTION_ARGS) switch (arg_type_oid) { - case TIMEOID: - data_to_char(DirectFunctionCall1(time_interval, arg_value), TIMEOID, buf); - break; - case TIMESTAMPOID: - data_to_char(arg_value, TIMESTAMPOID, buf); - break; - default: - pfree(buf); - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("The data type of the first argument is invalid/currently not supported."), - errhint("Convert it to other datatype and try again."))); - break; + case TIMEOID: + data_to_char(DirectFunctionCall1(time_interval, arg_value), TIMEOID, buf); + break; + case TIMESTAMPOID: + data_to_char(arg_value, TIMESTAMPOID, buf); + break; + default: + pfree(buf); + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("The data type of the first argument is invalid/currently not supported."), + errhint("Convert it to other datatype and try again."))); + break; } - result = (*common_utility_plugin_ptr->tsql_varchar_input)(buf->data, buf->len, -1); + result = (*common_utility_plugin_ptr->tsql_varchar_input) (buf->data, buf->len, -1); + pfree(buf->data); pfree(buf); @@ -157,22 +158,22 @@ format_datetime(PG_FUNCTION_ARGS) Datum format_numeric(PG_FUNCTION_ARGS) { - Datum datum_val = PG_GETARG_DATUM(0); - char *format_pattern; - char *data_type; - StringInfo format_res = makeStringInfo(); - Numeric numeric_val; - Oid arg_type_oid; - char *culture; - char *valid_culture; - char pattern; - char *precision_string; - int sig_len; - char *temp_pattern; - char real_pattern[120]; - char upper_pattern; - const char *format_re = "^[cdefgnprxCDEFGNPRX]{1}[0-9]*$"; - VarChar *result; + Datum datum_val = PG_GETARG_DATUM(0); + char *format_pattern; + char *data_type; + StringInfo format_res = makeStringInfo(); + Numeric numeric_val; + Oid arg_type_oid; + char *culture; + char *valid_culture; + char pattern; + char *precision_string; + int sig_len; + char *temp_pattern; + char real_pattern[120]; + char upper_pattern; + const char *format_re = "^[cdefgnprxCDEFGNPRX]{1}[0-9]*$"; + VarChar *result; if (PG_ARGISNULL(0)) PG_RETURN_NULL(); @@ -194,36 +195,70 @@ format_numeric(PG_FUNCTION_ARGS) pattern = format_pattern[0]; upper_pattern = toupper(pattern); - precision_string = TextDatumGetCString(DirectFunctionCall2(text_substr_no_len, PG_GETARG_DATUM(1), Int32GetDatum((int32)2))); + precision_string = TextDatumGetCString(DirectFunctionCall2(text_substr_no_len, PG_GETARG_DATUM(1), Int32GetDatum((int32) 2))); data_type = text_to_cstring(PG_GETARG_TEXT_P(3)); arg_type_oid = get_fn_expr_argtype(fcinfo->flinfo, 0); switch (arg_type_oid) { - case INT2OID: - case INT4OID: - case INT8OID: - numeric_val = int64_to_numeric(PG_GETARG_INT64(0)); - break; - case NUMERICOID: - numeric_val = PG_GETARG_NUMERIC(0); - break; - case FLOAT4OID: - set_config_option("extra_float_digits", "1", PGC_USERSET, PGC_S_SESSION, GUC_ACTION_LOCAL, true, 0, false); - - if (upper_pattern == 'R') - { - sig_len = PG_GETARG_INT32(4); + case INT2OID: + case INT4OID: + case INT8OID: + numeric_val = int64_to_numeric(PG_GETARG_INT64(0)); + break; + case NUMERICOID: + numeric_val = PG_GETARG_NUMERIC(0); + break; + case FLOAT4OID: + set_config_option("extra_float_digits", "1", PGC_USERSET, PGC_S_SESSION, GUC_ACTION_LOCAL, true, 0, false); - if (sig_len <= 0) + if (upper_pattern == 'R') { - snprintf(real_pattern, sizeof(real_pattern), "%.*g", 8, DatumGetFloat4(datum_val)); - numeric_val = cstring_to_numeric(real_pattern); + sig_len = PG_GETARG_INT32(4); + + if (sig_len <= 0) + { + snprintf(real_pattern, sizeof(real_pattern), "%.*g", 8, DatumGetFloat4(datum_val)); + numeric_val = cstring_to_numeric(real_pattern); + } + else + { + if (sig_len > 6) + { + temp_pattern = "9D99999999EEEE"; + } + else + { + temp_pattern = "9D999999EEEE"; + } + + resetStringInfo(format_res); + appendStringInfoString(format_res, temp_pattern); + + float4_data_to_char(format_res, datum_val); + + if (format_res->len > 0) + { + if (isupper(pattern)) + { + regexp_replace(format_res->data, "[.]{0,1}0*[eE]", "E", "i"); + } + + result = (*common_utility_plugin_ptr->tsql_varchar_input) (format_res->data, format_res->len, -1); + + pfree(format_res->data); + pfree(format_res); + PG_RETURN_VARCHAR_P(result); + } + pfree(format_res->data); + pfree(format_res); + PG_RETURN_NULL(); + } } else { - if (sig_len > 6) + if (upper_pattern == 'E' || upper_pattern == 'G') { temp_pattern = "9D99999999EEEE"; } @@ -232,85 +267,53 @@ format_numeric(PG_FUNCTION_ARGS) temp_pattern = "9D999999EEEE"; } - resetStringInfo(format_res); appendStringInfoString(format_res, temp_pattern); float4_data_to_char(format_res, datum_val); - if (format_res->len > 0) - { - if (isupper(pattern)) - { - regexp_replace(format_res->data, "[.]{0,1}0*[eE]", "E", "i"); - } + numeric_val = cstring_to_numeric(format_res->data); + } + break; + case FLOAT8OID: + set_config_option("extra_float_digits", "1", PGC_USERSET, PGC_S_SESSION, GUC_ACTION_LOCAL, true, 0, false); - result = (*common_utility_plugin_ptr->tsql_varchar_input)(format_res->data, format_res->len, -1); - pfree(format_res->data); - pfree(format_res); - PG_RETURN_VARCHAR_P(result); - } + if (upper_pattern == 'R') + { pfree(format_res->data); pfree(format_res); - PG_RETURN_NULL(); + + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Format \"R\" is currently not supported for FLOAT datatype"))); } - } - else - { - if (upper_pattern == 'E' || upper_pattern == 'G') + else if (upper_pattern == 'E' || upper_pattern == 'G') { - temp_pattern = "9D99999999EEEE"; + appendStringInfoString(format_res, "9D9999999999999999EEEE"); + float8_data_to_char(format_res, datum_val); + numeric_val = cstring_to_numeric(format_res->data); } else { - temp_pattern = "9D999999EEEE"; + numeric_val = DatumGetNumeric(DirectFunctionCall1(float8_numeric, datum_val)); } - - appendStringInfoString(format_res, temp_pattern); - - float4_data_to_char(format_res, datum_val); - - numeric_val = cstring_to_numeric(format_res->data); - } - break; - case FLOAT8OID: - set_config_option("extra_float_digits", "1", PGC_USERSET, PGC_S_SESSION, GUC_ACTION_LOCAL, true, 0, false); - - if (upper_pattern == 'R') - { + break; + default: pfree(format_res->data); pfree(format_res); - ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("Format \"R\" is currently not supported for FLOAT datatype"))); - } - else if (upper_pattern == 'E' || upper_pattern == 'G') - { - appendStringInfoString(format_res, "9D9999999999999999EEEE"); - float8_data_to_char(format_res, datum_val); - numeric_val = cstring_to_numeric(format_res->data); - } - else - { - numeric_val = DatumGetNumeric(DirectFunctionCall1(float8_numeric, datum_val)); - } - break; - default: - pfree(format_res->data); - pfree(format_res); - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("The data type of the first argument is invalid."), - errdetail("Use of invalid value parameter."), - errhint("Convert it to valid datatype and try again."))); - break; + errmsg("The data type of the first argument is invalid."), + errdetail("Use of invalid value parameter."), + errhint("Convert it to valid datatype and try again."))); + break; } format_numeric_handler(datum_val, numeric_val, format_res, pattern, precision_string, arg_type_oid, culture, valid_culture, data_type); if (format_res->len > 0) { - result = (*common_utility_plugin_ptr->tsql_varchar_input)(format_res->data, format_res->len, -1); + result = (*common_utility_plugin_ptr->tsql_varchar_input) (format_res->data, format_res->len, -1); + pfree(format_res->data); pfree(format_res); PG_RETURN_VARCHAR_P(result); @@ -323,43 +326,44 @@ format_numeric(PG_FUNCTION_ARGS) static void format_numeric_handler(Datum value, Numeric numeric_val, StringInfo format_res, char pattern, char *precision_string, - Oid arg_type_oid, char *culture, char *valid_culture, char *data_type) + Oid arg_type_oid, char *culture, char *valid_culture, char *data_type) { - char upper_pattern = toupper(pattern); + char upper_pattern = toupper(pattern); + resetStringInfo(format_res); switch (upper_pattern) { - case 'C': - if (set_culture(valid_culture, "LC_MONETARY", culture) == 1) - format_currency(numeric_val, format_res, upper_pattern, precision_string, culture); - break; - case 'D': - format_decimal(numeric_val, format_res, upper_pattern, precision_string, arg_type_oid); - break; - case 'F': - format_fixed_point(numeric_val, format_res, upper_pattern, precision_string); - break; - case 'N': - format_number(numeric_val, format_res, upper_pattern, precision_string); - break; - case 'P': - format_percent(numeric_val, format_res, upper_pattern, precision_string); - break; - case 'X': - format_hexadecimal(value, format_res, pattern, precision_string, arg_type_oid); - break; - case 'E': - format_exponential(numeric_val, format_res, pattern, precision_string); - break; - case 'G': - format_compact(numeric_val, format_res, pattern, precision_string, data_type, arg_type_oid); - break; - case 'R': - format_roundtrip(value, numeric_val, format_res, pattern, data_type, arg_type_oid); - break; - default: - break; + case 'C': + if (set_culture(valid_culture, "LC_MONETARY", culture) == 1) + format_currency(numeric_val, format_res, upper_pattern, precision_string, culture); + break; + case 'D': + format_decimal(numeric_val, format_res, upper_pattern, precision_string, arg_type_oid); + break; + case 'F': + format_fixed_point(numeric_val, format_res, upper_pattern, precision_string); + break; + case 'N': + format_number(numeric_val, format_res, upper_pattern, precision_string); + break; + case 'P': + format_percent(numeric_val, format_res, upper_pattern, precision_string); + break; + case 'X': + format_hexadecimal(value, format_res, pattern, precision_string, arg_type_oid); + break; + case 'E': + format_exponential(numeric_val, format_res, pattern, precision_string); + break; + case 'G': + format_compact(numeric_val, format_res, pattern, precision_string, data_type, arg_type_oid); + break; + case 'R': + format_roundtrip(value, numeric_val, format_res, pattern, data_type, arg_type_oid); + break; + default: + break; } } @@ -394,11 +398,11 @@ set_culture(char *valid_culture, const char *config_name, const char *culture) static char * format_validate_and_culture(const char *culture, const char *config_name) { - int culture_len = 0; - char *token; - char *temp_res; - int locale_pos = -1; - char *culture_temp; + int culture_len = 0; + char *token; + char *temp_res; + int locale_pos = -1; + char *culture_temp; if (culture != NULL) culture_len = strlen(culture); @@ -414,14 +418,16 @@ format_validate_and_culture(const char *culture, const char *config_name) if (strchr(culture_temp, '-') != NULL) { token = strtok(culture_temp, "-"); - for (char *c = token; *c; ++c) *c = tolower(*c); + for (char *c = token; *c; ++c) + *c = tolower(*c); memcpy(temp_res, token, strlen(token)); strncat(temp_res, "_", 2); if (token != NULL) { token = strtok(NULL, "-"); - for (char *c = token; *c; ++c) *c = toupper(*c); + for (char *c = token; *c; ++c) + *c = toupper(*c); strncat(temp_res, token, culture_len); temp_res[culture_len] = '\0'; } @@ -429,23 +435,23 @@ format_validate_and_culture(const char *culture, const char *config_name) { pfree(temp_res); ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("The culture parameter \"%s\" provided in the function call is not supported.", culture), - errhint("Invalid/Unsupported culture value.")));; + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("The culture parameter \"%s\" provided in the function call is not supported.", culture), + errhint("Invalid/Unsupported culture value.")));; } } else { pfree(temp_res); ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("The culture parameter \"%s\" provided in the function call is not supported.", culture), - errhint("Invalid/Unsupported culture value.")));; + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("The culture parameter \"%s\" provided in the function call is not supported.", culture), + errhint("Invalid/Unsupported culture value.")));; } pfree(culture_temp); - locale_pos = tsql_find_locale((const char *)temp_res); + locale_pos = tsql_find_locale((const char *) temp_res); if (locale_pos >= 0 && set_culture(temp_res, config_name, culture) == 1) { @@ -472,11 +478,11 @@ format_validate_and_culture(const char *culture, const char *config_name) static int match(const char *string, const char *pattern) { - int status; - text *regex = cstring_to_text(pattern); + int status; + text *regex = cstring_to_text(pattern); status = RE_compile_and_execute(regex, (char *) string, strlen(string), REG_ADVANCED, DEFAULT_COLLATION_OID, 0, NULL); - + pfree(regex); return status; } @@ -490,13 +496,13 @@ match(const char *string, const char *pattern) static int format_datetimeformats(StringInfo buf, const char *format_pattern, const char *culture, const char *data_type, const char *data_val) { - int j = 0; - int flag = 0; - char *pattern; - int milli_time_res; - int time_res; - const char *milli_time_re = "^[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}.[0-9]{1,7}$"; - const char *time_re = "^[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}$"; + int j = 0; + int flag = 0; + char *pattern; + int milli_time_res; + int time_res; + const char *milli_time_re = "^[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}.[0-9]{1,7}$"; + const char *time_re = "^[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}$"; if (pg_strcasecmp(format_pattern, "O") == 0) { @@ -510,42 +516,42 @@ format_datetimeformats(StringInfo buf, const char *format_pattern, const char *c switch (format_pattern[0]) { - case 'c': - case 't': - case 'T': - if (milli_time_res == 1) - { + case 'c': + case 't': + case 'T': + if (milli_time_res == 1) + { + appendStringInfoString(buf, "HH24\":\"MI\":\"ss\".\"FF6"); + } + else if (time_res == 1) + { + appendStringInfoString(buf, "HH24\":\"MI\":\"ss"); + } + else + { + return 0; + } + break; + case 'g': + if (milli_time_res == 1) + { + return -1; + } + else if (time_res == 1) + { + appendStringInfoString(buf, "HH24\":\"MI\":\"ss"); + } + else + { + return 0; + } + break; + case 'G': appendStringInfoString(buf, "HH24\":\"MI\":\"ss\".\"FF6"); - } - else if (time_res == 1) - { - appendStringInfoString(buf, "HH24\":\"MI\":\"ss"); - } - else - { - return 0; - } - break; - case 'g': - if (milli_time_res == 1) - { - return -1; - } - else if (time_res == 1) - { - appendStringInfoString(buf, "HH24\":\"MI\":\"ss"); - } - else - { + break; + default: return 0; - } - break; - case 'G': - appendStringInfoString(buf, "HH24\":\"MI\":\"ss\".\"FF6"); - break; - default: - return 0; - break; + break; } return 1; } @@ -558,75 +564,75 @@ format_datetimeformats(StringInfo buf, const char *format_pattern, const char *c flag = 1; switch (format_pattern[0]) { - case 'd': - pattern = datetimeformats[j].pg_shortdatepattern; - appendStringInfoString(buf, pattern); - break; - case 'D': - pattern = datetimeformats[j].pg_longdatepattern; - appendStringInfoString(buf, pattern); - break; - case 'f': - pattern = datetimeformats[j].pg_longdatepattern; - appendStringInfoString(buf, pattern); - appendStringInfoString(buf, " "); - appendStringInfoString(buf, datetimeformats[j].pg_shorttimepattern); - break; - case 'F': - pattern = datetimeformats[j].pg_fulldatetimepattern; - appendStringInfoString(buf, pattern); - break; - case 'g': - pattern = datetimeformats[j].pg_shortdatepattern; - appendStringInfoString(buf, pattern); - appendStringInfoString(buf, " "); - appendStringInfoString(buf, datetimeformats[j].pg_shorttimepattern); - break; - case '\0': - case 'G': - pattern = datetimeformats[j].pg_shortdatepattern; - appendStringInfoString(buf, pattern); - appendStringInfoString(buf, " "); - appendStringInfoString(buf, datetimeformats[j].pg_longtimepattern); - break; - case 't': - pattern = datetimeformats[j].pg_shorttimepattern; - appendStringInfoString(buf, pattern); - break; - case 'T': - pattern = datetimeformats[j].pg_longtimepattern; - appendStringInfoString(buf, pattern); - break; - case 'm': - case 'M': - pattern = datetimeformats[j].pg_monthdaypattern; - appendStringInfoString(buf, pattern); - break; - case 'y': - case 'Y': - pattern = datetimeformats[j].pg_yearmonthpattern; - appendStringInfoString(buf, pattern); - break; - case 'r': - case 'R': - pattern = "Dy, dd Mon yyyy HH24\":\"MI\":\"ss \"GMT\""; - appendStringInfoString(buf, pattern); - break; - case 's': - pattern = "yyyy\"-\"MM\"-\"dd\"T\"HH24\":\"MI\":\"ss"; - appendStringInfoString(buf, pattern); - break; - case 'u': - pattern = "yyyy\"-\"MM\"-\"dd HH24\":\"MI\":\"ss\"Z\""; - appendStringInfoString(buf, pattern); - break; - case 'U': - pattern = datetimeformats[j].pg_fulldatetimepattern; - appendStringInfoString(buf, pattern); - break; - default: - return 0; - break; + case 'd': + pattern = datetimeformats[j].pg_shortdatepattern; + appendStringInfoString(buf, pattern); + break; + case 'D': + pattern = datetimeformats[j].pg_longdatepattern; + appendStringInfoString(buf, pattern); + break; + case 'f': + pattern = datetimeformats[j].pg_longdatepattern; + appendStringInfoString(buf, pattern); + appendStringInfoString(buf, " "); + appendStringInfoString(buf, datetimeformats[j].pg_shorttimepattern); + break; + case 'F': + pattern = datetimeformats[j].pg_fulldatetimepattern; + appendStringInfoString(buf, pattern); + break; + case 'g': + pattern = datetimeformats[j].pg_shortdatepattern; + appendStringInfoString(buf, pattern); + appendStringInfoString(buf, " "); + appendStringInfoString(buf, datetimeformats[j].pg_shorttimepattern); + break; + case '\0': + case 'G': + pattern = datetimeformats[j].pg_shortdatepattern; + appendStringInfoString(buf, pattern); + appendStringInfoString(buf, " "); + appendStringInfoString(buf, datetimeformats[j].pg_longtimepattern); + break; + case 't': + pattern = datetimeformats[j].pg_shorttimepattern; + appendStringInfoString(buf, pattern); + break; + case 'T': + pattern = datetimeformats[j].pg_longtimepattern; + appendStringInfoString(buf, pattern); + break; + case 'm': + case 'M': + pattern = datetimeformats[j].pg_monthdaypattern; + appendStringInfoString(buf, pattern); + break; + case 'y': + case 'Y': + pattern = datetimeformats[j].pg_yearmonthpattern; + appendStringInfoString(buf, pattern); + break; + case 'r': + case 'R': + pattern = "Dy, dd Mon yyyy HH24\":\"MI\":\"ss \"GMT\""; + appendStringInfoString(buf, pattern); + break; + case 's': + pattern = "yyyy\"-\"MM\"-\"dd\"T\"HH24\":\"MI\":\"ss"; + appendStringInfoString(buf, pattern); + break; + case 'u': + pattern = "yyyy\"-\"MM\"-\"dd HH24\":\"MI\":\"ss\"Z\""; + appendStringInfoString(buf, pattern); + break; + case 'U': + pattern = datetimeformats[j].pg_fulldatetimepattern; + appendStringInfoString(buf, pattern); + break; + default: + return 0; + break; } } } @@ -656,15 +662,15 @@ format_datetimeformats(StringInfo buf, const char *format_pattern, const char *c static int process_format_pattern(StringInfo buf, const char *msg_string, const char *data_type) { - int i = 0; - int bc = 0; - int quotes_found = 0; - int percentile_found = 0; - int escape_found = 0; - int is_time = 0; - int count = 0; + int i = 0; + int bc = 0; + int quotes_found = 0; + int percentile_found = 0; + int escape_found = 0; + int is_time = 0; + int count = 0; - StringInfo str = makeStringInfo(); + StringInfo str = makeStringInfo(); if (msg_string == NULL) { @@ -690,7 +696,7 @@ process_format_pattern(StringInfo buf, const char *msg_string, const char *data_ appendStringInfoChar(str, '\\'); } - appendStringInfoChar(str, msg_string[bc]); + appendStringInfoChar(str, msg_string[bc]); } else { @@ -705,7 +711,7 @@ process_format_pattern(StringInfo buf, const char *msg_string, const char *data_ else { escape_found = 0; - appendStringInfoChar(str, msg_string[bc]); + appendStringInfoChar(str, msg_string[bc]); } } else if (msg_string[bc] == '%') @@ -718,7 +724,7 @@ process_format_pattern(StringInfo buf, const char *msg_string, const char *data_ { escape_found = 0; percentile_found = 0; - appendStringInfoChar(str, msg_string[bc]); + appendStringInfoChar(str, msg_string[bc]); } } else if (msg_string[bc] == 'd') @@ -1145,13 +1151,19 @@ process_format_pattern(StringInfo buf, const char *msg_string, const char *data_ } else { - // Case for one letter meridian - A, P instead of AM/PM - // is not supported by to_char in postgres, so we'll - // return the 2 letter case until an efficient workaround + /* + * Case for one letter meridian - A, P instead of + * AM/PM + */ + /* is not supported by to_char in postgres, so we'll */ + /* + * return the 2 letter case until an efficient + * workaround + */ appendStringInfo(str, "AM"); i = bc + 1; - // Anything longer than 'tt' is skipped. + /* Anything longer than 'tt' is skipped. */ while (msg_string[i] == 't') { i++; @@ -1209,20 +1221,22 @@ process_format_pattern(StringInfo buf, const char *msg_string, const char *data_ static void data_to_char(Datum data, Oid data_type, StringInfo buf) { - char *result; + char *result; switch (data_type) { - case TIMEOID: - result = TextDatumGetCString(DirectFunctionCall2Coll(interval_to_char, C_COLLATION_OID, data, - PointerGetDatum(cstring_to_text((const char *)buf->data)))); - break; - case TIMESTAMPOID: - result = TextDatumGetCString(DirectFunctionCall2Coll(timestamp_to_char, C_COLLATION_OID, data, - PointerGetDatum(cstring_to_text((const char *)buf->data)))); - break; - default: - break; + case TIMEOID: + result = TextDatumGetCString(DirectFunctionCall2Coll(interval_to_char, C_COLLATION_OID, data, + PointerGetDatum(cstring_to_text((const char *) buf->data)))); + + break; + case TIMESTAMPOID: + result = TextDatumGetCString(DirectFunctionCall2Coll(timestamp_to_char, C_COLLATION_OID, data, + PointerGetDatum(cstring_to_text((const char *) buf->data)))); + + break; + default: + break; } resetStringInfo(buf); @@ -1300,7 +1314,7 @@ get_compact_decimal_digits(const char *data_type) { return 15; } - // default precision + /* default precision */ return 7; } @@ -1313,8 +1327,8 @@ get_compact_decimal_digits(const char *data_type) static int get_numeric_sign(Numeric num) { - Numeric sign = DatumGetNumeric(DirectFunctionCall1(numeric_sign, - NumericGetDatum(num))); + Numeric sign = DatumGetNumeric(DirectFunctionCall1(numeric_sign, + NumericGetDatum(num))); return DatumGetInt32(DirectFunctionCall1(numeric_int4, NumericGetDatum(sign))); @@ -1425,8 +1439,8 @@ static void replace_currency_format(char *currency_format_mask, StringInfo format_res) { - const char *fmt = (const char *)format_res->data; - char *result; + const char *fmt = (const char *) format_res->data; + char *result; result = TextDatumGetCString(DirectFunctionCall3Coll(replace_text, C_COLLATION_OID, @@ -1466,8 +1480,8 @@ static void float4_data_to_char(StringInfo format_res, Datum num) { - const char *fmt = (const char *)format_res->data; - char *result; + const char *fmt = (const char *) format_res->data; + char *result; result = TextDatumGetCString(DirectFunctionCall2(float4_to_char, num, CStringGetTextDatum(fmt))); @@ -1483,8 +1497,8 @@ static void float8_data_to_char(StringInfo format_res, Datum num) { - const char *fmt = (const char *)format_res->data; - char *result; + const char *fmt = (const char *) format_res->data; + char *result; result = TextDatumGetCString(DirectFunctionCall2(float8_to_char, num, @@ -1504,7 +1518,7 @@ regexp_replace(char *format_res, char *match_with, const char *replace_with, cha text *s = cstring_to_text(format_res); text *p = cstring_to_text(match_with); text *r = cstring_to_text(replace_with); - char *result; + char *result; result = text_to_cstring(replace_text_regexp(s, p, r, REG_ADVANCED, C_COLLATION_OID, 0, 1)); @@ -1517,8 +1531,9 @@ regexp_replace(char *format_res, char *match_with, const char *replace_with, cha static void get_group_separator(StringInfo format_res, int integral_digits, int decimal_digits) { - int group; - char *temp; + int group; + char *temp; + resetStringInfo(format_res); if (integral_digits > 3) @@ -1562,16 +1577,18 @@ get_group_separator(StringInfo format_res, int integral_digits, int decimal_digi static void numeric_to_string(StringInfo format_res, Numeric num) { - const char *fmt = (const char *)format_res->data; - char *result; + const char *fmt = (const char *) format_res->data; + char *result; /* - * This essentially is just a wrapper to allow us to call C implementations - * of PG functions directly - in this case, numeric_to_char() + * This essentially is just a wrapper to allow us to call C + * implementations of PG functions directly - in this case, + * numeric_to_char() */ result = TextDatumGetCString(DirectFunctionCall2(numeric_to_char, NumericGetDatum(num), CStringGetTextDatum(fmt))); + resetStringInfo(format_res); appendStringInfoString(format_res, result); } @@ -1582,9 +1599,10 @@ numeric_to_string(StringInfo format_res, Numeric num) static void get_exponential_format(StringInfo format_res, int precision) { - char *temp; + char *temp; + resetStringInfo(format_res); - + if (precision > 0) { appendStringInfoString(format_res, "9D"); @@ -1605,7 +1623,7 @@ get_exponential_format(StringInfo format_res, int precision) static int get_precision(char pattern, char *precision_string, char *data_type, int integral_digits, char *culture) { - int precision; + int precision; if (pattern == 'R') { @@ -1627,26 +1645,26 @@ get_precision(char pattern, char *precision_string, char *data_type, int integra switch (pattern) { - case 'C': - precision = get_currency_decimal_digits(culture); - break; - case 'F': - case 'N': - case 'P': - precision = 2; - break; - case 'E': - precision = 6; - break; - case 'D': - precision = integral_digits; - break; - case 'G': - precision = get_compact_decimal_digits(data_type); - break; - default: - precision = -1; - break; + case 'C': + precision = get_currency_decimal_digits(culture); + break; + case 'F': + case 'N': + case 'P': + precision = 2; + break; + case 'E': + precision = 6; + break; + case 'D': + precision = integral_digits; + break; + case 'G': + precision = get_compact_decimal_digits(data_type); + break; + default: + precision = -1; + break; } return precision; } @@ -1674,13 +1692,13 @@ static void format_currency(Numeric numeric_val, StringInfo format_res, char pattern, char *precision_string, char *culture) { - Numeric numeric_abs_val; - int scale; - int total_digits; - int integral_digits; - int positive = 0; - char *currency_format; - int precision = get_precision(pattern, precision_string, "", 0, culture); + Numeric numeric_abs_val; + int scale; + int total_digits; + int integral_digits; + int positive = 0; + char *currency_format; + int precision = get_precision(pattern, precision_string, "", 0, culture); numeric_val = round_num(numeric_val, precision); numeric_abs_val = get_numeric_abs(numeric_val); @@ -1695,10 +1713,10 @@ format_currency(Numeric numeric_val, StringInfo format_res, char pattern, char * get_group_separator(format_res, integral_digits, scale); - //Get the currency format for the culture and sign + /* Get the currency format for the culture and sign */ currency_format = get_currency_sign_format(culture, positive); - //Change the current format by replacing "n" with group separator format + /* Change the current format by replacing "n" with group separator format */ replace_currency_format(currency_format, format_res); numeric_to_string(format_res, numeric_abs_val); @@ -1711,38 +1729,38 @@ static void format_decimal(Numeric numeric_val, StringInfo format_res, char pattern, char *precision_string, Oid arg_type_oid) { - Numeric numeric_abs_val; - int scale; - int total_digits; - int integral_digits; - int num_sign; - char *padding_format; - int precision; + Numeric numeric_abs_val; + int scale; + int total_digits; + int integral_digits; + int num_sign; + char *padding_format; + int precision; switch (arg_type_oid) { - case INT2OID: - case INT4OID: - case INT8OID: - numeric_abs_val = get_numeric_abs(numeric_val); - scale = get_numeric_scale(numeric_abs_val); - total_digits = get_numeric_digit_count(numeric_abs_val); - integral_digits = get_integral_digits(total_digits, scale); - num_sign = get_numeric_sign(numeric_val); + case INT2OID: + case INT4OID: + case INT8OID: + numeric_abs_val = get_numeric_abs(numeric_val); + scale = get_numeric_scale(numeric_abs_val); + total_digits = get_numeric_digit_count(numeric_abs_val); + integral_digits = get_integral_digits(total_digits, scale); + num_sign = get_numeric_sign(numeric_val); - precision = get_precision(pattern, precision_string, "", integral_digits, ""); + precision = get_precision(pattern, precision_string, "", integral_digits, ""); - padding_format = zero_left_padding(numeric_text(numeric_abs_val), precision); + padding_format = zero_left_padding(numeric_text(numeric_abs_val), precision); - resetStringInfo(format_res); - if (num_sign < 0) - { - appendStringInfoChar(format_res, '-'); - } - appendStringInfoString(format_res, padding_format); - break; - default: - break; + resetStringInfo(format_res); + if (num_sign < 0) + { + appendStringInfoChar(format_res, '-'); + } + appendStringInfoString(format_res, padding_format); + break; + default: + break; } } @@ -1753,12 +1771,12 @@ static void format_fixed_point(Numeric numeric_val, StringInfo format_res, char pattern, char *precision_string) { - Numeric numeric_abs_val; - int scale; - int total_digits; - int integral_digits; - int precision = get_precision(pattern, precision_string, "", 0, ""); - char *temp; + Numeric numeric_abs_val; + int scale; + int total_digits; + int integral_digits; + int precision = get_precision(pattern, precision_string, "", 0, ""); + char *temp; numeric_val = round_num(numeric_val, precision); numeric_abs_val = get_numeric_abs(numeric_val); @@ -1787,11 +1805,11 @@ format_fixed_point(Numeric numeric_val, StringInfo format_res, char pattern, cha static void format_number(Numeric numeric_val, StringInfo format_res, char pattern, char *precision_string) { - Numeric numeric_abs_val; - int scale; - int total_digits; - int integral_digits; - int precision = get_precision(pattern, precision_string, "", 0, ""); + Numeric numeric_abs_val; + int scale; + int total_digits; + int integral_digits; + int precision = get_precision(pattern, precision_string, "", 0, ""); numeric_val = round_num(numeric_val, precision); @@ -1810,11 +1828,11 @@ format_number(Numeric numeric_val, StringInfo format_res, char pattern, char *pr static void format_percent(Numeric numeric_val, StringInfo format_res, char pattern, char *precision_string) { - Numeric numeric_abs_val; - int scale; - int total_digits; - int integral_digits; - int precision = get_precision(pattern, precision_string, "", 0, ""); + Numeric numeric_abs_val; + int scale; + int total_digits; + int integral_digits; + int precision = get_precision(pattern, precision_string, "", 0, ""); numeric_val = round_num(multiply_numeric_by_100(numeric_val), precision); @@ -1835,22 +1853,22 @@ static void format_hexadecimal(Datum value, StringInfo format_res, char pattern, char *precision_string, Oid arg_type_oid) { - char *hexadecimal_pattern; - int precision; - int len; + char *hexadecimal_pattern; + int precision; + int len; switch (arg_type_oid) { - case INT2OID: - case INT4OID: - hexadecimal_pattern = TextDatumGetCString(DirectFunctionCall1(to_hex32, value)); - break; - case INT8OID: - hexadecimal_pattern = TextDatumGetCString(DirectFunctionCall1(to_hex64, value)); - break; - default: - hexadecimal_pattern = ""; - break; + case INT2OID: + case INT4OID: + hexadecimal_pattern = TextDatumGetCString(DirectFunctionCall1(to_hex32, value)); + break; + case INT8OID: + hexadecimal_pattern = TextDatumGetCString(DirectFunctionCall1(to_hex64, value)); + break; + default: + hexadecimal_pattern = ""; + break; } len = strlen(hexadecimal_pattern); @@ -1872,7 +1890,8 @@ format_hexadecimal(Datum value, StringInfo format_res, char pattern, char *preci if (isupper(pattern)) { - for (char *c = format_res->data; *c; ++c) *c = toupper(*c); + for (char *c = format_res->data; *c; ++c) + *c = toupper(*c); } } } @@ -1884,10 +1903,10 @@ static void format_exponential(Numeric numeric_val, StringInfo format_res, char pattern, char *precision_string) { - int len; - int temp; - char *buf; - int precision = get_precision(toupper(pattern), precision_string, "", 0, ""); + int len; + int temp; + char *buf; + int precision = get_precision(toupper(pattern), precision_string, "", 0, ""); get_exponential_format(format_res, precision); numeric_to_string(format_res, numeric_val); @@ -1898,15 +1917,16 @@ format_exponential(Numeric numeric_val, StringInfo format_res, char pattern, cha if (isupper(pattern)) { - for (char *c = buf; *c; ++c) *c = toupper(*c); + for (char *c = buf; *c; ++c) + *c = toupper(*c); } len = format_res->len; - // The last 4 characters are EEEE, appended in numeric_to_string + /* The last 4 characters are EEEE, appended in numeric_to_string */ if (len >= 5 && buf[len - 5] != 'E' && buf[len - 5] != 'e') { temp = len - 2; - // Copy the last 3 characters over one. + /* Copy the last 3 characters over one. */ for (; len >= temp; len--) { buf[len + 1] = buf[len]; @@ -1926,12 +1946,12 @@ format_exponential(Numeric numeric_val, StringInfo format_res, char pattern, cha static void format_compact(Numeric numeric_val, StringInfo format_res, char pattern, char *precision_string, char *data_type, Oid arg_type_oid) { - Numeric numeric_abs_val; - int scale; - int total_digits; - int integral_digits; - int precision; - char *temp; + Numeric numeric_abs_val; + int scale; + int total_digits; + int integral_digits; + int precision; + char *temp; numeric_abs_val = get_numeric_abs(numeric_val); scale = get_numeric_scale(numeric_abs_val); @@ -1977,65 +1997,64 @@ format_compact(Numeric numeric_val, StringInfo format_res, char pattern, char *p static void format_roundtrip(Datum value, Numeric numeric_val, StringInfo format_res, char pattern, char *data_type, Oid arg_type_oid) { - char *temp; - int scale; - int total_digits; - int integral_digits; - int precision; - Numeric numeric_abs_val; + char *temp; + int scale; + int total_digits; + int integral_digits; + int precision; + Numeric numeric_abs_val; switch (arg_type_oid) { - case FLOAT4OID: - numeric_abs_val = get_numeric_abs(numeric_val); - scale = get_numeric_scale(numeric_abs_val); - total_digits = get_numeric_digit_count(numeric_abs_val); - integral_digits = get_integral_digits(total_digits, scale); - - precision = get_precision(toupper(pattern), "", data_type, integral_digits, ""); - - if ((arg_type_oid == FLOAT4OID) && (scale > 0 || integral_digits <= 6)) - { - if ((integral_digits + scale) > 6) - { - appendStringInfoString(format_res, "9D99999999EEEE"); - } - else - { - appendStringInfoString(format_res, "9D999999EEEE"); - } - - float4_data_to_char(format_res, value); - numeric_val = cstring_to_numeric(format_res->data); - numeric_val = trim_scale_numeric(round_num(numeric_val, precision)); - + case FLOAT4OID: numeric_abs_val = get_numeric_abs(numeric_val); scale = get_numeric_scale(numeric_abs_val); total_digits = get_numeric_digit_count(numeric_abs_val); integral_digits = get_integral_digits(total_digits, scale); - appendStringInfoString(format_res, "FM"); - temp = repeat_string("0", integral_digits); - appendStringInfoString(format_res, temp); - appendStringInfoChar(format_res, 'D'); - temp = repeat_string("0", scale); - appendStringInfoString(format_res, temp); + precision = get_precision(toupper(pattern), "", data_type, integral_digits, ""); - numeric_to_string(format_res, numeric_val); - } - else - { - get_exponential_format(format_res, precision - 1); - float4_data_to_char(format_res, value); + if ((arg_type_oid == FLOAT4OID) && (scale > 0 || integral_digits <= 6)) + { + if ((integral_digits + scale) > 6) + { + appendStringInfoString(format_res, "9D99999999EEEE"); + } + else + { + appendStringInfoString(format_res, "9D999999EEEE"); + } - if (isupper(pattern)) + float4_data_to_char(format_res, value); + numeric_val = cstring_to_numeric(format_res->data); + numeric_val = trim_scale_numeric(round_num(numeric_val, precision)); + + numeric_abs_val = get_numeric_abs(numeric_val); + scale = get_numeric_scale(numeric_abs_val); + total_digits = get_numeric_digit_count(numeric_abs_val); + integral_digits = get_integral_digits(total_digits, scale); + + appendStringInfoString(format_res, "FM"); + temp = repeat_string("0", integral_digits); + appendStringInfoString(format_res, temp); + appendStringInfoChar(format_res, 'D'); + temp = repeat_string("0", scale); + appendStringInfoString(format_res, temp); + + numeric_to_string(format_res, numeric_val); + } + else { - regexp_replace(format_res->data, "[.]{0,1}0*[eE]", "E", "i"); + get_exponential_format(format_res, precision - 1); + float4_data_to_char(format_res, value); + + if (isupper(pattern)) + { + regexp_replace(format_res->data, "[.]{0,1}0*[eE]", "E", "i"); + } } - } - break; - default: - break; + break; + default: + break; } } - diff --git a/contrib/babelfishpg_tsql/src/format.h b/contrib/babelfishpg_tsql/src/format.h index a122ee66d8..fa20753f32 100644 --- a/contrib/babelfishpg_tsql/src/format.h +++ b/contrib/babelfishpg_tsql/src/format.h @@ -9,15 +9,15 @@ extern size_t CULTURE_COUNT; typedef struct _datetimeformat { - int culture_id; - char *sql_culture; - char *pg_shortdatepattern; - char *pg_longdatepattern; - char *pg_fulldatetimepattern; - char *pg_shorttimepattern; - char *pg_longtimepattern; - char *pg_monthdaypattern; - char *pg_yearmonthpattern; + int culture_id; + char *sql_culture; + char *pg_shortdatepattern; + char *pg_longdatepattern; + char *pg_fulldatetimepattern; + char *pg_shorttimepattern; + char *pg_longtimepattern; + char *pg_monthdaypattern; + char *pg_yearmonthpattern; } datetimeformat; /* @@ -423,8 +423,8 @@ static const datetimeformat datetimeformats[] = { {396, "id-ID", "dd/MM/yyyy", "TMDay, dd TMMonth yyyy", "TMDay, dd TMMonth yyyy HH.MI.ss", "HH24.MI", "HH24.MI.ss", "FMdd TMMonth", "TMMonth yyyy"}, {397, "ig", "dd/MM/yyyy", "TMDay, FMdd TMMonth yyyy", "TMDay, FMdd TMMonth yyyy HH24:MI:ss", "HH24:MI", "HH24:MI:ss", "TMMonth FMdd", "TMMonth yyyy"}, {398, "ig-NG", "dd/MM/yyyy", "TMDay, FMdd TMMonth yyyy", "TMDay, FMdd TMMonth yyyy HH24:MI:ss", "HH24:MI", "HH24:MI:ss", "TMMonth FMdd", "TMMonth yyyy"}, - {399, "ii", "yyyy/FMMM/FMdd", "yyyy\"ꈎ\" FMMM\"ꆪ\" FMdd\"ê‘\"", "yyyy\"ꈎ\" FMMM\"ꆪ\" FMdd\"ê‘\" AM FMHH12:MI:ss", "AM FMHH12:MI", "AM FMHH12:MI:ss", "FMMM’ ꆪ’FMdd’ ê‘’", "yyyy\"ꈎ\" FMMM\"ꆪ\""}, - {400, "ii-CN", "yyyy/FMMM/FMdd", "yyyy\"ꈎ\" FMMM\"ꆪ\" FMdd\"ê‘\"", "yyyy\"ꈎ\" FMMM\"ꆪ\" FMdd\"ê‘\" AM FMHH12:MI:ss", "AM FMHH12:MI", "AM FMHH12:MI:ss", "FMMM’ ꆪ’FMdd’ ê‘’", "yyyy\"ꈎ\" FMMM\"ꆪ\""}, + {399, "ii", "yyyy/FMMM/FMdd", "yyyy\"ꈎ\" FMMM\"ꆪ\" FMdd\"ê‘\"", "yyyy\"ꈎ\" FMMM\"ꆪ\" FMdd\"ê‘\" AM FMHH12:MI:ss", "AM FMHH12:MI", "AM FMHH12:MI:ss", "FMMMâ35™ ꆪâ35™FMddâ35™ ê‘â35™", "yyyy\"ꈎ\" FMMM\"ꆪ\""}, + {400, "ii-CN", "yyyy/FMMM/FMdd", "yyyy\"ꈎ\" FMMM\"ꆪ\" FMdd\"ê‘\"", "yyyy\"ꈎ\" FMMM\"ꆪ\" FMdd\"ê‘\" AM FMHH12:MI:ss", "AM FMHH12:MI", "AM FMHH12:MI:ss", "FMMMâ35™ ꆪâ35™FMddâ35™ ê‘â35™", "yyyy\"ꈎ\" FMMM\"ꆪ\""}, {401, "is", "FMdd.FMMM.yyyy", "TMDay, FMdd. TMMonth yyyy", "TMDay, FMdd. TMMonth yyyy HH24:MI:ss", "HH24:MI", "HH24:MI:ss", "FMdd. TMMonth", "TMMonth yyyy"}, {402, "is-IS", "FMdd.FMMM.yyyy", "TMDay, FMdd. TMMonth yyyy", "TMDay, FMdd. TMMonth yyyy HH24:MI:ss", "HH24:MI", "HH24:MI:ss", "FMdd. TMMonth", "TMMonth yyyy"}, {403, "it", "dd/MM/yyyy", "TMDay FMdd TMMonth yyyy", "TMDay FMdd TMMonth yyyy HH24:MI:ss", "HH24:MI", "HH24:MI:ss", "FMdd TMMonth", "TMMonth yyyy"}, @@ -565,8 +565,8 @@ static const datetimeformat datetimeformats[] = { {538, "ms-BN", "FMdd/MM/yyyy", "dd TMMonth yyyy", "dd TMMonth yyyy FMHH12:MI:ss AM", "FMHH12:MI AM", "FMHH12:MI:ss AM", "FMdd TMMonth", "TMMonth yyyy"}, {539, "ms-MY", "FMdd/MM/yyyy", "TMDay, FMdd TMMonth yyyy", "TMDay, FMdd TMMonth yyyy FMHH12:MI:ss AM", "FMHH12:MI AM", "FMHH12:MI:ss AM", "FMdd TMMonth", "TMMonth yyyy"}, {540, "ms-SG", "FMdd/MM/yyyy", "TMDay, FMdd TMMonth yyyy", "TMDay, FMdd TMMonth yyyy FMHH12:MI:ss AM", "FMHH12:MI AM", "FMHH12:MI:ss AM", "FMdd TMMonth", "TMMonth yyyy"}, - {541, "mt", "dd/MM/yyyy", "TMDay, FMdd \"ta\"’ TMMonth yyyy", "TMDay, FMdd \"ta\"’ TMMonth yyyy HH24:MI:ss", "HH24:MI", "HH24:MI:ss", "FMdd \"ta\"’ TMMonth", "TMMonth yyyy"}, - {542, "mt-MT", "dd/MM/yyyy", "TMDay, FMdd \"ta\"’ TMMonth yyyy", "TMDay, FMdd \"ta\"’ TMMonth yyyy HH24:MI:ss", "HH24:MI", "HH24:MI:ss", "FMdd \"ta\"’ TMMonth", "TMMonth yyyy"}, + {541, "mt", "dd/MM/yyyy", "TMDay, FMdd \"ta\"â35™ TMMonth yyyy", "TMDay, FMdd \"ta\"â35™ TMMonth yyyy HH24:MI:ss", "HH24:MI", "HH24:MI:ss", "FMdd \"ta\"â35™ TMMonth", "TMMonth yyyy"}, + {542, "mt-MT", "dd/MM/yyyy", "TMDay, FMdd \"ta\"â35™ TMMonth yyyy", "TMDay, FMdd \"ta\"â35™ TMMonth yyyy HH24:MI:ss", "HH24:MI", "HH24:MI:ss", "FMdd \"ta\"â35™ TMMonth", "TMMonth yyyy"}, {543, "mua", "FMdd/FMMM/yyyy", "TMDay FMdd TMMonth yyyy", "TMDay FMdd TMMonth yyyy HH24:MI:ss", "HH24:MI", "HH24:MI:ss", "TMMonth FMdd", "yyyy TMMonth"}, {544, "mua-CM", "FMdd/FMMM/yyyy", "TMDay FMdd TMMonth yyyy", "TMDay FMdd TMMonth yyyy HH24:MI:ss", "HH24:MI", "HH24:MI:ss", "TMMonth FMdd", "yyyy TMMonth"}, {545, "my", "dd-MM-yyyy", "yyyyአTMMonth dአTMDay", "yyyyአTMMonth dአTMDay HH24:MI:ss", "FMHH24:MI", "HH24:MI:ss", "TMMonth FMdd", "yyyy TMMonth"}, @@ -808,8 +808,8 @@ static const datetimeformat datetimeformats[] = { {781, "tzm-Tfng-MA", "dd-MM-yyyy", "TMDay, dd TMMonth, yyyy", "TMDay, dd TMMonth, yyyy FMHH24:MI:ss", "FMHH24:MI", "FMHH24:MI:ss", "dd TMMonth", "TMMonth, yyyy"}, {782, "ug", "yyyy-FMMM-FMdd", "yyyy-\"يىل\" FMdd-TMMonth", "yyyy-\"يىل\" FMdd-TMMonth FMHH24:MI:ss", "FMHH24:MI", "FMHH24:MI:ss", "FMdd-TMMonth", "yyyy-\"يىلى\" TMMonth"}, {783, "ug-CN", "yyyy-FMMM-FMdd", "yyyy-\"يىل\" FMdd-TMMonth", "yyyy-\"يىل\" FMdd-TMMonth FMHH24:MI:ss", "FMHH24:MI", "FMHH24:MI:ss", "FMdd-TMMonth", "yyyy-\"يىلى\" TMMonth"}, - {784, "uk", "dd.MM.yyyy", "FMdd TMMonth yyyy\" Ñ€.\"", "FMdd TMMonth yyyy\" Ñ€.\" FMHH24:MI:ss", "FMHH24:MI", "FMHH24:MI:ss", "FMdd TMMonth", "TMMonth yyyy\" Ñ€.\""}, - {785, "uk-UA", "dd.MM.yyyy", "FMdd TMMonth yyyy\" Ñ€.\"", "FMdd TMMonth yyyy\" Ñ€.\" FMHH24:MI:ss", "FMHH24:MI", "FMHH24:MI:ss", "FMdd TMMonth", "TMMonth yyyy\" Ñ€.\""}, + {784, "uk", "dd.MM.yyyy", "FMdd TMMonth yyyy\" Ñ35.\"", "FMdd TMMonth yyyy\" Ñ35.\" FMHH24:MI:ss", "FMHH24:MI", "FMHH24:MI:ss", "FMdd TMMonth", "TMMonth yyyy\" Ñ35.\""}, + {785, "uk-UA", "dd.MM.yyyy", "FMdd TMMonth yyyy\" Ñ35.\"", "FMdd TMMonth yyyy\" Ñ35.\" FMHH24:MI:ss", "FMHH24:MI", "FMHH24:MI:ss", "FMdd TMMonth", "TMMonth yyyy\" Ñ35.\""}, {786, "ur", "dd/MM/yyyy", "dd TMMonth, yyyy", "dd TMMonth, yyyy FMHH12:MI:ss AM", "FMHH12:MI AM", "FMHH12:MI:ss AM", "dd TMMonth", "TMMonth, yyyy"}, {787, "ur-IN", "FMdd/FMMM/yy", "TMDay, FMdd TMMonth, yyyy", "TMDay, FMdd TMMonth, yyyy FMHH12:MI:ss AM", "FMHH12:MI AM", "FMHH12:MI:ss AM", "FMdd TMMonth", "TMMonth yyyy"}, {788, "ur-PK", "dd/MM/yyyy", "dd TMMonth, yyyy", "dd TMMonth, yyyy FMHH12:MI:ss AM", "FMHH12:MI AM", "FMHH12:MI:ss AM", "dd TMMonth", "TMMonth, yyyy"}, @@ -866,7 +866,7 @@ static const datetimeformat datetimeformats[] = { {839, "zu", "FMMM/FMdd/yyyy", "TMDay, TMMonth FMdd, yyyy", "TMDay, TMMonth FMdd, yyyy HH24:MI:ss", "HH24:MI", "HH24:MI:ss", "TMMonth FMdd", "TMMonth yyyy"}, {840, "zu-ZA", "FMMM/FMdd/yyyy", "TMDay, TMMonth FMdd, yyyy", "TMDay, TMMonth FMdd, yyyy HH24:MI:ss", "HH24:MI", "HH24:MI:ss", "TMMonth FMdd", "TMMonth yyyy"}, {841, "zh-CHS", "yyyy/FMMM/FMdd", "yyyy\"å¹´\"FMMM\"月\"FMdd\"æ—¥\"", "yyyy\"å¹´\"FMMM\"月\"FMdd\"æ—¥\" FMHH24:MI:ss", "FMHH24:MI", "FMHH24:MI:ss", "FMMM月FMddæ—¥", "yyyy\"å¹´\"FMMM\"月\""}, - {842, "zh-CHT", "FMdd/FMMM/yyyy", "yyyy\"å¹´\"FMMM\"月\"FMdd\"æ—¥\"", "yyyy\"å¹´\"FMMM\"月\"FMdd\"æ—¥\" FMHH24:MI:ss", "FMHH24:MI", "FMHH24:MI:ss", "FMMM月FMddæ—¥", "yyyy\"å¹´\"FMMM\"月\""}}; +{842, "zh-CHT", "FMdd/FMMM/yyyy", "yyyy\"å¹´\"FMMM\"月\"FMdd\"æ—¥\"", "yyyy\"å¹´\"FMMM\"月\"FMdd\"æ—¥\" FMHH24:MI:ss", "FMHH24:MI", "FMHH24:MI:ss", "FMMM月FMddæ—¥", "yyyy\"å¹´\"FMMM\"月\""}}; /* * Culture wise CurrencyPositivePattern, CurrencyNegativePattern, CurrencyDecimalDigits @@ -874,13 +874,13 @@ static const datetimeformat datetimeformats[] = { */ static const struct currencyformat { - int culture_id; - char *sql_culture; - char *positive_pattern; - char *negative_pattern; - int decimal_digits; + int culture_id; + char *sql_culture; + char *positive_pattern; + char *negative_pattern; + int decimal_digits; -} currencyformats[] = { +} currencyformats[] = { {0, "", "Ln", "(Ln)", 2}, {1, "aa", "Ln", "-Ln", 2}, @@ -1724,27 +1724,27 @@ static const struct currencyformat {839, "zu", "Ln", "-Ln", 2}, {840, "zu-ZA", "Ln", "-Ln", 2}, {841, "zh-CHS", "Ln", "L-n", 2}, - {842, "zh-CHT", "Ln", "(Ln)", 2}}; +{842, "zh-CHT", "Ln", "(Ln)", 2}}; /* * Functions related to FORMAT() function in string.c */ -static int set_culture(char *valid_culture, const char *config_name, const char *culture); +static int set_culture(char *valid_culture, const char *config_name, const char *culture); static char *format_validate_and_culture(const char *culture, const char *config_name); -static int format_datetimeformats(StringInfo buf, const char *format_pattern, const char *culture, const char *data_type, const char *data_val); -static int process_format_pattern(StringInfo buf, const char *msg_string, const char *data_type); +static int format_datetimeformats(StringInfo buf, const char *format_pattern, const char *culture, const char *data_type, const char *data_val); +static int process_format_pattern(StringInfo buf, const char *msg_string, const char *data_type); static void data_to_char(Datum data, Oid data_type, StringInfo buf); static char *get_currency_sign_format(const char *culture, int positive); -static int get_currency_decimal_digits(const char *culture); -static int get_compact_decimal_digits(const char *data_type); -static int get_numeric_sign(Numeric num); +static int get_currency_decimal_digits(const char *culture); +static int get_compact_decimal_digits(const char *data_type); +static int get_numeric_sign(Numeric num); static void get_group_separator(StringInfo format_res, int integral_digits, int decimal_digits); static void get_exponential_format(StringInfo format_res, int precision); -static int get_precision(char pattern, char *precision_string, char *data_type, int integral_digits, char* culture); +static int get_precision(char pattern, char *precision_string, char *data_type, int integral_digits, char *culture); static Datum get_numeric_digit_count(Numeric num); -static int get_numeric_scale(Numeric num); -static int get_integral_digits(int total_digits, int scale); +static int get_numeric_scale(Numeric num); +static int get_integral_digits(int total_digits, int scale); static Numeric trim_scale_numeric(Numeric num); static Numeric get_numeric_abs(Numeric num); @@ -1754,17 +1754,17 @@ static void numeric_to_string(StringInfo format_res, Numeric num); static char *numeric_text(Numeric num); static void replace_currency_format(char *currency_format_mask, StringInfo format_res); -static char* zero_left_padding(char* num_string, int count); +static char *zero_left_padding(char *num_string, int count); static Numeric cstring_to_numeric(char *val_string); static void float4_data_to_char(StringInfo format_res, Datum num); static void float8_data_to_char(StringInfo format_res, Datum num); -static char* repeat_string(char *val, int count); +static char *repeat_string(char *val, int count); static void regexp_replace(char *format_res, char *match_with, const char *replace_with, char *flag); -static int match(const char *string, const char *pattern); +static int match(const char *string, const char *pattern); -static void format_currency(Numeric numeric_val, StringInfo format_res, char pattern, char *precision_string, char* culture); +static void format_currency(Numeric numeric_val, StringInfo format_res, char pattern, char *precision_string, char *culture); static void format_decimal(Numeric numeric_val, StringInfo format_res, char pattern, char *precision_string, Oid arg_type_oid); static void format_fixed_point(Numeric numeric_val, StringInfo format_res, char pattern, char *precision_string); static void format_number(Numeric numeric_val, StringInfo format_res, char pattern, char *precision_string); @@ -1774,6 +1774,6 @@ static void format_exponential(Numeric numeric_val, StringInfo format_res, char static void format_compact(Numeric numeric_val, StringInfo format_res, char pattern, char *precision_string, char *data_type, Oid arg_type_oid); static void format_roundtrip(Datum value, Numeric numeric_val, StringInfo format_res, char pattern, char *data_type, Oid arg_type_oid); static void format_numeric_handler(Datum value, Numeric numeric_val, StringInfo format_res, char pattern, char *precision_string, - Oid arg_type_oid, char *culture, char *valid_culture, char *data_type); + Oid arg_type_oid, char *culture, char *valid_culture, char *data_type); #endif diff --git a/contrib/babelfishpg_tsql/src/guc.c b/contrib/babelfishpg_tsql/src/guc.c index 5bdd89be1a..793b218f18 100644 --- a/contrib/babelfishpg_tsql/src/guc.c +++ b/contrib/babelfishpg_tsql/src/guc.c @@ -1,6 +1,6 @@ #include "postgres.h" #include "commands/explain.h" -#include "parser/scansup.h" /* downcase_identifier */ +#include "parser/scansup.h" /* downcase_identifier */ #include "utils/guc.h" #include "miscadmin.h" @@ -15,56 +15,56 @@ #define PLTSQL_TRANSACTION_ISOLATION_LEVEL "transaction_isolation" #define PLTSQL_DEFAULT_LANGUAGE "us_english" -static int migration_mode = SINGLE_DB; -bool enable_ownership_structure = false; - -bool enable_metadata_inconsistency_check = true; - -bool pltsql_dump_antlr_query_graph = false; -bool pltsql_enable_antlr_detailed_log = false; -bool pltsql_enable_sll_parse_mode = true; -bool pltsql_allow_antlr_to_unsupported_grammar_for_testing = false; -bool pltsql_ansi_defaults = true; -bool pltsql_quoted_identifier = true; -bool pltsql_concat_null_yields_null = true; -bool pltsql_ansi_nulls = true; -bool pltsql_ansi_null_dflt_on = true; -bool pltsql_ansi_null_dflt_off = false; -bool pltsql_ansi_padding = true; -bool pltsql_ansi_warnings = true; -bool pltsql_arithignore = false; -bool pltsql_arithabort = true; -bool pltsql_numeric_roundabort = false; -bool pltsql_nocount = false; -char* pltsql_database_name = NULL; -char* pltsql_version = NULL; -int pltsql_datefirst = 7; -int pltsql_rowcount = 0; -char* pltsql_language = NULL; -int pltsql_lock_timeout = -1; -bool pltsql_enable_linked_servers = true; -bool pltsql_allow_windows_login = true; - -bool pltsql_xact_abort = false; -bool pltsql_implicit_transactions = false; -bool pltsql_cursor_close_on_commit = false; -bool pltsql_disable_batch_auto_commit = false; -bool pltsql_disable_internal_savepoint = false; -bool pltsql_disable_txn_in_triggers = false; -bool pltsql_recursive_triggers = false; -bool pltsql_noexec = false; -bool pltsql_showplan_all = false; -bool pltsql_showplan_text = false; -bool pltsql_showplan_xml = false; -bool pltsql_fmtonly = false; -bool pltsql_enable_tsql_information_schema = true; -bool pltsql_no_browsetable = false; - -char* pltsql_host_destribution = NULL; -char* pltsql_host_release = NULL; -char* pltsql_host_service_pack_level = NULL; - -bool pltsql_enable_create_alter_view_from_pg = false; +static int migration_mode = SINGLE_DB; +bool enable_ownership_structure = false; + +bool enable_metadata_inconsistency_check = true; + +bool pltsql_dump_antlr_query_graph = false; +bool pltsql_enable_antlr_detailed_log = false; +bool pltsql_enable_sll_parse_mode = true; +bool pltsql_allow_antlr_to_unsupported_grammar_for_testing = false; +bool pltsql_ansi_defaults = true; +bool pltsql_quoted_identifier = true; +bool pltsql_concat_null_yields_null = true; +bool pltsql_ansi_nulls = true; +bool pltsql_ansi_null_dflt_on = true; +bool pltsql_ansi_null_dflt_off = false; +bool pltsql_ansi_padding = true; +bool pltsql_ansi_warnings = true; +bool pltsql_arithignore = false; +bool pltsql_arithabort = true; +bool pltsql_numeric_roundabort = false; +bool pltsql_nocount = false; +char *pltsql_database_name = NULL; +char *pltsql_version = NULL; +int pltsql_datefirst = 7; +int pltsql_rowcount = 0; +char *pltsql_language = NULL; +int pltsql_lock_timeout = -1; +bool pltsql_enable_linked_servers = true; +bool pltsql_allow_windows_login = true; + +bool pltsql_xact_abort = false; +bool pltsql_implicit_transactions = false; +bool pltsql_cursor_close_on_commit = false; +bool pltsql_disable_batch_auto_commit = false; +bool pltsql_disable_internal_savepoint = false; +bool pltsql_disable_txn_in_triggers = false; +bool pltsql_recursive_triggers = false; +bool pltsql_noexec = false; +bool pltsql_showplan_all = false; +bool pltsql_showplan_text = false; +bool pltsql_showplan_xml = false; +bool pltsql_fmtonly = false; +bool pltsql_enable_tsql_information_schema = true; +bool pltsql_no_browsetable = false; + +char *pltsql_host_destribution = NULL; +char *pltsql_host_release = NULL; +char *pltsql_host_service_pack_level = NULL; + +bool pltsql_enable_create_alter_view_from_pg = false; static const struct config_enum_entry explain_format_options[] = { {"text", EXPLAIN_FORMAT_TEXT, false}, @@ -77,42 +77,42 @@ static const struct config_enum_entry explain_format_options[] = { extern bool Transform_null_equals; /* Dump and Restore */ -bool babelfish_dump_restore = false; -bool restore_tsql_tabletype = false; -char *babelfish_dump_restore_min_oid = NULL; +bool babelfish_dump_restore = false; +bool restore_tsql_tabletype = false; +char *babelfish_dump_restore_min_oid = NULL; /* T-SQL Hint Mapping */ -bool enable_hint_mapping = true; -bool enable_pg_hint = false; - -static bool check_ansi_null_dflt_on (bool *newval, void **extra, GucSource source); -static bool check_ansi_null_dflt_off (bool *newval, void **extra, GucSource source); -static bool check_ansi_padding (bool *newval, void **extra, GucSource source); -static bool check_ansi_warnings (bool *newval, void **extra, GucSource source); -static bool check_arithignore (bool *newval, void **extra, GucSource source); -static bool check_arithabort (bool *newval, void **extra, GucSource source); -static bool check_babelfish_dump_restore_min_oid (char **newval, void **extra, GucSource source); -static bool check_numeric_roundabort (bool *newval, void **extra, GucSource source); -static bool check_cursor_close_on_commit (bool *newval, void **extra, GucSource source); -static bool check_language (char **newval, void **extra, GucSource source); -static bool check_noexec (bool *newval, void **extra, GucSource source); -static bool check_showplan_all (bool *newval, void **extra, GucSource source); -static bool check_showplan_text (bool *newval, void **extra, GucSource source); -static bool check_showplan_xml (bool *newval, void **extra, GucSource source); -static void assign_transform_null_equals (bool newval, void *extra); -static void assign_ansi_defaults (bool newval, void *extra); -static void assign_quoted_identifier (bool newval, void *extra); -static void assign_arithabort (bool newval, void *extra); -static void assign_ansi_null_dflt_on (bool newval, void *extra); -static void assign_ansi_warnings (bool newval, void *extra); -static void assign_ansi_padding (bool newval, void *extra); -static void assign_concat_null_yields_null (bool newval, void *extra); -static void assign_language (const char *newval, void *extra); -static void assign_lock_timeout (int newval, void *extra); -static void assign_datefirst (int newval, void *extra); -static bool check_no_browsetable (bool *newval, void **extra, GucSource source); -static void assign_enable_pg_hint (bool newval, void *extra); -int escape_hatch_session_settings; /* forward declaration */ +bool enable_hint_mapping = true; +bool enable_pg_hint = false; + +static bool check_ansi_null_dflt_on(bool *newval, void **extra, GucSource source); +static bool check_ansi_null_dflt_off(bool *newval, void **extra, GucSource source); +static bool check_ansi_padding(bool *newval, void **extra, GucSource source); +static bool check_ansi_warnings(bool *newval, void **extra, GucSource source); +static bool check_arithignore(bool *newval, void **extra, GucSource source); +static bool check_arithabort(bool *newval, void **extra, GucSource source); +static bool check_babelfish_dump_restore_min_oid(char **newval, void **extra, GucSource source); +static bool check_numeric_roundabort(bool *newval, void **extra, GucSource source); +static bool check_cursor_close_on_commit(bool *newval, void **extra, GucSource source); +static bool check_language(char **newval, void **extra, GucSource source); +static bool check_noexec(bool *newval, void **extra, GucSource source); +static bool check_showplan_all(bool *newval, void **extra, GucSource source); +static bool check_showplan_text(bool *newval, void **extra, GucSource source); +static bool check_showplan_xml(bool *newval, void **extra, GucSource source); +static void assign_transform_null_equals(bool newval, void *extra); +static void assign_ansi_defaults(bool newval, void *extra); +static void assign_quoted_identifier(bool newval, void *extra); +static void assign_arithabort(bool newval, void *extra); +static void assign_ansi_null_dflt_on(bool newval, void *extra); +static void assign_ansi_warnings(bool newval, void *extra); +static void assign_ansi_padding(bool newval, void *extra); +static void assign_concat_null_yields_null(bool newval, void *extra); +static void assign_language(const char *newval, void *extra); +static void assign_lock_timeout(int newval, void *extra); +static void assign_datefirst(int newval, void *extra); +static bool check_no_browsetable(bool *newval, void **extra, GucSource source); +static void assign_enable_pg_hint(bool newval, void *extra); +int escape_hatch_session_settings; /* forward declaration */ static const struct config_enum_entry migration_mode_options[] = { {"single-db", SINGLE_DB, false}, @@ -126,244 +126,270 @@ static const struct config_enum_entry escape_hatch_options[] = { {NULL, EH_NULL, false}, }; -static bool check_ansi_null_dflt_on (bool *newval, void **extra, GucSource source) +static bool +check_ansi_null_dflt_on(bool *newval, void **extra, GucSource source) { - /* We only support setting ansi_null_dflt_on to on atm, report an error if someone tries to set it to off */ + /* + * We only support setting ansi_null_dflt_on to on atm, report an error if + * someone tries to set it to off + */ if (*newval == false && escape_hatch_session_settings != EH_IGNORE) - { - TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_OPTION_ANSI_NULL_DFLT); - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("OFF setting is not allowed for option ANSI_NULL_DFLT_ON. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); - } + { + TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_OPTION_ANSI_NULL_DFLT); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("OFF setting is not allowed for option ANSI_NULL_DFLT_ON. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); + } else if (escape_hatch_session_settings == EH_IGNORE) { - *newval = true; /* overwrite to a default value */ + *newval = true; /* overwrite to a default value */ } - return true; + return true; } -static bool check_ansi_null_dflt_off (bool *newval, void **extra, GucSource source) +static bool +check_ansi_null_dflt_off(bool *newval, void **extra, GucSource source) { - /* We only support setting ansi_null_dflt_on to on atm, report an error if someone tries to set it to off */ + /* + * We only support setting ansi_null_dflt_on to on atm, report an error if + * someone tries to set it to off + */ if (*newval == true && escape_hatch_session_settings != EH_IGNORE) - { - TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_OPTION_ANSI_NULL_DFLT); - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("ON setting is not allowed for option ANSI_NULL_DFLT_OFF. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); - } + { + TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_OPTION_ANSI_NULL_DFLT); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("ON setting is not allowed for option ANSI_NULL_DFLT_OFF. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); + } else if (escape_hatch_session_settings == EH_IGNORE) { - *newval = false; /* overwrite to a default value */ + *newval = false; /* overwrite to a default value */ } - return true; + return true; } -static bool check_ansi_padding (bool *newval, void **extra, GucSource source) +static bool +check_ansi_padding(bool *newval, void **extra, GucSource source) { - /* We only support setting ANSI_PADDING to ON atm, report an error if someone tries to set it to OFF */ + /* + * We only support setting ANSI_PADDING to ON atm, report an error if + * someone tries to set it to OFF + */ if (*newval == false && escape_hatch_session_settings != EH_IGNORE) - { - TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_OPTION_ANSI_PADDING); - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("OFF setting is not allowed for option ANSI_PADDING. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); - } + { + TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_OPTION_ANSI_PADDING); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("OFF setting is not allowed for option ANSI_PADDING. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); + } else if (escape_hatch_session_settings == EH_IGNORE) { - *newval = true; /* overwrite to a default value */ + *newval = true; /* overwrite to a default value */ } - return true; + return true; } -static bool check_ansi_warnings (bool *newval, void **extra, GucSource source) +static bool +check_ansi_warnings(bool *newval, void **extra, GucSource source) { if (*newval == false && escape_hatch_session_settings != EH_IGNORE) - { - TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_OPTION_ANSI_WARNINGS); - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("OFF setting is not allowed for option ANSI_WARNINGS. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); - } + { + TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_OPTION_ANSI_WARNINGS); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("OFF setting is not allowed for option ANSI_WARNINGS. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); + } else if (escape_hatch_session_settings == EH_IGNORE) { - *newval = true; /* overwrite to a default value */ + *newval = true; /* overwrite to a default value */ } - return true; + return true; } -static bool check_arithignore (bool *newval, void **extra, GucSource source) +static bool +check_arithignore(bool *newval, void **extra, GucSource source) { if (*newval == true && escape_hatch_session_settings != EH_IGNORE) - { - TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_OPTION_ARITHIGNORE); - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("ON setting is not allowed for option ARITHIGNORE. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); - } + { + TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_OPTION_ARITHIGNORE); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("ON setting is not allowed for option ARITHIGNORE. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); + } else if (escape_hatch_session_settings == EH_IGNORE) { - *newval = false; /* overwrite to a default value */ + *newval = false; /* overwrite to a default value */ } - return true; + return true; } -static bool check_arithabort (bool *newval, void **extra, GucSource source) +static bool +check_arithabort(bool *newval, void **extra, GucSource source) { if (*newval == false && escape_hatch_session_settings != EH_IGNORE) - { - TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_OPTION_ARITHABORT); - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("OFF setting is not allowed for option ARITHABORT. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); - } + { + TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_OPTION_ARITHABORT); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("OFF setting is not allowed for option ARITHABORT. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); + } else if (escape_hatch_session_settings == EH_IGNORE) { - *newval = true; /* overwrite to a default value */ + *newval = true; /* overwrite to a default value */ } - return true; + return true; } -static bool check_babelfish_dump_restore_min_oid (char **newval, void **extra, GucSource source) +static bool +check_babelfish_dump_restore_min_oid(char **newval, void **extra, GucSource source) { return *newval == NULL || OidIsValid(atooid(*newval)); } -static bool check_numeric_roundabort (bool *newval, void **extra, GucSource source) +static bool +check_numeric_roundabort(bool *newval, void **extra, GucSource source) { if (*newval == true && escape_hatch_session_settings != EH_IGNORE) - { - TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_OPTION_NUMERIC_ROUNDABORT); - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("ON setting is not allowed for option NUMERIC_ROUNDABORT. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); - } + { + TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_OPTION_NUMERIC_ROUNDABORT); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("ON setting is not allowed for option NUMERIC_ROUNDABORT. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); + } else if (escape_hatch_session_settings == EH_IGNORE) { - *newval = false; /* overwrite to a default value */ + *newval = false; /* overwrite to a default value */ } - return true; + return true; } -static bool check_cursor_close_on_commit (bool *newval, void **extra, GucSource source) +static bool +check_cursor_close_on_commit(bool *newval, void **extra, GucSource source) { - if (*newval == true && escape_hatch_session_settings != EH_IGNORE) - { - TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_OPTION_CURSOR_CLOSE_ON_COMMIT); - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("ON setting is not allowed for option CURSOR_CLOSE_ON_COMMIT. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); - } - else if (escape_hatch_session_settings == EH_IGNORE) - { - *newval = false; /* overwrite to a default value */ - } - return true; + if (*newval == true && escape_hatch_session_settings != EH_IGNORE) + { + TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_OPTION_CURSOR_CLOSE_ON_COMMIT); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("ON setting is not allowed for option CURSOR_CLOSE_ON_COMMIT. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); + } + else if (escape_hatch_session_settings == EH_IGNORE) + { + *newval = false; /* overwrite to a default value */ + } + return true; } -static bool check_language (char **newval, void **extra, GucSource source) +static bool +check_language(char **newval, void **extra, GucSource source) { /* We will only allow "us_english" for now */ if (strcmp(*newval, PLTSQL_DEFAULT_LANGUAGE) != 0 && escape_hatch_session_settings != EH_IGNORE) ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Settings other than \"%s\" are not allowed for option LANGUAGE. Please use babelfishpg_tsql.escape_hatch_session_settings to ignore", PLTSQL_DEFAULT_LANGUAGE))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Settings other than \"%s\" are not allowed for option LANGUAGE. Please use babelfishpg_tsql.escape_hatch_session_settings to ignore", PLTSQL_DEFAULT_LANGUAGE))); else if (escape_hatch_session_settings == EH_IGNORE) - *newval = PLTSQL_DEFAULT_LANGUAGE; /* overwrite to a default value */ + *newval = PLTSQL_DEFAULT_LANGUAGE; /* overwrite to a default value */ return true; } -static bool check_noexec (bool *newval, void **extra, GucSource source) +static bool +check_noexec(bool *newval, void **extra, GucSource source) { if (*newval == true && escape_hatch_session_settings != EH_IGNORE) { TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_OPTION_NOEXEC); ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("ON setting is not allowed for option NOEXEC. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("ON setting is not allowed for option NOEXEC. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); } else if (escape_hatch_session_settings == EH_IGNORE) { - *newval = false; /* overwrite to a default value */ + *newval = false; /* overwrite to a default value */ } return true; } -static bool check_showplan_all (bool *newval, void **extra, GucSource source) +static bool +check_showplan_all(bool *newval, void **extra, GucSource source) { if (*newval == true && escape_hatch_session_settings != EH_IGNORE) { TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_OPTION_SHOWPLAN_ALL); ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("ON setting is not allowed for option SHOWPLAN_ALL. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("ON setting is not allowed for option SHOWPLAN_ALL. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); } else if (escape_hatch_session_settings == EH_IGNORE) { - *newval = false; /* overwrite to a default value */ + *newval = false; /* overwrite to a default value */ } return true; } -static bool check_showplan_text (bool *newval, void **extra, GucSource source) +static bool +check_showplan_text(bool *newval, void **extra, GucSource source) { if (*newval == true && escape_hatch_session_settings != EH_IGNORE) { TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_OPTION_SHOWPLAN_TEXT); ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("ON setting is not allowed for option SHOWPLAN_TEXT. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("ON setting is not allowed for option SHOWPLAN_TEXT. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); } else if (escape_hatch_session_settings == EH_IGNORE) { - *newval = false; /* overwrite to a default value */ + *newval = false; /* overwrite to a default value */ } return true; } -static bool check_no_browsetable (bool *newval, void **extra, GucSource source) +static bool +check_no_browsetable(bool *newval, void **extra, GucSource source) { if (*newval == false && escape_hatch_session_settings != EH_IGNORE) - { + { TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_OPTION_NO_BROWSETABLE); ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("OFF setting is not allowed for option NO_BROWSETABLE. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); - } + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("OFF setting is not allowed for option NO_BROWSETABLE. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); + } else if (escape_hatch_session_settings == EH_IGNORE) { - *newval = true; /* overwrite to a default value */ + *newval = true; /* overwrite to a default value */ } - return true; + return true; } -static bool check_showplan_xml (bool *newval, void **extra, GucSource source) +static bool +check_showplan_xml(bool *newval, void **extra, GucSource source) { if (*newval == true && escape_hatch_session_settings != EH_IGNORE) { TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_OPTION_SHOWPLAN_XML); ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("ON setting is not allowed for option SHOWPLAN_XML. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("ON setting is not allowed for option SHOWPLAN_XML. please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); } else if (escape_hatch_session_settings == EH_IGNORE) { - *newval = false; /* overwrite to a default value */ + *newval = false; /* overwrite to a default value */ } return true; } -static bool check_tsql_version (char **newval, void **extra, GucSource source) +static bool +check_tsql_version(char **newval, void **extra, GucSource source) { Assert(*newval != NULL); - if(pg_strcasecmp(*newval,"default") != 0) + if (pg_strcasecmp(*newval, "default") != 0) ereport(WARNING, - (errmsg("Product version setting by babelfishpg_tds.product_version GUC will have no effect on @@VERSION"))); + (errmsg("Product version setting by babelfishpg_tds.product_version GUC will have no effect on @@VERSION"))); return true; } -static void assign_enable_pg_hint (bool newval, void *extra) +static void +assign_enable_pg_hint(bool newval, void *extra) { if (newval) { @@ -375,12 +401,13 @@ static void assign_enable_pg_hint (bool newval, void *extra) SetConfigOption("pg_hint_plan.enable_hint", newval ? "on" : "off", PGC_USERSET, PGC_S_SESSION); } -static void assign_transform_null_equals (bool newval, void *extra) +static void +assign_transform_null_equals(bool newval, void *extra) { Transform_null_equals = !newval; if (pltsql_protocol_plugin_ptr && *pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->set_guc_stat_var) - (*pltsql_protocol_plugin_ptr)->set_guc_stat_var("babelfishpg_tsql.ansi_nulls", newval, NULL, 0); + (*pltsql_protocol_plugin_ptr)->set_guc_stat_var("babelfishpg_tsql.ansi_nulls", newval, NULL, 0); } /* @@ -395,107 +422,120 @@ static void assign_transform_null_equals (bool newval, void *extra) * Also tested that changing ANSI_DEFAULTS in a session don't change CURSOR_CLOSE_ON_COMMIT at all. * Thus I'm excluding CURSOR_CLOSE_ON_COMMIT from this assign function. */ -static void assign_ansi_defaults (bool newval, void *extra) +static void +assign_ansi_defaults(bool newval, void *extra) { - if (newval == false && escape_hatch_session_settings != EH_IGNORE) - { - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("OFF setting is not allowed for option ANSI_NULL_DFLT_ON, ANSI_PADDING and ANSI_WARNINGS. Please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); - } - else if (newval) - { - pltsql_ansi_nulls = true; - /* Call the assign hook function for ANSI_NULLS as well */ - assign_transform_null_equals (true, NULL); - - pltsql_ansi_warnings = true; - pltsql_ansi_null_dflt_on = true; - pltsql_ansi_padding = true; - pltsql_implicit_transactions = true; - pltsql_quoted_identifier = true; - - if (pltsql_protocol_plugin_ptr && *pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->set_guc_stat_var) + if (newval == false && escape_hatch_session_settings != EH_IGNORE) + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("OFF setting is not allowed for option ANSI_NULL_DFLT_ON, ANSI_PADDING and ANSI_WARNINGS. Please use babelfishpg_tsql.escape_hatch_session_settings to ignore"))); + } + else if (newval) { + pltsql_ansi_nulls = true; + /* Call the assign hook function for ANSI_NULLS as well */ + assign_transform_null_equals(true, NULL); + + pltsql_ansi_warnings = true; + pltsql_ansi_null_dflt_on = true; + pltsql_ansi_padding = true; + pltsql_implicit_transactions = true; + pltsql_quoted_identifier = true; + + if (pltsql_protocol_plugin_ptr && *pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->set_guc_stat_var) + { (*pltsql_protocol_plugin_ptr)->set_guc_stat_var("babelfishpg_tsql.ansi_defaults", newval, NULL, 0); (*pltsql_protocol_plugin_ptr)->set_guc_stat_var("babelfishpg_tsql.ansi_warnings", true, NULL, 0); (*pltsql_protocol_plugin_ptr)->set_guc_stat_var("babelfishpg_tsql.ansi_null_dflt_on", true, NULL, 0); (*pltsql_protocol_plugin_ptr)->set_guc_stat_var("babelfishpg_tsql.ansi_padding", true, NULL, 0); (*pltsql_protocol_plugin_ptr)->set_guc_stat_var("babelfishpg_tsql.quoted_identifier", true, NULL, 0); + } } - } - /* newval == false && escape_hatch_session_settings == EH_IGNORE, skip unsupported settings */ - else - { - pltsql_ansi_nulls = false; - /* Call the assign hook function for ANSI_NULLS as well */ - assign_transform_null_equals (false, NULL); - - pltsql_implicit_transactions = false; - pltsql_quoted_identifier = false; - if (pltsql_protocol_plugin_ptr && *pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->set_guc_stat_var) + /* + * newval == false && escape_hatch_session_settings == EH_IGNORE, skip + * unsupported settings + */ + else { + pltsql_ansi_nulls = false; + /* Call the assign hook function for ANSI_NULLS as well */ + assign_transform_null_equals(false, NULL); + + pltsql_implicit_transactions = false; + pltsql_quoted_identifier = false; + + if (pltsql_protocol_plugin_ptr && *pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->set_guc_stat_var) + { (*pltsql_protocol_plugin_ptr)->set_guc_stat_var("babelfishpg_tsql.ansi_defaults", newval, NULL, 0); (*pltsql_protocol_plugin_ptr)->set_guc_stat_var("babelfishpg_tsql.quoted_identifier", false, NULL, 0); - } + } - /* Skip ANSI_WARNINGS, ANSI_PADDING and ANSI_NULL_DFLT_ON */ - } + /* Skip ANSI_WARNINGS, ANSI_PADDING and ANSI_NULL_DFLT_ON */ + } } -static void assign_quoted_identifier (bool newval, void *extra) +static void +assign_quoted_identifier(bool newval, void *extra) { if (pltsql_protocol_plugin_ptr && *pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->set_guc_stat_var) - (*pltsql_protocol_plugin_ptr)->set_guc_stat_var("babelfishpg_tsql.quoted_identifier", newval, NULL, 0); + (*pltsql_protocol_plugin_ptr)->set_guc_stat_var("babelfishpg_tsql.quoted_identifier", newval, NULL, 0); } -static void assign_arithabort (bool newval, void *extra) +static void +assign_arithabort(bool newval, void *extra) { if (pltsql_protocol_plugin_ptr && *pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->set_guc_stat_var) - (*pltsql_protocol_plugin_ptr)->set_guc_stat_var("babelfishpg_tsql.arithabort", newval, NULL, 0); + (*pltsql_protocol_plugin_ptr)->set_guc_stat_var("babelfishpg_tsql.arithabort", newval, NULL, 0); } -static void assign_ansi_null_dflt_on (bool newval, void *extra) +static void +assign_ansi_null_dflt_on(bool newval, void *extra) { if (pltsql_protocol_plugin_ptr && *pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->set_guc_stat_var) - (*pltsql_protocol_plugin_ptr)->set_guc_stat_var("babelfishpg_tsql.ansi_null_dflt_on", newval, NULL, 0); + (*pltsql_protocol_plugin_ptr)->set_guc_stat_var("babelfishpg_tsql.ansi_null_dflt_on", newval, NULL, 0); } -static void assign_ansi_warnings (bool newval, void *extra) +static void +assign_ansi_warnings(bool newval, void *extra) { if (pltsql_protocol_plugin_ptr && *pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->set_guc_stat_var) - (*pltsql_protocol_plugin_ptr)->set_guc_stat_var("babelfishpg_tsql.ansi_warnings", newval, NULL, 0); + (*pltsql_protocol_plugin_ptr)->set_guc_stat_var("babelfishpg_tsql.ansi_warnings", newval, NULL, 0); } -static void assign_ansi_padding (bool newval, void *extra) +static void +assign_ansi_padding(bool newval, void *extra) { if (pltsql_protocol_plugin_ptr && *pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->set_guc_stat_var) - (*pltsql_protocol_plugin_ptr)->set_guc_stat_var("babelfishpg_tsql.ansi_padding", newval, NULL, 0); + (*pltsql_protocol_plugin_ptr)->set_guc_stat_var("babelfishpg_tsql.ansi_padding", newval, NULL, 0); } -static void assign_concat_null_yields_null (bool newval, void *extra) +static void +assign_concat_null_yields_null(bool newval, void *extra) { if (pltsql_protocol_plugin_ptr && *pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->set_guc_stat_var) - (*pltsql_protocol_plugin_ptr)->set_guc_stat_var("babelfishpg_tsql.concat_null_yields_null", newval, NULL, 0); + (*pltsql_protocol_plugin_ptr)->set_guc_stat_var("babelfishpg_tsql.concat_null_yields_null", newval, NULL, 0); } -static void assign_language (const char *newval, void *extra) +static void +assign_language(const char *newval, void *extra) { if (pltsql_language != NULL) { - char mbuf[1024]; + char mbuf[1024]; + snprintf(mbuf, sizeof(mbuf), "Changed language setting to '%s'", newval); if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->send_env_change && (*pltsql_protocol_plugin_ptr)->send_info) { ((*pltsql_protocol_plugin_ptr)->send_env_change) (2, newval, pltsql_language); - ((*pltsql_protocol_plugin_ptr)->send_info) (5703 /* number */, - 1 /* state */, - 10 /* class */, - mbuf /* message */, - 1 /* line number */); + ((*pltsql_protocol_plugin_ptr)->send_info) (5703 /* number */ , + 1 /* state */ , + 10 /* class */ , + mbuf /* message */ , + 1 /* line number */ ); } if (pltsql_protocol_plugin_ptr && *pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->set_guc_stat_var) @@ -506,14 +546,16 @@ static void assign_language (const char *newval, void *extra) static void assign_lock_timeout(int newval, void *extra) { - char timeout_str[16]; - /* PG's lock_timeout guc will take different values depending upon newval: - * newval = INT_MIN to -1: no time-out period (wait forever, PG's lock_timeout = 0) - * newval = 0 : not wait at all and return a message as soon as a lock is - * encountered. (no matching setting in PG, so we will set - * lock_timeout to smallest possible value = 1ms) - * newval = 1 to INT_MAX : number of milliseconds that will pass before returns a - * locking error. (PG's lock_timeout = newval) + char timeout_str[16]; + + /* + * PG's lock_timeout guc will take different values depending upon newval: + * newval = INT_MIN to -1: no time-out period (wait forever, PG's + * lock_timeout = 0) newval = 0 : not wait at all and return a + * message as soon as a lock is encountered. (no matching setting in PG, + * so we will set lock_timeout to smallest possible value = 1ms) newval = + * 1 to INT_MAX : number of milliseconds that will pass before returns a + * locking error. (PG's lock_timeout = newval) */ if (newval > 0) @@ -523,17 +565,18 @@ assign_lock_timeout(int newval, void *extra) else snprintf(timeout_str, sizeof(timeout_str), "%d", 0); SetConfigOption("lock_timeout", timeout_str, - PGC_USERSET, PGC_S_OVERRIDE); + PGC_USERSET, PGC_S_OVERRIDE); } -static void assign_datefirst (int newval, void *extra) +static void +assign_datefirst(int newval, void *extra) { if (pltsql_protocol_plugin_ptr && *pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->set_guc_stat_var) - (*pltsql_protocol_plugin_ptr)->set_guc_stat_var("babelfishpg_tsql.datefirst", false, NULL, newval); + (*pltsql_protocol_plugin_ptr)->set_guc_stat_var("babelfishpg_tsql.datefirst", false, NULL, newval); } void -define_escape_hatch_variables(void); + define_escape_hatch_variables(void); void define_custom_variables(void) @@ -541,237 +584,237 @@ define_custom_variables(void) define_escape_hatch_variables(); DefineCustomEnumVariable("babelfishpg_tsql.migration_mode", - gettext_noop("Defines if multiple user databases are supported"), - NULL, - &migration_mode, - SINGLE_DB, - migration_mode_options, - PGC_SUSET, /* only superuser can set */ - GUC_NO_RESET_ALL, - NULL, NULL, NULL); + gettext_noop("Defines if multiple user databases are supported"), + NULL, + &migration_mode, + SINGLE_DB, + migration_mode_options, + PGC_SUSET, /* only superuser can set */ + GUC_NO_RESET_ALL, + NULL, NULL, NULL); /* ANTLR parser */ DefineCustomBoolVariable("babelfishpg_tsql.dump_antlr_query_graph", - gettext_noop("dump query graph parsed by ANTLR parser to local disk"), - NULL, - &pltsql_dump_antlr_query_graph, - false, - PGC_SUSET, - GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("dump query graph parsed by ANTLR parser to local disk"), + NULL, + &pltsql_dump_antlr_query_graph, + false, + PGC_SUSET, + GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomBoolVariable("babelfishpg_tsql.enable_antlr_detailed_log", - gettext_noop("enable detailed ATNLR parser logging"), - NULL, - &pltsql_enable_antlr_detailed_log, - false, - PGC_SUSET, - GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("enable detailed ATNLR parser logging"), + NULL, + &pltsql_enable_antlr_detailed_log, + false, + PGC_SUSET, + GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomBoolVariable("babelfishpg_tsql.enable_sll_parse_mode", - gettext_noop("enable SLL parser mode for ANTLR parser"), - NULL, - &pltsql_enable_sll_parse_mode, - true, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("enable SLL parser mode for ANTLR parser"), + NULL, + &pltsql_enable_sll_parse_mode, + true, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); /* temporary GUC until test is refactored properly */ DefineCustomBoolVariable("babelfishpg_tsql.allow_antlr_to_unsupported_grammar_for_testing", - gettext_noop("GUC for internal testing - make antlr allow some of unsupported grammar"), - NULL, - &pltsql_allow_antlr_to_unsupported_grammar_for_testing, - false, - PGC_SUSET, /* only superuser can set */ - GUC_NO_SHOW_ALL, - NULL, NULL, NULL); + gettext_noop("GUC for internal testing - make antlr allow some of unsupported grammar"), + NULL, + &pltsql_allow_antlr_to_unsupported_grammar_for_testing, + false, + PGC_SUSET, /* only superuser can set */ + GUC_NO_SHOW_ALL, + NULL, NULL, NULL); /* temporary GUC for enable or disable windows login */ DefineCustomBoolVariable("babelfishpg_tsql.allow_windows_login", - gettext_noop("GUC for enable or disable windows login"), - NULL, - &pltsql_allow_windows_login, - true, - PGC_SUSET, - GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("GUC for enable or disable windows login"), + NULL, + &pltsql_allow_windows_login, + true, + PGC_SUSET, + GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); /* ISO standard settings */ DefineCustomBoolVariable("babelfishpg_tsql.ansi_defaults", - gettext_noop("Controls a group of settings that collectively specify some " - "ISO standard behavior. "), - NULL, - &pltsql_ansi_defaults, - true, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, assign_ansi_defaults, NULL); + gettext_noop("Controls a group of settings that collectively specify some " + "ISO standard behavior. "), + NULL, + &pltsql_ansi_defaults, + true, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, assign_ansi_defaults, NULL); DefineCustomBoolVariable("babelfishpg_tsql.quoted_identifier", - gettext_noop("Interpret double-quoted strings as quoted identifiers"), - NULL, - &pltsql_quoted_identifier, - true, - PGC_USERSET, - GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, assign_quoted_identifier, NULL); - + gettext_noop("Interpret double-quoted strings as quoted identifiers"), + NULL, + &pltsql_quoted_identifier, + true, + PGC_USERSET, + GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, assign_quoted_identifier, NULL); + DefineCustomBoolVariable("babelfishpg_tsql.concat_null_yields_null", - gettext_noop("If enabled, concatenating a NULL value produces a NULL result"), - NULL, - &pltsql_concat_null_yields_null, - true, - PGC_USERSET, 0, - NULL, assign_concat_null_yields_null, NULL); + gettext_noop("If enabled, concatenating a NULL value produces a NULL result"), + NULL, + &pltsql_concat_null_yields_null, + true, + PGC_USERSET, 0, + NULL, assign_concat_null_yields_null, NULL); DefineCustomBoolVariable("babelfishpg_tsql.ansi_nulls", - gettext_noop("Specifies ISO compliant behavior of the Equals (=) " - "and Not Equal To (<>) comparison operators when they " - "are used with null values."), - NULL, - &pltsql_ansi_nulls, - true, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, assign_transform_null_equals, NULL); + gettext_noop("Specifies ISO compliant behavior of the Equals (=) " + "and Not Equal To (<>) comparison operators when they " + "are used with null values."), + NULL, + &pltsql_ansi_nulls, + true, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, assign_transform_null_equals, NULL); DefineCustomBoolVariable("babelfishpg_tsql.ansi_null_dflt_on", - gettext_noop("Modifies the behavior of the session to override default nullability " - "of new columns when the ANSI null default option for the database is false."), + gettext_noop("Modifies the behavior of the session to override default nullability " + "of new columns when the ANSI null default option for the database is false."), - NULL, - &pltsql_ansi_null_dflt_on, - true, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - check_ansi_null_dflt_on, assign_ansi_null_dflt_on, NULL); + NULL, + &pltsql_ansi_null_dflt_on, + true, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + check_ansi_null_dflt_on, assign_ansi_null_dflt_on, NULL); DefineCustomBoolVariable("babelfishpg_tsql.ansi_null_dflt_off", - gettext_noop("Modifies the behavior of the session to override default nullability " - "of new columns when the ANSI null default option for the database is on."), + gettext_noop("Modifies the behavior of the session to override default nullability " + "of new columns when the ANSI null default option for the database is on."), - NULL, - &pltsql_ansi_null_dflt_off, - false, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - check_ansi_null_dflt_off, NULL, NULL); + NULL, + &pltsql_ansi_null_dflt_off, + false, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + check_ansi_null_dflt_off, NULL, NULL); DefineCustomBoolVariable("babelfishpg_tsql.ansi_padding", - gettext_noop("Controls the way the column stores values shorter than the defined size of the column, " - "and the way the column stores values that have trailing blanks in char, varchar, binary, and varbinary data."), + gettext_noop("Controls the way the column stores values shorter than the defined size of the column, " + "and the way the column stores values that have trailing blanks in char, varchar, binary, and varbinary data."), - NULL, - &pltsql_ansi_padding, - true, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - check_ansi_padding, assign_ansi_padding, NULL); + NULL, + &pltsql_ansi_padding, + true, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + check_ansi_padding, assign_ansi_padding, NULL); DefineCustomBoolVariable("babelfishpg_tsql.ansi_warnings", - gettext_noop("Specifies ISO standard behavior for several error conditions"), - NULL, - &pltsql_ansi_warnings, - true, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - check_ansi_warnings, assign_ansi_warnings, NULL); + gettext_noop("Specifies ISO standard behavior for several error conditions"), + NULL, + &pltsql_ansi_warnings, + true, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + check_ansi_warnings, assign_ansi_warnings, NULL); DefineCustomBoolVariable("babelfishpg_tsql.arithignore", - gettext_noop("Controls whether error messages are returned from overflow or " - "divide-by-zero errors during a query."), - NULL, - &pltsql_arithignore, - false, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - check_arithignore, NULL, NULL); + gettext_noop("Controls whether error messages are returned from overflow or " + "divide-by-zero errors during a query."), + NULL, + &pltsql_arithignore, + false, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + check_arithignore, NULL, NULL); DefineCustomBoolVariable("babelfishpg_tsql.arithabort", - gettext_noop("Ends a query when an overflow or divide-by-zero error occurs " - "during query execution."), - NULL, - &pltsql_arithabort, - true, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - check_arithabort, assign_arithabort, NULL); + gettext_noop("Ends a query when an overflow or divide-by-zero error occurs " + "during query execution."), + NULL, + &pltsql_arithabort, + true, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + check_arithabort, assign_arithabort, NULL); DefineCustomBoolVariable("babelfishpg_tsql.numeric_roundabort", - gettext_noop("Ends a query when an overflow or divide-by-zero error occurs " - "during query execution."), - NULL, - &pltsql_numeric_roundabort, - false, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - check_numeric_roundabort, NULL, NULL); + gettext_noop("Ends a query when an overflow or divide-by-zero error occurs " + "during query execution."), + NULL, + &pltsql_numeric_roundabort, + false, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + check_numeric_roundabort, NULL, NULL); DefineCustomBoolVariable("babelfishpg_tsql.nocount", - gettext_noop("Tsql compatibility NOCOUNT option."), - NULL, - &pltsql_nocount, - false, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("Tsql compatibility NOCOUNT option."), + NULL, + &pltsql_nocount, + false, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomStringVariable("babelfishpg_tsql.database_name", - gettext_noop("Predefined Babelfish database name"), - NULL, - &pltsql_database_name, - "babelfish_db", - PGC_SUSET, - GUC_NOT_IN_SAMPLE | GUC_NO_RESET_ALL, - NULL, NULL, NULL); + gettext_noop("Predefined Babelfish database name"), + NULL, + &pltsql_database_name, + "babelfish_db", + PGC_SUSET, + GUC_NOT_IN_SAMPLE | GUC_NO_RESET_ALL, + NULL, NULL, NULL); DefineCustomIntVariable("babelfishpg_tsql.datefirst", - gettext_noop("Sets the first day of the week to a number from 1 through 7."), - NULL, - &pltsql_datefirst, - 7, 1, 7, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, assign_datefirst, NULL); + gettext_noop("Sets the first day of the week to a number from 1 through 7."), + NULL, + &pltsql_datefirst, + 7, 1, 7, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, assign_datefirst, NULL); DefineCustomIntVariable("babelfishpg_tsql.rowcount", - gettext_noop("Causes the DB engine to stop processing the query after the " - "specified number of rows are returned."), - NULL, - &pltsql_rowcount, - 0, 0, INT_MAX, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("Causes the DB engine to stop processing the query after the " + "specified number of rows are returned."), + NULL, + &pltsql_rowcount, + 0, 0, INT_MAX, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomIntVariable("babelfishpg_tsql.lock_timeout", - gettext_noop("Specifies the number of milliseconds a statement waits for a lock to be released."), - NULL, - &pltsql_lock_timeout, - -1, INT_MIN, INT_MAX, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, assign_lock_timeout, NULL); + gettext_noop("Specifies the number of milliseconds a statement waits for a lock to be released."), + NULL, + &pltsql_lock_timeout, + -1, INT_MIN, INT_MAX, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, assign_lock_timeout, NULL); DefineCustomStringVariable("babelfishpg_tsql.version", - gettext_noop("Sets the output of @@VERSION variable"), - NULL, - &pltsql_version, - "default", - PGC_SUSET, - GUC_NOT_IN_SAMPLE, - check_tsql_version, NULL, NULL); + gettext_noop("Sets the output of @@VERSION variable"), + NULL, + &pltsql_version, + "default", + PGC_SUSET, + GUC_NOT_IN_SAMPLE, + check_tsql_version, NULL, NULL); DefineCustomStringVariable("babelfishpg_tsql.language", - gettext_noop("T-SQL compatibility LANGUAGE option."), - NULL, - &pltsql_language, - "us_english", /* TODO correct boot value? */ - PGC_USERSET, 0, - check_language, assign_language, NULL); + gettext_noop("T-SQL compatibility LANGUAGE option."), + NULL, + &pltsql_language, + "us_english", /* TODO correct boot value? */ + PGC_USERSET, 0, + check_language, assign_language, NULL); DefineCustomBoolVariable("babelfishpg_tsql.xact_abort", gettext_noop("enable xact abort"), @@ -838,130 +881,130 @@ define_custom_variables(void) NULL, NULL, NULL); DefineCustomBoolVariable("babelfishpg_tsql.noexec", - gettext_noop("SQL-Server compatibility NOEXEC option."), - NULL, - &pltsql_noexec, - false, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - check_noexec, NULL, NULL); + gettext_noop("SQL-Server compatibility NOEXEC option."), + NULL, + &pltsql_noexec, + false, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + check_noexec, NULL, NULL); DefineCustomBoolVariable("babelfishpg_tsql.fmtonly", - gettext_noop("SQL-Server compatibility FMTONLY option."), - NULL, - &pltsql_fmtonly, - false, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("SQL-Server compatibility FMTONLY option."), + NULL, + &pltsql_fmtonly, + false, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomBoolVariable("babelfishpg_tsql.showplan_all", - gettext_noop("SQL-Server compatibility SHOWPLAN_ALL option."), - NULL, - &pltsql_showplan_all, - false, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - check_showplan_all, NULL, NULL); + gettext_noop("SQL-Server compatibility SHOWPLAN_ALL option."), + NULL, + &pltsql_showplan_all, + false, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + check_showplan_all, NULL, NULL); DefineCustomBoolVariable("babelfishpg_tsql.showplan_text", - gettext_noop("SQL-Server compatibility SHOWPLAN_TEXT option."), - NULL, - &pltsql_showplan_text, - false, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - check_showplan_text, NULL, NULL); + gettext_noop("SQL-Server compatibility SHOWPLAN_TEXT option."), + NULL, + &pltsql_showplan_text, + false, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + check_showplan_text, NULL, NULL); DefineCustomBoolVariable("babelfishpg_tsql.no_browsetable", - gettext_noop("SQL-Server compatibility NO_BROWSETABLE option."), - NULL, - &pltsql_no_browsetable, - true, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - check_no_browsetable, NULL, NULL); - + gettext_noop("SQL-Server compatibility NO_BROWSETABLE option."), + NULL, + &pltsql_no_browsetable, + true, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + check_no_browsetable, NULL, NULL); + DefineCustomBoolVariable("babelfishpg_tsql.showplan_xml", - gettext_noop("SQL-Server compatibility SHOWPLAN_XML option."), - NULL, - &pltsql_showplan_xml, - false, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - check_showplan_xml, NULL, NULL); + gettext_noop("SQL-Server compatibility SHOWPLAN_XML option."), + NULL, + &pltsql_showplan_xml, + false, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + check_showplan_xml, NULL, NULL); DefineCustomBoolVariable("babelfishpg_tsql.enable_tsql_information_schema", - gettext_noop("toggles between the information_schema for postgres and tsql"), - NULL, - &pltsql_enable_tsql_information_schema, - false, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("toggles between the information_schema for postgres and tsql"), + NULL, + &pltsql_enable_tsql_information_schema, + false, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); /* EXPLAIN-related GUCs */ DefineCustomBoolVariable("babelfishpg_tsql.explain_verbose", - gettext_noop("Display additional information regarding the plan"), - NULL, - &pltsql_explain_verbose, - false, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("Display additional information regarding the plan"), + NULL, + &pltsql_explain_verbose, + false, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomBoolVariable("babelfishpg_tsql.explain_costs", - gettext_noop("Include information on estimated startup and total cost"), - NULL, - &pltsql_explain_costs, - true, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("Include information on estimated startup and total cost"), + NULL, + &pltsql_explain_costs, + true, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomBoolVariable("babelfishpg_tsql.explain_settings", - gettext_noop("Include information on configuration parameters"), - NULL, - &pltsql_explain_settings, - false, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("Include information on configuration parameters"), + NULL, + &pltsql_explain_settings, + false, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomBoolVariable("babelfishpg_tsql.explain_buffers", - gettext_noop("Include information on buffer usage"), - NULL, - &pltsql_explain_buffers, - false, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("Include information on buffer usage"), + NULL, + &pltsql_explain_buffers, + false, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomBoolVariable("babelfishpg_tsql.explain_wal", - gettext_noop("Include information on WAL record generation"), - NULL, - &pltsql_explain_wal, - false, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("Include information on WAL record generation"), + NULL, + &pltsql_explain_wal, + false, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomBoolVariable("babelfishpg_tsql.explain_timing", - gettext_noop("Include actual startup time and time spent in each node in the output"), - NULL, - &pltsql_explain_timing, - true, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("Include actual startup time and time spent in each node in the output"), + NULL, + &pltsql_explain_timing, + true, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomBoolVariable("babelfishpg_tsql.explain_summary", - gettext_noop("Include summary information (e.g., totaled timing information) after the query plan"), - NULL, - &pltsql_explain_summary, - true, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("Include summary information (e.g., totaled timing information) after the query plan"), + NULL, + &pltsql_explain_summary, + true, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomEnumVariable("babelfishpg_tsql.explain_format", "Specify the output format, which can be TEXT, XML, JSON, or YAML", @@ -973,500 +1016,500 @@ define_custom_variables(void) GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, NULL, NULL, NULL); - /* Host info related GUCs*/ + /* Host info related GUCs */ DefineCustomStringVariable("babelfishpg_tsql.host_distribution", - gettext_noop("Sets host distribution"), - NULL, - &pltsql_host_destribution, - "", - PGC_SIGHUP, - GUC_NOT_IN_SAMPLE, - NULL, NULL, NULL); + gettext_noop("Sets host distribution"), + NULL, + &pltsql_host_destribution, + "", + PGC_SIGHUP, + GUC_NOT_IN_SAMPLE, + NULL, NULL, NULL); DefineCustomStringVariable("babelfishpg_tsql.host_release", - gettext_noop("Sets host release"), - NULL, - &pltsql_host_release, - "", - PGC_SIGHUP, - GUC_NOT_IN_SAMPLE, - NULL, NULL, NULL); + gettext_noop("Sets host release"), + NULL, + &pltsql_host_release, + "", + PGC_SIGHUP, + GUC_NOT_IN_SAMPLE, + NULL, NULL, NULL); DefineCustomStringVariable("babelfishpg_tsql.host_service_pack_level", - gettext_noop("Sets host service pack level"), - NULL, - &pltsql_host_service_pack_level, - "", - PGC_SIGHUP, - GUC_NOT_IN_SAMPLE, - NULL, NULL, NULL); + gettext_noop("Sets host service pack level"), + NULL, + &pltsql_host_service_pack_level, + "", + PGC_SIGHUP, + GUC_NOT_IN_SAMPLE, + NULL, NULL, NULL); /* - * Block DDL from PG endpoint - * Currently only blocks DDLs for View object + * Block DDL from PG endpoint Currently only blocks DDLs for View object */ DefineCustomBoolVariable("babelfishpg_tsql.enable_create_alter_view_from_pg", - gettext_noop("Enables blocked DDL statements from PG endpoint"), - NULL, - &pltsql_enable_create_alter_view_from_pg, - false, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("Enables blocked DDL statements from PG endpoint"), + NULL, + &pltsql_enable_create_alter_view_from_pg, + false, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); /* Dump and Restore */ DefineCustomBoolVariable("babelfishpg_tsql.dump_restore", - gettext_noop("Enable special handlings during dump and restore"), - NULL, - &babelfish_dump_restore, - false, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("Enable special handlings during dump and restore"), + NULL, + &babelfish_dump_restore, + false, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomBoolVariable("babelfishpg_tsql.restore_tsql_tabletype", - gettext_noop("Shows that if a table is creating a T-SQL table type during restore"), - NULL, - &restore_tsql_tabletype, - false, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("Shows that if a table is creating a T-SQL table type during restore"), + NULL, + &restore_tsql_tabletype, + false, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomStringVariable("babelfishpg_tsql.dump_restore_min_oid", - gettext_noop("All new OIDs should be greater than this number during dump and restore"), - NULL, - &babelfish_dump_restore_min_oid, - NULL, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - check_babelfish_dump_restore_min_oid, NULL, NULL); + gettext_noop("All new OIDs should be greater than this number during dump and restore"), + NULL, + &babelfish_dump_restore_min_oid, + NULL, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + check_babelfish_dump_restore_min_oid, NULL, NULL); /* T-SQL Hint Mapping */ DefineCustomBoolVariable("babelfishpg_tsql.enable_hint_mapping", - gettext_noop("Enables T-SQL hint mapping in ANTLR parser"), - NULL, - &enable_hint_mapping, - true, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("Enables T-SQL hint mapping in ANTLR parser"), + NULL, + &enable_hint_mapping, + true, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomBoolVariable("babelfishpg_tsql.enable_pg_hint", - gettext_noop("Loads and enables pg_hint_plan library"), - NULL, - &enable_pg_hint, - false, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, assign_enable_pg_hint, NULL); + gettext_noop("Loads and enables pg_hint_plan library"), + NULL, + &enable_pg_hint, + false, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, assign_enable_pg_hint, NULL); DefineCustomIntVariable("babelfishpg_tsql.insert_bulk_rows_per_batch", - gettext_noop("Sets the number of rows per batch to be processed for Insert Bulk"), - NULL, - &insert_bulk_rows_per_batch, - DEFAULT_INSERT_BULK_ROWS_PER_BATCH, 1, INT_MAX, - PGC_USERSET, - GUC_NOT_IN_SAMPLE, - NULL, NULL, NULL); + gettext_noop("Sets the number of rows per batch to be processed for Insert Bulk"), + NULL, + &insert_bulk_rows_per_batch, + DEFAULT_INSERT_BULK_ROWS_PER_BATCH, 1, INT_MAX, + PGC_USERSET, + GUC_NOT_IN_SAMPLE, + NULL, NULL, NULL); DefineCustomIntVariable("babelfishpg_tsql.insert_bulk_kilobytes_per_batch", - gettext_noop("Sets the number of bytes per batch to be processed for Insert Bulk"), - NULL, - &insert_bulk_kilobytes_per_batch, - DEFAULT_INSERT_BULK_PACKET_SIZE, 1, INT_MAX, - PGC_USERSET, - GUC_NOT_IN_SAMPLE, - NULL, NULL, NULL); + gettext_noop("Sets the number of bytes per batch to be processed for Insert Bulk"), + NULL, + &insert_bulk_kilobytes_per_batch, + DEFAULT_INSERT_BULK_PACKET_SIZE, 1, INT_MAX, + PGC_USERSET, + GUC_NOT_IN_SAMPLE, + NULL, NULL, NULL); DefineCustomBoolVariable("babelfishpg_tsql.enable_metadata_inconsistency_check", - gettext_noop("Enables babelfish_inconsistent_metadata"), - NULL, - &enable_metadata_inconsistency_check, - true, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("Enables babelfish_inconsistent_metadata"), + NULL, + &enable_metadata_inconsistency_check, + true, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomBoolVariable("babelfishpg_tsql.enable_linked_servers", - gettext_noop("Enables linked servers"), - NULL, - &pltsql_enable_linked_servers, - true, - PGC_SUSET, - GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("Enables linked servers"), + NULL, + &pltsql_enable_linked_servers, + true, + PGC_SUSET, + GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); } -int escape_hatch_storage_options = EH_IGNORE; -int escape_hatch_storage_on_partition = EH_STRICT; -int escape_hatch_database_misc_options = EH_IGNORE; -int escape_hatch_language_non_english = EH_STRICT; -int escape_hatch_login_hashed_password = EH_STRICT; -int escape_hatch_login_old_password = EH_STRICT; -int escape_hatch_login_password_must_change = EH_STRICT; -int escape_hatch_login_password_unlock = EH_STRICT; -int escape_hatch_login_misc_options = EH_STRICT; -int escape_hatch_compatibility_level = EH_IGNORE; -int escape_hatch_fulltext = EH_STRICT; -int escape_hatch_schemabinding_function = EH_IGNORE; -int escape_hatch_schemabinding_trigger = EH_IGNORE; -int escape_hatch_schemabinding_procedure = EH_IGNORE; -int escape_hatch_schemabinding_view = EH_IGNORE; -int escape_hatch_index_clustering = EH_IGNORE; -int escape_hatch_index_columnstore = EH_STRICT; -int escape_hatch_for_replication = EH_STRICT; -int escape_hatch_rowguidcol_column = EH_IGNORE; -int escape_hatch_nocheck_add_constraint = EH_STRICT; -int escape_hatch_nocheck_existing_constraint = EH_STRICT; -int escape_hatch_constraint_name_for_default = EH_IGNORE; -int escape_hatch_table_hints = EH_IGNORE; -int escape_hatch_query_hints = EH_IGNORE; -int escape_hatch_join_hints = EH_IGNORE; -int escape_hatch_session_settings = EH_IGNORE; -int escape_hatch_unique_constraint = EH_STRICT; -int escape_hatch_ignore_dup_key = EH_STRICT; -int escape_hatch_rowversion = EH_STRICT; -int escape_hatch_showplan_all = EH_STRICT; -int escape_hatch_checkpoint = EH_IGNORE; +int escape_hatch_storage_options = EH_IGNORE; +int escape_hatch_storage_on_partition = EH_STRICT; +int escape_hatch_database_misc_options = EH_IGNORE; +int escape_hatch_language_non_english = EH_STRICT; +int escape_hatch_login_hashed_password = EH_STRICT; +int escape_hatch_login_old_password = EH_STRICT; +int escape_hatch_login_password_must_change = EH_STRICT; +int escape_hatch_login_password_unlock = EH_STRICT; +int escape_hatch_login_misc_options = EH_STRICT; +int escape_hatch_compatibility_level = EH_IGNORE; +int escape_hatch_fulltext = EH_STRICT; +int escape_hatch_schemabinding_function = EH_IGNORE; +int escape_hatch_schemabinding_trigger = EH_IGNORE; +int escape_hatch_schemabinding_procedure = EH_IGNORE; +int escape_hatch_schemabinding_view = EH_IGNORE; +int escape_hatch_index_clustering = EH_IGNORE; +int escape_hatch_index_columnstore = EH_STRICT; +int escape_hatch_for_replication = EH_STRICT; +int escape_hatch_rowguidcol_column = EH_IGNORE; +int escape_hatch_nocheck_add_constraint = EH_STRICT; +int escape_hatch_nocheck_existing_constraint = EH_STRICT; +int escape_hatch_constraint_name_for_default = EH_IGNORE; +int escape_hatch_table_hints = EH_IGNORE; +int escape_hatch_query_hints = EH_IGNORE; +int escape_hatch_join_hints = EH_IGNORE; +int escape_hatch_session_settings = EH_IGNORE; +int escape_hatch_unique_constraint = EH_STRICT; +int escape_hatch_ignore_dup_key = EH_STRICT; +int escape_hatch_rowversion = EH_STRICT; +int escape_hatch_showplan_all = EH_STRICT; +int escape_hatch_checkpoint = EH_IGNORE; void define_escape_hatch_variables(void) { /* storage_options */ DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_storage_options", - gettext_noop("escape hatch for storage options option in CREATE/ALTER TABLE/INDEX"), - NULL, - &escape_hatch_storage_options, - EH_IGNORE, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for storage options option in CREATE/ALTER TABLE/INDEX"), + NULL, + &escape_hatch_storage_options, + EH_IGNORE, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); /* storage_on_partition */ DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_storage_on_partition", - gettext_noop("escape hatch for storage_on_partition option in CREATE/ALTER TABLE and CREATE INDEX"), - NULL, - &escape_hatch_storage_on_partition, - EH_STRICT, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for storage_on_partition option in CREATE/ALTER TABLE and CREATE INDEX"), + NULL, + &escape_hatch_storage_on_partition, + EH_STRICT, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); /* database_misc_options */ DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_database_misc_options", - gettext_noop("escape hatch for misc options in CREATE/ALTER DATABASE"), - NULL, - &escape_hatch_database_misc_options, - EH_IGNORE, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for misc options in CREATE/ALTER DATABASE"), + NULL, + &escape_hatch_database_misc_options, + EH_IGNORE, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); /* language non_english */ DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_language_non_english", - gettext_noop("escape hatch for non-english language"), - NULL, - &escape_hatch_language_non_english, - EH_STRICT, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for non-english language"), + NULL, + &escape_hatch_language_non_english, + EH_STRICT, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); /* login hashed password */ DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_login_hashed_password", - gettext_noop("escape hatch for login hashed passwords"), - NULL, - &escape_hatch_login_hashed_password, - EH_STRICT, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for login hashed passwords"), + NULL, + &escape_hatch_login_hashed_password, + EH_STRICT, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); /* login old password */ DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_login_old_password", - gettext_noop("escape hatch for login old passwords"), - NULL, - &escape_hatch_login_old_password, - EH_STRICT, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for login old passwords"), + NULL, + &escape_hatch_login_old_password, + EH_STRICT, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); /* login password must_change */ DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_login_password_must_change", - gettext_noop("escape hatch for login passwords must_change option"), - NULL, - &escape_hatch_login_password_must_change, - EH_STRICT, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for login passwords must_change option"), + NULL, + &escape_hatch_login_password_must_change, + EH_STRICT, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); /* login password unlock */ DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_login_password_unlock", - gettext_noop("escape hatch for login passwords unlock option"), - NULL, - &escape_hatch_login_password_unlock, - EH_STRICT, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for login passwords unlock option"), + NULL, + &escape_hatch_login_password_unlock, + EH_STRICT, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); /* login misc options */ DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_login_misc_options", - gettext_noop("escape hatch for login miscellaneous options"), - NULL, - &escape_hatch_login_misc_options, - EH_STRICT, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for login miscellaneous options"), + NULL, + &escape_hatch_login_misc_options, + EH_STRICT, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); /* compatibility_level */ - /* disable escape_hatch_compatibility_level as long as we block all ALTER DATABASE */ /* - DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_compatibility_level", - gettext_noop("escape hatch for compatibility level"), - NULL, - &escape_hatch_compatibility_level, - EH_IGNORE, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); - */ + * disable escape_hatch_compatibility_level as long as we block all ALTER + * DATABASE + */ + + /* + * + * DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_compatibility_level", + * gettext_noop("escape hatch for compatibility level"), NULL, + * &escape_hatch_compatibility_level, EH_IGNORE, escape_hatch_options, + * PGC_USERSET, GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | + * GUC_DISALLOW_IN_AUTO_FILE, NULL, NULL, NULL); + */ /* fulltext */ DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_fulltext", - gettext_noop("escape hatch for fulltext"), - NULL, - &escape_hatch_fulltext, - EH_STRICT, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for fulltext"), + NULL, + &escape_hatch_fulltext, + EH_STRICT, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); /* schemabinding */ DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_schemabinding_function", - gettext_noop("escape hatch for SCHEMABINDING option in CREATE FUNCTION"), - NULL, - &escape_hatch_schemabinding_function, - EH_IGNORE, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for SCHEMABINDING option in CREATE FUNCTION"), + NULL, + &escape_hatch_schemabinding_function, + EH_IGNORE, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_schemabinding_trigger", - gettext_noop("escape hatch for SCHEMABINDING option in CREATE TRIGGER"), - NULL, - &escape_hatch_schemabinding_trigger, - EH_IGNORE, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for SCHEMABINDING option in CREATE TRIGGER"), + NULL, + &escape_hatch_schemabinding_trigger, + EH_IGNORE, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_schemabinding_procedure", - gettext_noop("escape hatch for SCHEMABINDING option in CREATE PROCEDURE"), - NULL, - &escape_hatch_schemabinding_procedure, - EH_IGNORE, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for SCHEMABINDING option in CREATE PROCEDURE"), + NULL, + &escape_hatch_schemabinding_procedure, + EH_IGNORE, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_schemabinding_view", - gettext_noop("escape hatch for SCHEMABINDING option in CREATE VIEW"), - NULL, - &escape_hatch_schemabinding_view, - EH_IGNORE, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for SCHEMABINDING option in CREATE VIEW"), + NULL, + &escape_hatch_schemabinding_view, + EH_IGNORE, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); /* index clustering */ DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_index_clustering", - gettext_noop("escape hatch for CLUSTERED option in CREATE INDEX"), - NULL, - &escape_hatch_index_clustering, - EH_IGNORE, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for CLUSTERED option in CREATE INDEX"), + NULL, + &escape_hatch_index_clustering, + EH_IGNORE, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); /* index columnstore */ DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_index_columnstore", - gettext_noop("escape hatch for COLUMNSTORE option in CREATE INDEX"), - NULL, - &escape_hatch_index_columnstore, - EH_STRICT, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for COLUMNSTORE option in CREATE INDEX"), + NULL, + &escape_hatch_index_columnstore, + EH_STRICT, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); /* for_replication */ DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_for_replication", - gettext_noop("escape hatch for (NOT) FOR REPLICATION option"), - NULL, - &escape_hatch_for_replication, - EH_STRICT, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for (NOT) FOR REPLICATION option"), + NULL, + &escape_hatch_for_replication, + EH_STRICT, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); /* ROWGUIDCOL */ DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_rowguidcol_column", - gettext_noop("escape hatch for ROWGUIDCOL option"), - NULL, - &escape_hatch_rowguidcol_column, - EH_IGNORE, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for ROWGUIDCOL option"), + NULL, + &escape_hatch_rowguidcol_column, + EH_IGNORE, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); /* with [no]check */ DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_nocheck_add_constraint", - gettext_noop("escape hatch for WITH [NO]CHECK option in alter table add"), - NULL, - &escape_hatch_nocheck_add_constraint, - EH_STRICT, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for WITH [NO]CHECK option in alter table add"), + NULL, + &escape_hatch_nocheck_add_constraint, + EH_STRICT, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_nocheck_existing_constraint", - gettext_noop("escape hatch for WITH [NO]CHECK option in alter table on exsiting constraint"), - NULL, - &escape_hatch_nocheck_existing_constraint, - EH_STRICT, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for WITH [NO]CHECK option in alter table on exsiting constraint"), + NULL, + &escape_hatch_nocheck_existing_constraint, + EH_STRICT, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); /* escape_hatch_constraint_name_for_default */ DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_constraint_name_for_default", - gettext_noop("escape hatch for DEFAULT option in alter table add constraint"), - NULL, - &escape_hatch_constraint_name_for_default, - EH_IGNORE, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for DEFAULT option in alter table add constraint"), + NULL, + &escape_hatch_constraint_name_for_default, + EH_IGNORE, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); /* hints */ DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_table_hints", - gettext_noop("escape hatch for table hints"), - NULL, - &escape_hatch_table_hints, - EH_IGNORE, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for table hints"), + NULL, + &escape_hatch_table_hints, + EH_IGNORE, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_query_hints", - gettext_noop("escape hatch for query hints"), - NULL, - &escape_hatch_query_hints, - EH_IGNORE, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for query hints"), + NULL, + &escape_hatch_query_hints, + EH_IGNORE, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_join_hints", - gettext_noop("escape hatch for join hints"), - NULL, - &escape_hatch_join_hints, - EH_IGNORE, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for join hints"), + NULL, + &escape_hatch_join_hints, + EH_IGNORE, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_session_settings", - gettext_noop("escape hatch for session settings"), - NULL, - &escape_hatch_session_settings, - EH_IGNORE, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for session settings"), + NULL, + &escape_hatch_session_settings, + EH_IGNORE, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_unique_constraint", - gettext_noop("escape hatch for unique constraint"), - NULL, - &escape_hatch_unique_constraint, - EH_STRICT, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for unique constraint"), + NULL, + &escape_hatch_unique_constraint, + EH_STRICT, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); /* Ignore_dup_key */ DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_ignore_dup_key", - gettext_noop("escape hatch for ignore_dup_key=on option in CREATE/ALTER TABLE/INDEX"), - NULL, - &escape_hatch_ignore_dup_key, - EH_STRICT, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for ignore_dup_key=on option in CREATE/ALTER TABLE/INDEX"), + NULL, + &escape_hatch_ignore_dup_key, + EH_STRICT, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_rowversion", - gettext_noop("escape hatch for TIMESTAMP/ROWVERSION columns"), - NULL, - &escape_hatch_rowversion, - EH_STRICT, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for TIMESTAMP/ROWVERSION columns"), + NULL, + &escape_hatch_rowversion, + EH_STRICT, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); /* SHOWPLAN_ALL */ DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_showplan_all", - gettext_noop("escape hatch for SHOWPLAN_ALL and STATISTICS PROFILE"), - NULL, - &escape_hatch_showplan_all, - EH_STRICT, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for SHOWPLAN_ALL and STATISTICS PROFILE"), + NULL, + &escape_hatch_showplan_all, + EH_STRICT, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); /* CHECKPOINT */ DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_checkpoint", - gettext_noop("escape hatch for CHECKPOINT"), - NULL, - &escape_hatch_checkpoint, - EH_IGNORE, - escape_hatch_options, - PGC_USERSET, - GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("escape hatch for CHECKPOINT"), + NULL, + &escape_hatch_checkpoint, + EH_IGNORE, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); } void @@ -1497,4 +1540,4 @@ bool metadata_inconsistency_check_enabled(void) { return enable_metadata_inconsistency_check; -} \ No newline at end of file +} diff --git a/contrib/babelfishpg_tsql/src/guc.h b/contrib/babelfishpg_tsql/src/guc.h index c0a06f8e00..44343841ff 100644 --- a/contrib/babelfishpg_tsql/src/guc.h +++ b/contrib/babelfishpg_tsql/src/guc.h @@ -1,8 +1,14 @@ #ifndef PLTSQL_GUC_H #define PLTSQL_GUC_H -typedef enum MigrationMode { SINGLE_DB, MULTI_DB } MigrationMode; -typedef enum EscapeHatchOption { EH_STRICT, EH_IGNORE, EH_NULL } EscapeHatchOption; +typedef enum MigrationMode +{ + SINGLE_DB, MULTI_DB +} MigrationMode; +typedef enum EscapeHatchOption +{ + EH_STRICT, EH_IGNORE, EH_NULL +} EscapeHatchOption; extern bool pltsql_fmtonly; extern bool pltsql_enable_create_alter_view_from_pg; @@ -17,13 +23,14 @@ extern void pltsql_validate_set_config_function(char *name, char *value); ************************************/ extern MigrationMode get_migration_mode(void); -extern bool metadata_inconsistency_check_enabled(void); +extern bool metadata_inconsistency_check_enabled(void); + /* * Defined in pl_handler.c for managing GUC stack */ -int pltsql_new_guc_nest_level(void); -void pltsql_revert_guc(int nest_level); +int pltsql_new_guc_nest_level(void); +void pltsql_revert_guc(int nest_level); -extern int pltsql_new_scope_identity_nest_level(void); +extern int pltsql_new_scope_identity_nest_level(void); extern void pltsql_revert_last_scope_identity(int nest_level); #endif diff --git a/contrib/babelfishpg_tsql/src/hooks.c b/contrib/babelfishpg_tsql/src/hooks.c index 87b82f7c26..bdcd1098d2 100644 --- a/contrib/babelfishpg_tsql/src/hooks.c +++ b/contrib/babelfishpg_tsql/src/hooks.c @@ -76,40 +76,40 @@ extern bool pltsql_ansi_nulls; *****************************************/ IsExtendedCatalogHookType PrevIsExtendedCatalogHook = NULL; static bool PlTsqlMatchNamedCall(HeapTuple proctup, int nargs, List *argnames, - bool include_out_arguments, int pronargs, - int **argnumbers, List **defaults); + bool include_out_arguments, int pronargs, + int **argnumbers, List **defaults); static bool match_pltsql_func_call(HeapTuple proctup, int nargs, List *argnames, bool include_out_arguments, int **argnumbers, List **defaults, bool expand_defaults, bool expand_variadic, bool *use_defaults, bool *any_special, bool *variadic, Oid *va_elem_type); -static ObjectAddress get_trigger_object_address(List *object, Relation *relp, bool missing_ok,bool object_from_input); -Oid get_tsql_trigger_oid(List *object, const char *tsql_trigger_name,bool object_from_input); -static Node* transform_like_in_add_constraint (Node* node); +static ObjectAddress get_trigger_object_address(List *object, Relation *relp, bool missing_ok, bool object_from_input); +Oid get_tsql_trigger_oid(List *object, const char *tsql_trigger_name, bool object_from_input); +static Node *transform_like_in_add_constraint(Node *node); /***************************************** * Analyzer Hooks *****************************************/ -static int pltsql_set_target_table_alternative(ParseState *pstate, Node *stmt, CmdType command); +static int pltsql_set_target_table_alternative(ParseState *pstate, Node *stmt, CmdType command); static void set_output_clause_transformation_info(bool enabled); static bool get_output_clause_transformation_info(void); static Node *output_update_self_join_transformation(ParseState *pstate, UpdateStmt *stmt, Query *query); static void handle_returning_qualifiers(Query *query, List *returningList, ParseState *pstate); static void check_insert_row(List *icolumns, List *exprList, Oid relid); -static void pltsql_post_transform_column_definition(ParseState *pstate, RangeVar* relation, ColumnDef *column, List **alist); -static void pltsql_post_transform_table_definition(ParseState *pstate, RangeVar* relation, char *relname, List **alist); +static void pltsql_post_transform_column_definition(ParseState *pstate, RangeVar *relation, ColumnDef *column, List **alist); +static void pltsql_post_transform_table_definition(ParseState *pstate, RangeVar *relation, char *relname, List **alist); static void pre_transform_target_entry(ResTarget *res, ParseState *pstate, ParseExprKind exprKind); static bool tle_name_comparison(const char *tlename, const char *identifier); static void resolve_target_list_unknowns(ParseState *pstate, List *targetlist); static inline bool is_identifier_char(char c); -static int find_attr_by_name_from_relation(Relation rd, const char *attname, bool sysColOK); +static int find_attr_by_name_from_relation(Relation rd, const char *attname, bool sysColOK); static void modify_insert_stmt(InsertStmt *stmt, Oid relid); static void modify_RangeTblFunction_tupdesc(char *funcname, Node *expr, TupleDesc *tupdesc); /***************************************** * Commands Hooks *****************************************/ -static int find_attr_by_name_from_column_def_list(const char *attributeName, List *schema); +static int find_attr_by_name_from_column_def_list(const char *attributeName, List *schema); static void pltsql_drop_func_default_positions(Oid objectId); static void fill_missing_values_in_copyfrom(Relation rel, Datum *values, bool *nulls); @@ -121,12 +121,13 @@ extern PLtsql_execstate *get_outermost_tsql_estate(int *nestlevel); extern PLtsql_execstate *get_current_tsql_estate(); static void pltsql_store_view_definition(const char *queryString, ObjectAddress address); static void pltsql_drop_view_definition(Oid objectId); -static void preserve_view_constraints_from_base_table(ColumnDef *col, Oid tableOid, AttrNumber colId); +static void preserve_view_constraints_from_base_table(ColumnDef *col, Oid tableOid, AttrNumber colId); static bool pltsql_detect_numeric_overflow(int weight, int dscale, int first_block, int numeric_base); static void insert_pltsql_function_defaults(HeapTuple func_tuple, List *defaults, Node **argarray); -static int print_pltsql_function_arguments(StringInfo buf, HeapTuple proctup, bool print_table_args, bool print_defaults); +static int print_pltsql_function_arguments(StringInfo buf, HeapTuple proctup, bool print_table_args, bool print_defaults); static void pltsql_GetNewObjectId(VariableCache variableCache); static void pltsql_validate_var_datatype_scale(const TypeName *typeName, Type typ); + /***************************************** * Executor Hooks *****************************************/ @@ -154,7 +155,7 @@ static char *gen_func_arg_list(Oid objectId); /***************************************** * Planner Hook *****************************************/ -static PlannedStmt * pltsql_planner_hook(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams); +static PlannedStmt *pltsql_planner_hook(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams); /* Save hook values in case of unload */ static core_yylex_hook_type prev_core_yylex_hook = NULL; @@ -289,7 +290,7 @@ InstallExtendedHooks(void) prev_validate_var_datatype_scale_hook = validate_var_datatype_scale_hook; validate_var_datatype_scale_hook = pltsql_validate_var_datatype_scale; - + prev_modify_RangeTblFunction_tupdesc_hook = modify_RangeTblFunction_tupdesc_hook; modify_RangeTblFunction_tupdesc_hook = modify_RangeTblFunction_tupdesc; @@ -311,7 +312,7 @@ UninstallExtendedHooks(void) get_output_clause_status_hook = NULL; pre_output_clause_transformation_hook = NULL; pre_transform_returning_hook = prev_pre_transform_returning_hook; - pre_transform_insert_hook = prev_pre_transform_insert_hook ; + pre_transform_insert_hook = prev_pre_transform_insert_hook; post_transform_insert_row_hook = prev_post_transform_insert_row_hook; post_transform_column_definition_hook = NULL; post_transform_table_definition_hook = NULL; @@ -350,7 +351,7 @@ UninstallExtendedHooks(void) static void pltsql_GetNewObjectId(VariableCache variableCache) { - Oid minOid; + Oid minOid; if (!babelfish_dump_restore || !babelfish_dump_restore_min_oid) return; @@ -367,10 +368,12 @@ pltsql_GetNewObjectId(VariableCache variableCache) static void pltsql_ExecutorStart(QueryDesc *queryDesc, int eflags) { - int ef = pltsql_explain_only ? EXEC_FLAG_EXPLAIN_ONLY : eflags; + int ef = pltsql_explain_only ? EXEC_FLAG_EXPLAIN_ONLY : eflags; + if (pltsql_explain_analyze) { PLtsql_execstate *estate = get_current_tsql_estate(); + Assert(estate != NULL); INSTR_TIME_SET_CURRENT(estate->execution_start); } @@ -441,7 +444,7 @@ pltsql_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, if ((count == 0 || count > pltsql_rowcount) && queryDesc->operation == CMD_SELECT) count = pltsql_rowcount; - + if (prev_ExecutorRun) prev_ExecutorRun(queryDesc, direction, count, execute_once); else @@ -472,25 +475,25 @@ pltsql_ExecutorEnd(QueryDesc *queryDesc) } /** - * @brief - * the function will depend on PLtsql_execstate to find whether - * the trigger is called before on this query stack, so that's why we + * @brief + * the function will depend on PLtsql_execstate to find whether + * the trigger is called before on this query stack, so that's why we * have to add a hook into Postgres code to callback into babel code, - * since we need to get access to PLtsql_execstate to iterate the + * since we need to get access to PLtsql_execstate to iterate the * stack triggers - * + * * return true if it's a recursive call of trigger * return false if it's not - * - * @param resultRelInfo - * @return true - * @return false + * + * @param resultRelInfo + * @return true + * @return false */ static bool plsql_TriggerRecursiveCheck(ResultRelInfo *resultRelInfo) { - int i; - PLExecStateCallStack * cur; + int i; + PLExecStateCallStack *cur; PLtsql_execstate *estate; if (resultRelInfo->ri_TrigDesc == NULL) @@ -498,16 +501,21 @@ plsql_TriggerRecursiveCheck(ResultRelInfo *resultRelInfo) if (pltsql_recursive_triggers) return false; cur = exec_state_call_stack; - while (cur != NULL){ + while (cur != NULL) + { estate = cur->estate; if (estate->trigdata != NULL && estate->trigdata->tg_trigger != NULL - && resultRelInfo->ri_TrigDesc != NULL - && (resultRelInfo->ri_TrigDesc->trig_insert_instead_statement - || resultRelInfo->ri_TrigDesc->trig_delete_instead_statement - || resultRelInfo->ri_TrigDesc->trig_update_instead_statement)){ - for (i = 0; iri_TrigDesc->numtriggers; ++i){ + && resultRelInfo->ri_TrigDesc != NULL + && (resultRelInfo->ri_TrigDesc->trig_insert_instead_statement + || resultRelInfo->ri_TrigDesc->trig_delete_instead_statement + || resultRelInfo->ri_TrigDesc->trig_update_instead_statement)) + { + for (i = 0; i < resultRelInfo->ri_TrigDesc->numtriggers; ++i) + { Trigger *trigger = &resultRelInfo->ri_TrigDesc->triggers[i]; - if (trigger->tgoid == estate->trigdata->tg_trigger->tgoid){ + + if (trigger->tgoid == estate->trigdata->tg_trigger->tgoid) + { return true; } } @@ -520,26 +528,31 @@ plsql_TriggerRecursiveCheck(ResultRelInfo *resultRelInfo) static Node * output_update_self_join_transformation(ParseState *pstate, UpdateStmt *stmt, Query *query) { - Node *qual = NULL, *pre_transform_qual = NULL; - RangeVar *from_table = NULL; - ColumnRef *l_expr, *r_expr; - A_Expr *where_ctid = NULL; - Node *where_clone = NULL; - - /* - * Invoke transformWhereClause() to check for ambiguities in column name - * of the original query before self-join transformation. - */ + Node *qual = NULL, + *pre_transform_qual = NULL; + RangeVar *from_table = NULL; + ColumnRef *l_expr, + *r_expr; + A_Expr *where_ctid = NULL; + Node *where_clone = NULL; + + /* + * Invoke transformWhereClause() to check for ambiguities in column name + * of the original query before self-join transformation. + */ where_clone = copyObject(stmt->whereClause); pre_transform_qual = transformWhereClause(pstate, stmt->whereClause, - EXPR_KIND_WHERE, "WHERE"); + EXPR_KIND_WHERE, "WHERE"); if (sql_dialect != SQL_DIALECT_TSQL) return pre_transform_qual; if (get_output_clause_transformation_info()) { - /* Unset the OUTPUT clause info variable to prevent unintended side-effects */ + /* + * Unset the OUTPUT clause info variable to prevent unintended + * side-effects + */ set_output_clause_transformation_info(false); /* Add target table with deleted alias to the from clause */ @@ -556,32 +569,40 @@ output_update_self_join_transformation(ParseState *pstate, UpdateStmt *stmt, Que r_expr = makeNode(ColumnRef); r_expr->fields = list_make2(makeString("deleted"), makeString("ctid")); r_expr->location = -1; - where_ctid = makeA_Expr(AEXPR_OP, list_make1(makeString("=")), (Node*) l_expr, (Node*) r_expr, -1); + where_ctid = makeA_Expr(AEXPR_OP, list_make1(makeString("=")), (Node *) l_expr, (Node *) r_expr, -1); /* Add the self-join condition to the where clause */ if (where_clone) { - BoolExpr *self_join_condition; - self_join_condition = (BoolExpr*) makeBoolExpr(AND_EXPR, list_make2(where_clone, where_ctid), -1); - stmt->whereClause = (Node*) self_join_condition; + BoolExpr *self_join_condition; + + self_join_condition = (BoolExpr *) makeBoolExpr(AND_EXPR, list_make2(where_clone, where_ctid), -1); + stmt->whereClause = (Node *) self_join_condition; } else - stmt->whereClause = (Node*) where_ctid; + stmt->whereClause = (Node *) where_ctid; - /* Set the OUTPUT clause info variable to be used in transformColumnRef() */ + /* + * Set the OUTPUT clause info variable to be used in + * transformColumnRef() + */ set_output_clause_transformation_info(true); /* - * We let transformWhereClause() be called before the invokation of this hook - * to handle ambiguity errors. If there are any ambiguous references in the - * query an error is thrown. At this point, we have cleared that check and - * know that there are no ambiguities. Therefore, we can go ahead with the - * where clause transformation without worrying about ambiguous references. - */ + * We let transformWhereClause() be called before the invokation of + * this hook to handle ambiguity errors. If there are any ambiguous + * references in the query an error is thrown. At this point, we have + * cleared that check and know that there are no ambiguities. + * Therefore, we can go ahead with the where clause transformation + * without worrying about ambiguous references. + */ qual = transformWhereClause(pstate, stmt->whereClause, - EXPR_KIND_WHERE, "WHERE"); + EXPR_KIND_WHERE, "WHERE"); - /* Unset the OUTPUT clause info variable because we do not need it anymore */ + /* + * Unset the OUTPUT clause info variable because we do not need it + * anymore + */ set_output_clause_transformation_info(false); } else @@ -606,14 +627,16 @@ get_output_clause_transformation_info(void) static void handle_returning_qualifiers(Query *query, List *returningList, ParseState *pstate) { - ListCell *o_target, *expr; - Node *field1; - char *qualifier = NULL; - ParseNamespaceItem *nsitem = NULL; - int levels_up; - bool inserted = false, deleted = false; - List *queue = NIL; - CmdType command = query->commandType; + ListCell *o_target, + *expr; + Node *field1; + char *qualifier = NULL; + ParseNamespaceItem *nsitem = NULL; + int levels_up; + bool inserted = false, + deleted = false; + List *queue = NIL; + CmdType command = query->commandType; if (prev_pre_transform_returning_hook) prev_pre_transform_returning_hook(query, returningList, pstate); @@ -621,12 +644,13 @@ handle_returning_qualifiers(Query *query, List *returningList, ParseState *pstat if (sql_dialect != SQL_DIALECT_TSQL) return; - /* - * For UPDATE/DELETE statement, we'll need to update the result relation index after - * analyzing FROM clause and getting the final range table entries. - * post_parse_analyze hook, won't be triggered by CTE parse analyze. So we perform the - * operation here instead, which will be triggered by all INSERT/UPDATE/DELETE statements. - */ + /* + * For UPDATE/DELETE statement, we'll need to update the result relation + * index after analyzing FROM clause and getting the final range table + * entries. post_parse_analyze hook, won't be triggered by CTE parse + * analyze. So we perform the operation here instead, which will be + * triggered by all INSERT/UPDATE/DELETE statements. + */ if (command == CMD_DELETE || command == CMD_UPDATE) pltsql_update_query_result_relation(query, pstate->p_target_relation, pstate->p_rtable); @@ -638,12 +662,14 @@ handle_returning_qualifiers(Query *query, List *returningList, ParseState *pstat foreach(o_target, returningList) { ResTarget *res = (ResTarget *) lfirst(o_target); + queue = NIL; queue = list_make1(res->val); foreach(expr, queue) { - Node *node = (Node *) lfirst(expr); + Node *node = (Node *) lfirst(expr); + if (IsA(node, ColumnRef)) { ColumnRef *cref = (ColumnRef *) node; @@ -671,18 +697,19 @@ handle_returning_qualifiers(Query *query, List *returningList, ParseState *pstat cref->fields = list_delete_first(cref->fields); } } - else if(IsA(node, A_Expr)) + else if (IsA(node, A_Expr)) { - A_Expr *a_expr = (A_Expr *) node; + A_Expr *a_expr = (A_Expr *) node; if (a_expr->lexpr) queue = lappend(queue, a_expr->lexpr); if (a_expr->rexpr) queue = lappend(queue, a_expr->rexpr); } - else if(IsA(node, FuncCall)) + else if (IsA(node, FuncCall)) { - FuncCall *func_call = (FuncCall*) node; + FuncCall *func_call = (FuncCall *) node; + if (func_call->args) queue = list_concat(queue, func_call->args); } @@ -694,22 +721,24 @@ handle_returning_qualifiers(Query *query, List *returningList, ParseState *pstat foreach(o_target, returningList) { ResTarget *res = (ResTarget *) lfirst(o_target); + queue = NIL; queue = list_make1(res->val); foreach(expr, queue) { - Node *node = (Node *) lfirst(expr); + Node *node = (Node *) lfirst(expr); if (IsA(node, ColumnRef)) { /* - * Checks for RTEs could have been performed outside of the loop - * but we need to perform them inside the loop so that we can pass - * cref->location to refnameRangeTblEntry() and keep error messages - * correct. - */ + * Checks for RTEs could have been performed outside of + * the loop but we need to perform them inside the loop so + * that we can pass cref->location to + * refnameRangeTblEntry() and keep error messages correct. + */ ColumnRef *cref = (ColumnRef *) node; + nsitem = refnameNamespaceItem(pstate, NULL, "inserted", cref->location, &levels_up); @@ -726,18 +755,19 @@ handle_returning_qualifiers(Query *query, List *returningList, ParseState *pstat if (inserted && deleted) break; } - else if(IsA(node, A_Expr)) + else if (IsA(node, A_Expr)) { - A_Expr *a_expr = (A_Expr *) node; + A_Expr *a_expr = (A_Expr *) node; if (a_expr->lexpr) queue = lappend(queue, a_expr->lexpr); if (a_expr->rexpr) queue = lappend(queue, a_expr->rexpr); } - else if(IsA(node, FuncCall)) + else if (IsA(node, FuncCall)) { - FuncCall *func_call = (FuncCall*) node; + FuncCall *func_call = (FuncCall *) node; + if (func_call->args) queue = list_concat(queue, func_call->args); } @@ -746,16 +776,18 @@ handle_returning_qualifiers(Query *query, List *returningList, ParseState *pstat foreach(o_target, returningList) { ResTarget *res = (ResTarget *) lfirst(o_target); + queue = NIL; queue = list_make1(res->val); foreach(expr, queue) { - Node *node = (Node *) lfirst(expr); + Node *node = (Node *) lfirst(expr); if (IsA(node, ColumnRef)) { ColumnRef *cref = (ColumnRef *) node; + if (list_length(cref->fields) == 2) { field1 = (Node *) linitial(cref->fields); @@ -764,6 +796,7 @@ handle_returning_qualifiers(Query *query, List *returningList, ParseState *pstat if ((!inserted && !strcmp(qualifier, "inserted")) || (!deleted && !strcmp(qualifier, "deleted"))) { if (update_delete_target_alias) + /* * If target relation is specified by an alias * in FROM clause, we should use the alias @@ -777,18 +810,19 @@ handle_returning_qualifiers(Query *query, List *returningList, ParseState *pstat } } } - else if(IsA(node, A_Expr)) + else if (IsA(node, A_Expr)) { - A_Expr *a_expr = (A_Expr *) node; + A_Expr *a_expr = (A_Expr *) node; if (a_expr->lexpr) queue = lappend(queue, a_expr->lexpr); if (a_expr->rexpr) queue = lappend(queue, a_expr->rexpr); } - else if(IsA(node, FuncCall)) + else if (IsA(node, FuncCall)) { - FuncCall *func_call = (FuncCall*) node; + FuncCall *func_call = (FuncCall *) node; + if (func_call->args) queue = list_concat(queue, func_call->args); } @@ -807,23 +841,27 @@ check_insert_row(List *icolumns, List *exprList, Oid relid) errmsg("Number of given values does not match target table definition"))); } -char* +char * extract_identifier(const char *start) { /* - * We will extract original identifier from source query string. 'start' is a char potiner to start of identifier, which is provided from caller based on location of each token. - * The remaning task is to find the end position of identifier. For this, we will mimic the lexer rule. - * This includes plain identifier (and un-reserved keyword) as well as delimited by double-quote and squared bracket (T-SQL). + * We will extract original identifier from source query string. 'start' + * is a char potiner to start of identifier, which is provided from caller + * based on location of each token. The remaning task is to find the end + * position of identifier. For this, we will mimic the lexer rule. This + * includes plain identifier (and un-reserved keyword) as well as + * delimited by double-quote and squared bracket (T-SQL). * - * Please note that, this function assumes that identifier is already valid. (otherwise, syntax error should be already thrown). + * Please note that, this function assumes that identifier is already + * valid. (otherwise, syntax error should be already thrown). */ - bool dq = false; - bool sqb = false; - int i = 0; - char *original_name = NULL; - bool valid = false; - bool found_escaped_in_dq = false; + bool dq = false; + bool sqb = false; + int i = 0; + char *original_name = NULL; + bool valid = false; + bool found_escaped_in_dq = false; /* check identifier is delimited */ Assert(start); @@ -831,14 +869,21 @@ extract_identifier(const char *start) dq = true; else if (start[0] == '[') sqb = true; - ++i; /* advance cursor by one. As it is already a valid identiifer, its length should be greater than 1 */ + ++i; /* advance cursor by one. As it is already a + * valid identiifer, its length should be + * greater than 1 */ - /* valid identifier cannot be longer than 258 (2*128+2) bytes. SQL server allows up to 128 bascially. And escape character can take additional one byte for each character in worst case. And additional 2 byes for delimiter */ + /* + * valid identifier cannot be longer than 258 (2*128+2) bytes. SQL server + * allows up to 128 bascially. And escape character can take additional + * one byte for each character in worst case. And additional 2 byes for + * delimiter + */ while (i < 258) { - char c = start[i]; + char c = start[i]; - if (!dq && !sqb) /* normal case */ + if (!dq && !sqb) /* normal case */ { /* please see {tsql_ident_cont} in scan-tsql-decl.l */ valid = is_identifier_char(c); @@ -854,9 +899,10 @@ extract_identifier(const char *start) { /* please see xdinside in scan.l */ valid = (c != '"'); - if (!valid && start[i+1] == '"') /* escaped */ + if (!valid && start[i + 1] == '"') /* escaped */ { - ++i; ++i; /* advance two characters */ + ++i; + ++i; /* advance two characters */ found_escaped_in_dq = true; continue; } @@ -866,18 +912,24 @@ extract_identifier(const char *start) if (!found_escaped_in_dq) { /* no escaped character. copy whole string at once */ - original_name = palloc(i); /* exclude first/last double quote */ - memcpy(original_name, start + 1, i -1); + original_name = palloc(i); /* exclude first/last double + * quote */ + memcpy(original_name, start + 1, i - 1); original_name[i - 1] = '\0'; return original_name; } else { - /* there is escaped character. copy one by one to handle escaped character */ - int rcur = 1; /* read-cursor */ - int wcur = 0; /* write-cursor */ - original_name = palloc(i); /* exclude first/last double quote */ - for (; rcur)" to alist so that original_name will be stored in pg_attribute.attoptions */ + /* + * add "ALTER TABLE ALTER COLUMN SET (bbf_original_name=)" + * to alist so that original_name will be stored in + * pg_attribute.attoptions + */ AlterTableStmt *stmt; AlterTableCmd *cmd; - // To get original column name, utilize location of ColumnDef and query string. - const char* column_name_start = pstate->p_sourcetext + column->location; - char* original_name = extract_identifier(column_name_start); + + /* + * To get original column name, utilize location of ColumnDef and query + * string. + */ + const char *column_name_start = pstate->p_sourcetext + column->location; + char *original_name = extract_identifier(column_name_start); + if (original_name == NULL) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), @@ -945,33 +1007,41 @@ extern const char *ATTOPTION_BBF_ORIGINAL_TABLE_NAME; extern const char *ATTOPTION_BBF_TABLE_CREATE_DATE; static void -pltsql_post_transform_table_definition(ParseState *pstate, RangeVar* relation, char *relname, List **alist) +pltsql_post_transform_table_definition(ParseState *pstate, RangeVar *relation, char *relname, List **alist) { AlterTableStmt *stmt; AlterTableCmd *cmd_orig_name; AlterTableCmd *cmd_crdate; - char *curr_datetime; + char *curr_datetime; - /* To get original column name, utilize location of relation and query string. */ - char *table_name_start, *original_name, *temp; + /* + * To get original column name, utilize location of relation and query + * string. + */ + char *table_name_start, + *original_name, + *temp; - /* Skip during restore since reloptions are also dumped using separate ALTER command */ + /* + * Skip during restore since reloptions are also dumped using separate + * ALTER command + */ if (babelfish_dump_restore) return; table_name_start = (char *) pstate->p_sourcetext + relation->location; /* - * Could be the case that the fully qualified name is included, - * so just find the text after '.' in the identifier. - * We need to be careful as there can be '.' in the table name - * itself, so we will break the loop if current string matches - * with actual relname. + * Could be the case that the fully qualified name is included, so just + * find the text after '.' in the identifier. We need to be careful as + * there can be '.' in the table name itself, so we will break the loop if + * current string matches with actual relname. */ temp = strpbrk(table_name_start, ". "); while (temp && temp[0] != ' ' && - strncasecmp(relname, table_name_start, strlen(relname)) != 0 && - strncasecmp(relname, table_name_start + 1, strlen(relname)) != 0) /* match after skipping delimiter */ + strncasecmp(relname, table_name_start, strlen(relname)) != 0 && + strncasecmp(relname, table_name_start + 1, strlen(relname)) != 0) /* match after skipping + * delimiter */ { temp += 1; table_name_start = temp; @@ -989,10 +1059,16 @@ pltsql_post_transform_table_definition(ParseState *pstate, RangeVar* relation, c stmt->cmds = NIL; stmt->objtype = OBJECT_TABLE; - /* Only store original_name if there's a difference, and if the difference is only in capitalization */ + /* + * Only store original_name if there's a difference, and if the difference + * is only in capitalization + */ if (strncmp(relname, original_name, strlen(relname)) != 0 && strncasecmp(relname, original_name, strlen(relname)) == 0) { - /* add "ALTER TABLE SET (bbf_original_table_name=)" to alist so that original_name will be stored in pg_class.reloptions */ + /* + * add "ALTER TABLE SET (bbf_original_table_name=)" to + * alist so that original_name will be stored in pg_class.reloptions + */ cmd_orig_name = makeNode(AlterTableCmd); cmd_orig_name->subtype = AT_SetRelOptions; cmd_orig_name->def = (Node *) list_make1(makeDefElem(pstrdup(ATTOPTION_BBF_ORIGINAL_TABLE_NAME), (Node *) makeString(pstrdup(original_name)), -1)); @@ -1001,7 +1077,10 @@ pltsql_post_transform_table_definition(ParseState *pstate, RangeVar* relation, c stmt->cmds = lappend(stmt->cmds, cmd_orig_name); } - /* add "ALTER TABLE SET (bbf_rel_create_date=)" to alist so that create_date will be stored in pg_class.reloptions */ + /* + * add "ALTER TABLE SET (bbf_rel_create_date=)" to alist so that + * create_date will be stored in pg_class.reloptions + */ curr_datetime = DatumGetCString(DirectFunctionCall1(timestamp_out, TimestampGetDatum(GetSQLLocalTimestamp(3)))); cmd_crdate = makeNode(AlterTableCmd); cmd_crdate->subtype = AT_SetRelOptions; @@ -1023,7 +1102,7 @@ resolve_target_list_unknowns(ParseState *pstate, List *targetlist) foreach(l, targetlist) { - Const *con; + Const *con; TargetEntry *tle = (TargetEntry *) lfirst(l); Oid restype = exprType((Node *) tle->expr); @@ -1036,23 +1115,27 @@ resolve_target_list_unknowns(ParseState *pstate, List *targetlist) con = (Const *) tle->expr; if (con->constisnull) { - /* In T-SQL, NULL const (without explicit datatype) should be resolved as INT4 */ + /* + * In T-SQL, NULL const (without explicit datatype) should be + * resolved as INT4 + */ tle->expr = (Expr *) coerce_type(pstate, (Node *) con, - restype, INT4OID, -1, - COERCION_IMPLICIT, - COERCE_IMPLICIT_CAST, - -1); + restype, INT4OID, -1, + COERCION_IMPLICIT, + COERCE_IMPLICIT_CAST, + -1); } else { - Oid sys_nspoid = get_namespace_oid("sys", false); - Oid sys_varchartypoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, - CStringGetDatum("varchar"), ObjectIdGetDatum(sys_nspoid)); + Oid sys_nspoid = get_namespace_oid("sys", false); + Oid sys_varchartypoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, + CStringGetDatum("varchar"), ObjectIdGetDatum(sys_nspoid)); + tle->expr = (Expr *) coerce_type(pstate, (Node *) con, - restype, sys_varchartypoid, -1, - COERCION_IMPLICIT, - COERCE_IMPLICIT_CAST, - -1); + restype, sys_varchartypoid, -1, + COERCION_IMPLICIT, + COERCE_IMPLICIT_CAST, + -1); } } } @@ -1061,11 +1144,11 @@ static inline bool is_identifier_char(char c) { /* please see {tsql_ident_cont} in scan-tsql-decl.l */ - bool valid = ((c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z') || - (c >= 0200 && c <= 0377) || - (c >= '0' && c <= '9') || - c == '_' || c == '$' || c == '#'); + bool valid = ((c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + (c >= 0200 && c <= 0377) || + (c >= '0' && c <= '9') || + c == '_' || c == '$' || c == '#'); return valid; } @@ -1073,10 +1156,10 @@ is_identifier_char(char c) static int find_attr_by_name_from_column_def_list(const char *attributeName, List *schema) { - char *attrname = downcase_identifier(attributeName, strlen(attributeName), false, false); - int attrlen = strlen(attrname); - int i = 1; - ListCell *s; + char *attrname = downcase_identifier(attributeName, strlen(attributeName), false, false); + int attrlen = strlen(attrname); + int i = 1; + ListCell *s; foreach(s, schema) { @@ -1084,13 +1167,15 @@ find_attr_by_name_from_column_def_list(const char *attributeName, List *schema) if (strlen(def->colname) == attrlen) { - char *defname; + char *defname; - if (strcmp(attributeName, def->colname) == 0) // compare with original strings + if (strcmp(attributeName, def->colname) == 0) + /* compare with original strings */ return i; defname = downcase_identifier(def->colname, strlen(def->colname), false, false); - if (strncmp(attrname, defname, attrlen) == 0) // compare with downcased strings + if (strncmp(attrname, defname, attrlen) == 0) + /* compare with downcased strings */ return i; } i++; @@ -1121,27 +1206,29 @@ specialAttNum(const char *attname) static int find_attr_by_name_from_relation(Relation rd, const char *attname, bool sysColOK) { - int i; + int i; for (i = 0; i < RelationGetNumberOfAttributes(rd); i++) { Form_pg_attribute att = TupleDescAttr(rd->rd_att, i); const char *origname = NameStr(att->attname); - int rdattlen = strlen(origname); + int rdattlen = strlen(origname); const char *rdattname; if (strlen(attname) == rdattlen && !att->attisdropped) { - if (namestrcmp(&(att->attname), attname) == 0) // compare with original strings + if (namestrcmp(&(att->attname), attname) == 0) + /* compare with original strings */ return i + 1; /* - * Currently, we don't have any cases where attname needs to be downcased - * If exists, we have to take a deeper look - * whether the downcasing is needed here or gram.y + * Currently, we don't have any cases where attname needs to be + * downcased If exists, we have to take a deeper look whether the + * downcasing is needed here or gram.y */ rdattname = downcase_identifier(origname, rdattlen, false, false); - if (strcmp(rdattname, attname) == 0) // compare with downcased strings + if (strcmp(rdattname, attname) == 0) + /* compare with downcased strings */ return i + 1; } } @@ -1158,31 +1245,33 @@ find_attr_by_name_from_relation(Relation rd, const char *attname, bool sysColOK) static void pre_transform_target_entry(ResTarget *res, ParseState *pstate, - ParseExprKind exprKind) + ParseExprKind exprKind) { if (prev_pre_transform_target_entry_hook) (*prev_pre_transform_target_entry_hook) (res, pstate, exprKind); - /* In the TSQL dialect construct an AS clause for each target list - * item that is a column using the capitalization from the sourcetext. + /* + * In the TSQL dialect construct an AS clause for each target list item + * that is a column using the capitalization from the sourcetext. */ if (sql_dialect != SQL_DIALECT_TSQL) return; if (exprKind == EXPR_KIND_SELECT_TARGET) { - int alias_len = 0; + int alias_len = 0; const char *colname_start; const char *identifier_name = NULL; if (res->name == NULL && res->location != -1 && IsA(res->val, ColumnRef)) { - ColumnRef *cref = (ColumnRef *) res->val; + ColumnRef *cref = (ColumnRef *) res->val; - /* If no alias is specified on a ColumnRef, then - * get the length of the name from the ColumnRef and - * copy the column name from the sourcetext + /* + * If no alias is specified on a ColumnRef, then get the length of + * the name from the ColumnRef and copy the column name from the + * sourcetext */ if (list_length(cref->fields) == 1 && IsA(linitial(cref->fields), String)) @@ -1201,13 +1290,13 @@ pre_transform_target_entry(ResTarget *res, ParseState *pstate, if (alias_len > 0) { - char *alias = palloc0(alias_len + 1); - bool dq = *colname_start == '"'; - bool sqb = *colname_start == '['; - bool sq = *colname_start == '\''; - int a = 0; + char *alias = palloc0(alias_len + 1); + bool dq = *colname_start == '"'; + bool sqb = *colname_start == '['; + bool sq = *colname_start == '\''; + int a = 0; const char *colname_end; - bool closing_quote_reached = false; + bool closing_quote_reached = false; if (dq || sqb || sq) { @@ -1224,7 +1313,7 @@ pre_transform_target_entry(ResTarget *res, ParseState *pstate, if ((*(++colname_end) != '"')) { closing_quote_reached = true; - break; /* end of dbl-quoted identifier */ + break; /* end of dbl-quoted identifier */ } } else if (sq && *colname_end == '\'') @@ -1232,14 +1321,14 @@ pre_transform_target_entry(ResTarget *res, ParseState *pstate, if ((*(++colname_end) != '\'')) { closing_quote_reached = true; - break; /* end of single-quoted identifier */ + break; /* end of single-quoted identifier */ } } alias[a++] = *colname_end; } - // Assert(a == alias_len); + /* Assert(a == alias_len); */ } else { @@ -1247,18 +1336,18 @@ pre_transform_target_entry(ResTarget *res, ParseState *pstate, memcpy(alias, colname_start, alias_len); } - /* If the end of the string is a uniquifier, then copy - * the uniquifier into the last 32 characters of - * the alias + /* + * If the end of the string is a uniquifier, then copy the + * uniquifier into the last 32 characters of the alias */ - if (alias_len == NAMEDATALEN-1 && - (((sq || dq) && !closing_quote_reached) || - is_identifier_char(*colname_end))) + if (alias_len == NAMEDATALEN - 1 && + (((sq || dq) && !closing_quote_reached) || + is_identifier_char(*colname_end))) { - memcpy(alias+(NAMEDATALEN-1)-32, - identifier_name+(NAMEDATALEN-1)-32, - 32); + memcpy(alias + (NAMEDATALEN - 1) - 32, + identifier_name + (NAMEDATALEN - 1) - 32, + 32); alias[NAMEDATALEN] = '\0'; } @@ -1272,23 +1361,25 @@ pre_transform_target_entry(ResTarget *res, ParseState *pstate, Oid targetRelid = InvalidOid; char *relname = NULL; char *schemaname = NULL; - - switch(list_length(res->indirection)) + + switch (list_length(res->indirection)) { case 1: /* update t set x.y, try to resolve as t.c if it's not x[i] */ - if(!IsA(linitial(res->indirection), A_Indices)) + if (!IsA(linitial(res->indirection), A_Indices)) { relname = res->name; } break; case 2: /* if it's set x.y[i], try to resolve as t.c[i] */ - if(IsA(lsecond(res->indirection), A_Indices)) + if (IsA(lsecond(res->indirection), A_Indices)) { relname = res->name; } - /* otherwise try to resolve as s.t.c. Do not resolve as t.c.f + + /* + * otherwise try to resolve as s.t.c. Do not resolve as t.c.f * because we don't want to extend the legacy case c.f to have * qualifiers. */ @@ -1299,11 +1390,13 @@ pre_transform_target_entry(ResTarget *res, ParseState *pstate, } break; case 3: - /* if it's set x.y.z[i], try to resolve as s.t.c[i]. Do not + + /* + * if it's set x.y.z[i], try to resolve as s.t.c[i]. Do not * resolve as t.c.f.ff because we don't want to extend the * legecy case c.f.ff to have qualifiers. */ - if(IsA(lthird(res->indirection), A_Indices)) + if (IsA(lthird(res->indirection), A_Indices)) { schemaname = res->name; relname = strVal(linitial(res->indirection)); @@ -1314,84 +1407,91 @@ pre_transform_target_entry(ResTarget *res, ParseState *pstate, } /* Get relid either by s.t or t */ - if(schemaname && relname) + if (schemaname && relname) { relid = RangeVarGetRelid(makeRangeVar(schemaname, relname, res->location), - NoLock, - true); + NoLock, + true); } - else if(relname) + else if (relname) { relid = RelnameGetRelid(relname); } targetRelid = RelationGetRelid(pstate->p_target_relation); /* If relid matches or alias matches, try to resolve the qualifiers */ - if(relname - /* relid matches */ + if (relname + /* relid matches */ && (targetRelid == relid - /* or alias name matches */ + /* or alias name matches */ || (!schemaname - && strcmp(pstate->p_target_nsitem->p_rte->eref->aliasname,relname) == 0))) + && strcmp(pstate->p_target_nsitem->p_rte->eref->aliasname, relname) == 0))) { - /* If set x.y... happens to match legacy case set c.f..., treat it as c.f... for - * backward compatability. + /* + * If set x.y... happens to match legacy case set c.f..., treat it + * as c.f... for backward compatability. */ - AttrNumber x_attnum = get_attnum(targetRelid, res->name); - bool isLegacy = false; - Oid atttype = get_atttype(targetRelid, x_attnum); + AttrNumber x_attnum = get_attnum(targetRelid, res->name); + bool isLegacy = false; + Oid atttype = get_atttype(targetRelid, x_attnum); + /* If x is a column of target table t and x is a composite type */ - if(x_attnum != InvalidAttrNumber + if (x_attnum != InvalidAttrNumber && get_typtype(atttype) == TYPTYPE_COMPOSITE) { - char *subfield = strVal(linitial(res->indirection)); - Oid x_relid = get_typ_typrelid(atttype); - AttrNumber y_attnum = get_attnum(x_relid, subfield); + char *subfield = strVal(linitial(res->indirection)); + Oid x_relid = get_typ_typrelid(atttype); + AttrNumber y_attnum = get_attnum(x_relid, subfield); + /* Check if y is a subfield of composite type column x */ - if(y_attnum != InvalidAttrNumber) + if (y_attnum != InvalidAttrNumber) { /* set c.f.z, further check if it is c.f.ff */ - if(schemaname) + if (schemaname) { atttype = get_atttype(x_relid, y_attnum); - /* If y is composite type*/ - if(get_typtype(atttype) == TYPTYPE_COMPOSITE) + /* If y is composite type */ + if (get_typtype(atttype) == TYPTYPE_COMPOSITE) { - char *subsubfield = strVal(lsecond(res->indirection)); - Oid y_relid = get_typ_typrelid(atttype); - AttrNumber z_attnum = get_attnum(y_relid, subsubfield); + char *subsubfield = strVal(lsecond(res->indirection)); + Oid y_relid = get_typ_typrelid(atttype); + AttrNumber z_attnum = get_attnum(y_relid, subsubfield); + /* if z is a subfield of y */ - if(z_attnum != InvalidAttrNumber) + if (z_attnum != InvalidAttrNumber) { /* - * if z is also a column of the target table, then we face an ambiguity here: should do we interpret it (x.y.z) as - * s.t.z or c.f.ff? We don't know, log an ERROR to avoid silent data corruption. + * if z is also a column of the target table, + * then we face an ambiguity here: should do + * we interpret it (x.y.z) as s.t.z or c.f.ff? + * We don't know, log an ERROR to avoid silent + * data corruption. */ z_attnum = get_attnum(targetRelid, subsubfield); - if(z_attnum != InvalidAttrNumber) + if (z_attnum != InvalidAttrNumber) { ereport(ERROR, - (errcode(ERRCODE_AMBIGUOUS_COLUMN), - errmsg("\"%s\" can be interpreted either as a schema name or a column name.", - res->name), - errdetail("\"%s.%s\" has column \"%s\" that is a composite type with \"%s\" as a subfield, " \ - "which is a composite type with \"%s\" as a subfield, as well as column \"%s\".", - res->name, - subfield, - res->name, - subfield, - subsubfield, - res->name), - errhint("Use a table alias other than \"%s.%s\" to remove the ambiguity.", - res->name, - subfield), - parser_errposition(pstate, exprLocation((Node *)res)))); + (errcode(ERRCODE_AMBIGUOUS_COLUMN), + errmsg("\"%s\" can be interpreted either as a schema name or a column name.", + res->name), + errdetail("\"%s.%s\" has column \"%s\" that is a composite type with \"%s\" as a subfield, " \ + "which is a composite type with \"%s\" as a subfield, as well as column \"%s\".", + res->name, + subfield, + res->name, + subfield, + subsubfield, + res->name), + errhint("Use a table alias other than \"%s.%s\" to remove the ambiguity.", + res->name, + subfield), + parser_errposition(pstate, exprLocation((Node *) res)))); } else { elog(DEBUG1, - "\"%s\" will be interpreted as a column name because it has a composite type and \"%s\" is a subfield " - "of \"%s\" and \"%s\" is a subfield of \"%s\".", - res->name, subfield, res->name, subsubfield, subfield); + "\"%s\" will be interpreted as a column name because it has a composite type and \"%s\" is a subfield " + "of \"%s\" and \"%s\" is a subfield of \"%s\".", + res->name, subfield, res->name, subsubfield, subfield); isLegacy = true; } } @@ -1401,48 +1501,54 @@ pre_transform_target_entry(ResTarget *res, ParseState *pstate, else { /* - * if y is also a column of the target table, then we face an ambiguity here: should do we interpret it (x.y) as - * t.y or c.y? We don't know, log an ERROR to avoid silent data corruption. + * if y is also a column of the target table, then we + * face an ambiguity here: should do we interpret it + * (x.y) as t.y or c.y? We don't know, log an ERROR to + * avoid silent data corruption. */ y_attnum = get_attnum(targetRelid, subfield); - if(y_attnum != InvalidAttrNumber) + if (y_attnum != InvalidAttrNumber) { ereport(ERROR, - (errcode(ERRCODE_AMBIGUOUS_COLUMN), - errmsg("\"%s\" can be interpreted either as a table name or a column name.", - res->name), - errdetail("\"%s\" has column \"%s\" that is a composite type with \"%s\" as a subfield, " \ - "as well as column \"%s\".", - res->name, - res->name, - subfield, - subfield), - errhint("Use a table alias other than \"%s\" to remove the ambiguity.", - res->name), - parser_errposition(pstate, exprLocation((Node *)res)))); + (errcode(ERRCODE_AMBIGUOUS_COLUMN), + errmsg("\"%s\" can be interpreted either as a table name or a column name.", + res->name), + errdetail("\"%s\" has column \"%s\" that is a composite type with \"%s\" as a subfield, " \ + "as well as column \"%s\".", + res->name, + res->name, + subfield, + subfield), + errhint("Use a table alias other than \"%s\" to remove the ambiguity.", + res->name), + parser_errposition(pstate, exprLocation((Node *) res)))); } else { elog(DEBUG1, - "\"%s\" will be interpreted as a column name because it has a composite type and \"%s\" is a subfield of \"%s\".", - res->name, subfield, res->name); + "\"%s\" will be interpreted as a column name because it has a composite type and \"%s\" is a subfield of \"%s\".", + res->name, subfield, res->name); isLegacy = true; } } } } - /* If it's not the legacy case then it's safe to resolve x.y... as qualified name */ - if(!isLegacy) + + /* + * If it's not the legacy case then it's safe to resolve x.y... as + * qualified name + */ + if (!isLegacy) { - if(schemaname) + if (schemaname) { res->name = strVal(lsecond(res->indirection)); - res->indirection = list_copy_tail(res->indirection,2); + res->indirection = list_copy_tail(res->indirection, 2); } else { res->name = strVal(linitial(res->indirection)); - res->indirection = list_copy_tail(res->indirection,1); + res->indirection = list_copy_tail(res->indirection, 1); } } } @@ -1455,14 +1561,14 @@ tle_name_comparison(const char *tlename, const char *identifier) { if (sql_dialect == SQL_DIALECT_TSQL) { - int tlelen = strlen(tlename); + int tlelen = strlen(tlename); if (tlelen != strlen(identifier)) return false; if (pltsql_case_insensitive_identifiers) return (0 == strcmp(downcase_identifier(tlename, tlelen, false, false), - downcase_identifier(identifier, tlelen, false, false))); + downcase_identifier(identifier, tlelen, false, false))); else return (0 == strcmp(tlename, identifier)); } @@ -1473,64 +1579,67 @@ tle_name_comparison(const char *tlename, const char *identifier) } Oid -get_tsql_trigger_oid(List *object, const char *tsql_trigger_name, bool object_from_input){ - Oid trigger_rel_oid = InvalidOid; - Relation tgrel; - ScanKeyData key; - SysScanDesc tgscan; - HeapTuple tuple; - Oid reloid; - Relation relation = NULL; - const char *pg_trigger_physical_schema = NULL; - const char *cur_physical_schema = NULL; - const char *tsql_trigger_physical_schema = NULL; - const char *tsql_trigger_logical_schema = NULL; - List *search_path = fetch_search_path(false); - - if(list_length(object) == 1) +get_tsql_trigger_oid(List *object, const char *tsql_trigger_name, bool object_from_input) +{ + Oid trigger_rel_oid = InvalidOid; + Relation tgrel; + ScanKeyData key; + SysScanDesc tgscan; + HeapTuple tuple; + Oid reloid; + Relation relation = NULL; + const char *pg_trigger_physical_schema = NULL; + const char *cur_physical_schema = NULL; + const char *tsql_trigger_physical_schema = NULL; + const char *tsql_trigger_logical_schema = NULL; + List *search_path = fetch_search_path(false); + + if (list_length(object) == 1) { cur_physical_schema = get_namespace_name(linitial_oid(search_path)); list_free(search_path); } else { - if(object_from_input) - tsql_trigger_logical_schema = ((String *)linitial(object))->sval; + if (object_from_input) + tsql_trigger_logical_schema = ((String *) linitial(object))->sval; else { - tsql_trigger_physical_schema = ((String *)linitial(object))->sval; + tsql_trigger_physical_schema = ((String *) linitial(object))->sval; tsql_trigger_logical_schema = get_logical_schema_name(tsql_trigger_physical_schema, true); } - cur_physical_schema = get_physical_schema_name(get_cur_db_name(),tsql_trigger_logical_schema); + cur_physical_schema = get_physical_schema_name(get_cur_db_name(), tsql_trigger_logical_schema); } - /* - * Get the table name of the trigger from pg_trigger. We know that - * trigger names are forced to be unique in the tsql dialect, so we - * can rely on searching for trigger name and schema name to find - * the corresponding relation name. - */ + /* + * Get the table name of the trigger from pg_trigger. We know that trigger + * names are forced to be unique in the tsql dialect, so we can rely on + * searching for trigger name and schema name to find the corresponding + * relation name. + */ tgrel = table_open(TriggerRelationId, AccessShareLock); ScanKeyInit(&key, - Anum_pg_trigger_tgname, - BTEqualStrategyNumber, F_NAMEEQ, - CStringGetDatum(tsql_trigger_name)); + Anum_pg_trigger_tgname, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(tsql_trigger_name)); tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, false, - NULL, 1, &key); + NULL, 1, &key); while (HeapTupleIsValid(tuple = systable_getnext(tgscan))) { Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple); - if(!OidIsValid(pg_trigger->tgrelid)) + + if (!OidIsValid(pg_trigger->tgrelid)) { break; } - - if(namestrcmp(&(pg_trigger->tgname), tsql_trigger_name) == 0){ + + if (namestrcmp(&(pg_trigger->tgname), tsql_trigger_name) == 0) + { reloid = pg_trigger->tgrelid; relation = RelationIdGetRelation(reloid); pg_trigger_physical_schema = get_namespace_name(get_rel_namespace(pg_trigger->tgrelid)); - if(strcasecmp(pg_trigger_physical_schema,cur_physical_schema) == 0) + if (strcasecmp(pg_trigger_physical_schema, cur_physical_schema) == 0) { trigger_rel_oid = reloid; RelationClose(relation); @@ -1560,15 +1669,15 @@ get_tsql_trigger_oid(List *object, const char *tsql_trigger_name, bool object_fr static ObjectAddress get_trigger_object_address(List *object, Relation *relp, bool missing_ok, bool object_from_input) { - ObjectAddress address; - const char *depname; - Oid trigger_rel_oid = InvalidOid; + ObjectAddress address; + const char *depname; + Oid trigger_rel_oid = InvalidOid; address.classId = InvalidOid; address.objectId = InvalidOid; address.objectSubId = InvalidAttrNumber; - + if (sql_dialect != SQL_DIALECT_TSQL) { return address; @@ -1577,11 +1686,11 @@ get_trigger_object_address(List *object, Relation *relp, bool missing_ok, bool o depname = strVal(llast(object)); if (prev_get_trigger_object_address_hook) - return (*prev_get_trigger_object_address_hook)(object,relp,missing_ok,object_from_input); + return (*prev_get_trigger_object_address_hook) (object, relp, missing_ok, object_from_input); - trigger_rel_oid = get_tsql_trigger_oid(object,depname,object_from_input); + trigger_rel_oid = get_tsql_trigger_oid(object, depname, object_from_input); - if(!OidIsValid(trigger_rel_oid)) + if (!OidIsValid(trigger_rel_oid)) return address; address.classId = TriggerRelationId; @@ -1597,41 +1706,55 @@ get_trigger_object_address(List *object, Relation *relp, bool missing_ok, bool o void pltsql_report_proc_not_found_error(List *names, List *given_argnames, int nargs, ParseState *pstate, int location, bool proc_call) { - FuncCandidateList candidates = NULL, current_candidate = NULL; - int max_nargs = -1; - int min_nargs = INT_MAX; - int ncandidates = 0; - bool found = false; + FuncCandidateList candidates = NULL, + current_candidate = NULL; + int max_nargs = -1; + int min_nargs = INT_MAX; + int ncandidates = 0; + bool found = false; const char *obj_type = proc_call ? "procedure" : "function"; - candidates = FuncnameGetCandidates(names, -1, NIL, false, false, false, true); /* search all possible candidate regardless of the # of arguments */ + candidates = FuncnameGetCandidates(names, -1, NIL, false, false, false, true); /* search all possible + * candidate regardless + * of the # of arguments */ if (candidates == NULL) - return; /* no candidates at all. let backend handle the proc-not-found error */ + return; /* no candidates at all. let backend handle + * the proc-not-found error */ for (current_candidate = candidates; current_candidate != NULL; current_candidate = current_candidate->next) { - if (current_candidate->nargs == nargs) /* Found the proc/func having the same number of arguments. */ + if (current_candidate->nargs == nargs) /* Found the proc/func having + * the same number of + * arguments. */ found = true; - + ncandidates++; min_nargs = (current_candidate->nargs < min_nargs) ? current_candidate->nargs : min_nargs; max_nargs = (current_candidate->nargs > max_nargs) ? current_candidate->nargs : max_nargs; } - if (max_nargs == -1 || min_nargs == INT_MAX) /* Unexpected number of arguments, let PG backend handle the error message */ + if (max_nargs == -1 || min_nargs == INT_MAX) /* Unexpected number of + * arguments, let PG + * backend handle the + * error message */ return; - if (ncandidates > 1) /* More than one candidates exist, throwing an error message with possible number of arguments */ + if (ncandidates > 1) /* More than one candidates exist, throwing an + * error message with possible number of + * arguments */ { const char *arg_str = (max_nargs < 2) ? "argument" : "arguments"; - /* Found the proc/func having the same number of arguments. possibly data-type mistmatch. */ + /* + * Found the proc/func having the same number of arguments. possibly + * data-type mistmatch. + */ if (found) { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("The %s %s is found but cannot be used. Possibly due to datatype mismatch and implicit casting is not allowed.", obj_type, NameListToString(names))), - parser_errposition(pstate, location)); + parser_errposition(pstate, location)); } if (max_nargs == min_nargs) @@ -1641,14 +1764,14 @@ pltsql_report_proc_not_found_error(List *names, List *given_argnames, int nargs, ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("%s %s has too many arguments specified.", obj_type, NameListToString(names))), - parser_errposition(pstate, location)); + parser_errposition(pstate, location)); } else { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("The %s %s requires %d %s", NameListToString(names), obj_type, max_nargs, arg_str)), - parser_errposition(pstate, location)); + parser_errposition(pstate, location)); } } else @@ -1656,49 +1779,49 @@ pltsql_report_proc_not_found_error(List *names, List *given_argnames, int nargs, ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("The %s %s requires %d to %d %s", NameListToString(names), obj_type, min_nargs, max_nargs, arg_str)), - parser_errposition(pstate, location)); + parser_errposition(pstate, location)); } } - else /* Only one candidate exists, */ + else /* Only one candidate exists, */ { - HeapTuple tup; - bool isnull; + HeapTuple tup; + bool isnull; tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(candidates->oid)); if (HeapTupleIsValid(tup)) { (void) SysCacheGetAttr(PROCOID, tup, - Anum_pg_proc_proargnames, - &isnull); - - if(!isnull) + Anum_pg_proc_proargnames, + &isnull); + + if (!isnull) { Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(tup); - HeapTuple bbffunctuple; - int pronargs = procform->pronargs; - int first_arg_with_default = pronargs - procform->pronargdefaults; - int pronallargs; - int ap; - int pp; - int numposargs = nargs - list_length(given_argnames); - Oid *p_argtypes; - char **p_argnames; - char *p_argmodes; - char *first_unknown_argname = NULL; - bool arggiven[FUNC_MAX_ARGS]; - bool default_positions_available = false; - List *default_positions = NIL; - ListCell *lc; - char *langname = get_language_name(procform->prolang, true); - - if (nargs > pronargs) /* Too many parameters provided. */ + HeapTuple bbffunctuple; + int pronargs = procform->pronargs; + int first_arg_with_default = pronargs - procform->pronargdefaults; + int pronallargs; + int ap; + int pp; + int numposargs = nargs - list_length(given_argnames); + Oid *p_argtypes; + char **p_argnames; + char *p_argmodes; + char *first_unknown_argname = NULL; + bool arggiven[FUNC_MAX_ARGS]; + bool default_positions_available = false; + List *default_positions = NIL; + ListCell *lc; + char *langname = get_language_name(procform->prolang, true); + + if (nargs > pronargs) /* Too many parameters provided. */ { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("%s %s has too many arguments specified.",obj_type, NameListToString(names))), - parser_errposition(pstate, location)); + errmsg("%s %s has too many arguments specified.", obj_type, NameListToString(names))), + parser_errposition(pstate, location)); } - + pronallargs = get_func_arg_info(tup, &p_argtypes, &p_argnames, @@ -1711,9 +1834,9 @@ pltsql_report_proc_not_found_error(List *names, List *given_argnames, int nargs, foreach(lc, given_argnames) { - char *argname = (char *) lfirst(lc); - bool match_found; - int i; + char *argname = (char *) lfirst(lc); + bool match_found; + int i; pp = 0; match_found = false; @@ -1721,7 +1844,7 @@ pltsql_report_proc_not_found_error(List *names, List *given_argnames, int nargs, { /* consider only input parameters */ if (p_argmodes && - (p_argmodes[i] != FUNC_PARAM_IN && + (p_argmodes[i] != FUNC_PARAM_IN && p_argmodes[i] != FUNC_PARAM_INOUT && p_argmodes[i] != FUNC_PARAM_VARIADIC)) continue; @@ -1738,15 +1861,15 @@ pltsql_report_proc_not_found_error(List *names, List *given_argnames, int nargs, if (!match_found && first_unknown_argname == NULL) first_unknown_argname = argname; } - + if (langname && pg_strcasecmp("pltsql", langname) == 0 && nargs < pronargs) { bbffunctuple = get_bbf_function_tuple_from_proctuple(tup); if (HeapTupleIsValid(bbffunctuple)) { - Datum arg_default_positions; - char *str; + Datum arg_default_positions; + char *str; /* Fetch default positions */ arg_default_positions = SysCacheGetAttr(PROCNSPSIGNATURE, @@ -1767,28 +1890,32 @@ pltsql_report_proc_not_found_error(List *names, List *given_argnames, int nargs, } } - /* Traverse arggiven list to check if a non-default parameter is not supplied. */ + /* + * Traverse arggiven list to check if a non-default parameter + * is not supplied. + */ for (pp = numposargs; pp < pronargs; pp++) { if (arggiven[pp]) continue; /* - * If the positions of default arguments are available then we need - * special handling. Look into default_positions list to find out - * the default expression for pp'th argument. + * If the positions of default arguments are available + * then we need special handling. Look into + * default_positions list to find out the default + * expression for pp'th argument. */ if (default_positions_available) { - bool has_default = false; - + bool has_default = false; + /* - * Iterate over argdefaults list to find out the default expression - * for current argument. + * Iterate over argdefaults list to find out the + * default expression for current argument. */ while (lc != NULL) { - int position = intVal((Node *) lfirst(lc)); + int position = intVal((Node *) lfirst(lc)); if (position == pp) { @@ -1805,43 +1932,52 @@ pltsql_report_proc_not_found_error(List *names, List *given_argnames, int nargs, ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("%s %s expects parameter \"%s\", which was not supplied.", obj_type, NameListToString(names), p_argnames[pp])), - parser_errposition(pstate, location)); + parser_errposition(pstate, location)); } else if (pp < first_arg_with_default) { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("%s %s expects parameter \"%s\", which was not supplied.", obj_type, NameListToString(names), p_argnames[pp])), - parser_errposition(pstate, location)); + parser_errposition(pstate, location)); } } - /* Default arguments are also supplied but parameter name is unknown. */ - if(first_unknown_argname) + + /* + * Default arguments are also supplied but parameter name is + * unknown. + */ + if (first_unknown_argname) { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("\"%s\" is not an parameter for %s %s.", first_unknown_argname, obj_type, NameListToString(names))), - parser_errposition(pstate, location)); + parser_errposition(pstate, location)); } - /* Still no issue with the arguments provided, possibly data-type mistmatch. */ + + /* + * Still no issue with the arguments provided, possibly + * data-type mistmatch. + */ ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("The %s %s is found but cannot be used. Possibly due to datatype mismatch and implicit casting is not allowed.", obj_type, NameListToString(names))), - parser_errposition(pstate, location)); - + parser_errposition(pstate, location)); + if (default_positions_available) { ReleaseSysCache(bbffunctuple); } pfree(langname); } - else if(nargs > 0) /* proargnames is NULL. Procedure/function has no parameters but arguments are specified. */ + else if (nargs > 0) /* proargnames is NULL. Procedure/function has + * no parameters but arguments are specified. */ { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("%s %s has no parameters and arguments were supplied.", obj_type, NameListToString(names))), - parser_errposition(pstate, location)); - } + parser_errposition(pstate, location)); + } } ReleaseSysCache(tup); } @@ -1868,13 +2004,13 @@ logicalrep_modify_slot(Relation rel, EState *estate, TupleTableSlot *slot) continue; /* - * If it is rowversion/timestamp column, then re-evaluate the column default - * and replace the slot with this new value. + * If it is rowversion/timestamp column, then re-evaluate the column + * default and replace the slot with this new value. */ - if ((*common_utility_plugin_ptr->is_tsql_rowversion_or_timestamp_datatype)(attr->atttypid)) + if ((*common_utility_plugin_ptr->is_tsql_rowversion_or_timestamp_datatype) (attr->atttypid)) { - Expr *defexpr; - ExprState *def; + Expr *defexpr; + ExprState *def; defexpr = (Expr *) build_column_default(rel, attnum + 1); @@ -1884,10 +2020,11 @@ logicalrep_modify_slot(Relation rel, EState *estate, TupleTableSlot *slot) defexpr = expression_planner(defexpr); def = ExecInitExpr(defexpr, NULL); slot->tts_values[attnum] = ExecEvalExpr(def, econtext, &slot->tts_isnull[attnum]); + /* - * No need to check for other columns since we can only - * have one rowversion/timestamp column in a table. - */ + * No need to check for other columns since we can only have + * one rowversion/timestamp column in a table. + */ break; } } @@ -1917,16 +2054,17 @@ bbf_object_access_hook(ObjectAccessType access, Oid classId, Oid objectId, int s revoke_func_permission_from_public(objectId); } -static void revoke_func_permission_from_public(Oid objectId) +static void +revoke_func_permission_from_public(Oid objectId) { - const char *query; - List *res; - GrantStmt *revoke; + const char *query; + List *res; + GrantStmt *revoke; PlannedStmt *wrapper; - const char *obj_name; + const char *obj_name; Oid phy_sch_oid; - const char *phy_sch_name; - const char *arg_list; + const char *phy_sch_name; + const char *arg_list; char kind; /* TSQL specific behavior */ @@ -1978,21 +2116,23 @@ static void revoke_func_permission_from_public(Oid objectId) /* Command Counter will be increased by validator */ } -static char *gen_func_arg_list(Oid objectId) +static char * +gen_func_arg_list(Oid objectId) { - Oid *argtypes; - int nargs = 0; + Oid *argtypes; + int nargs = 0; StringInfoData arg_list; + initStringInfo(&arg_list); get_func_signature(objectId, &argtypes, &nargs); for (int i = 0; i < nargs; i++) { - Oid typoid = argtypes[i]; - char *nsp_name; - char *type_name; - HeapTuple typeTuple; + Oid typoid = argtypes[i]; + char *nsp_name; + char *type_name; + HeapTuple typeTuple; typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typoid)); @@ -2006,7 +2146,7 @@ static char *gen_func_arg_list(Oid objectId) appendStringInfoString(&arg_list, nsp_name); appendStringInfoString(&arg_list, "."); appendStringInfoString(&arg_list, type_name); - if (i < nargs -1) + if (i < nargs - 1) appendStringInfoString(&arg_list, ", "); } @@ -2015,20 +2155,21 @@ static char *gen_func_arg_list(Oid objectId) /* * This function adds column names to the insert target relation in rewritten -* CTE for OUTPUT INTO clause. +* CTE for OUTPUT INTO clause. */ -static void +static void modify_insert_stmt(InsertStmt *stmt, Oid relid) { Relation pg_attribute; ScanKeyData scankey; SysScanDesc scan; HeapTuple tuple; - List *insert_col_list = NIL, *temp_col_list; - + List *insert_col_list = NIL, + *temp_col_list; + if (prev_pre_transform_insert_hook) (*prev_pre_transform_insert_hook) (stmt, relid); - + if (sql_dialect != SQL_DIALECT_TSQL) return; @@ -2045,14 +2186,15 @@ modify_insert_stmt(InsertStmt *stmt, Oid relid) ObjectIdGetDatum(relid)); pg_attribute = table_open(AttributeRelationId, AccessShareLock); - + scan = systable_beginscan(pg_attribute, AttributeRelidNumIndexId, true, NULL, 1, &scankey); while (HeapTupleIsValid(tuple = systable_getnext(scan))) { - ResTarget *col = makeNode(ResTarget); + ResTarget *col = makeNode(ResTarget); Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(tuple); + temp_col_list = NIL; if (att->attnum > 0) @@ -2085,13 +2227,15 @@ pltsql_store_view_definition(const char *queryString, ObjectAddress address) TupleDesc bbf_view_def_rel_dsc; Datum new_record[BBF_VIEW_DEF_NUM_COLS]; bool new_record_nulls[BBF_VIEW_DEF_NUM_COLS]; - HeapTuple tuple, reltup; - Form_pg_class form_reltup; + HeapTuple tuple, + reltup; + Form_pg_class form_reltup; int16 dbid; - uint64 flag_values = 0, flag_validity = 0; - char *physical_schemaname; - const char *logical_schemaname; - char *original_query = get_original_query_string(); + uint64 flag_values = 0, + flag_validity = 0; + char *physical_schemaname; + const char *logical_schemaname; + char *original_query = get_original_query_string(); if (sql_dialect != SQL_DIALECT_TSQL) return; @@ -2108,13 +2252,13 @@ pltsql_store_view_definition(const char *queryString, ObjectAddress address) if (physical_schemaname == NULL) { elog(ERROR, - "Could not find physical schemaname for %u", - form_reltup->relnamespace); + "Could not find physical schemaname for %u", + form_reltup->relnamespace); } /* - * Do not store definition/data in case of sys, information_schema_tsql and - * other shared schemas. + * Do not store definition/data in case of sys, information_schema_tsql + * and other shared schemas. */ if (is_shared_schema(physical_schemaname)) { @@ -2125,12 +2269,12 @@ pltsql_store_view_definition(const char *queryString, ObjectAddress address) dbid = get_dbid_from_physical_schema_name(physical_schemaname, true); logical_schemaname = get_logical_schema_name(physical_schemaname, true); - if(!DbidIsValid(dbid) || logical_schemaname == NULL) + if (!DbidIsValid(dbid) || logical_schemaname == NULL) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Could not find dbid or logical schema for this physical schema '%s'." \ - "CREATE VIEW from non-babelfish schema/db is not allowed in TSQL dialect.", physical_schemaname))); + errmsg("Could not find dbid or logical schema for this physical schema '%s'." \ + "CREATE VIEW from non-babelfish schema/db is not allowed in TSQL dialect.", physical_schemaname))); } bbf_view_def_rel = table_open(get_bbf_view_def_oid(), RowExclusiveLock); @@ -2141,10 +2285,10 @@ pltsql_store_view_definition(const char *queryString, ObjectAddress address) /* * To use particular flag bit to store certain flag, Set corresponding bit * in flag_validity which tracks currently supported flag bits and then - * set/unset flag_values bit according to flag settings. - * Used !Transform_null_equals instead of pltsql_ansi_nulls because NULL is - * being inserted in catalog if it is used. - * Currently, Only two flags are supported. + * set/unset flag_values bit according to flag settings. Used + * !Transform_null_equals instead of pltsql_ansi_nulls because NULL is + * being inserted in catalog if it is used. Currently, Only two flags are + * supported. */ flag_validity |= BBF_VIEW_DEF_FLAG_IS_ANSI_NULLS_ON; if (!Transform_null_equals) @@ -2152,11 +2296,11 @@ pltsql_store_view_definition(const char *queryString, ObjectAddress address) flag_validity |= BBF_VIEW_DEF_FLAG_USES_QUOTED_IDENTIFIER; if (pltsql_quoted_identifier) flag_values |= BBF_VIEW_DEF_FLAG_USES_QUOTED_IDENTIFIER; + /* - * Setting this flag bit to 0 to distinguish between the objects - * created in 2.x or 3.x for future references. Let's not use - * this bit in 3.x, as we are setting this to 1 in 2.x and will - * be reserved for MVU. + * Setting this flag bit to 0 to distinguish between the objects created + * in 2.x or 3.x for future references. Let's not use this bit in 3.x, as + * we are setting this to 1 in 2.x and will be reserved for MVU. */ flag_validity |= BBF_VIEW_DEF_FLAG_CREATED_IN_OR_AFTER_2_4; flag_values |= BBF_VIEW_DEF_FLAG_CREATED_IN_OR_AFTER_2_4; @@ -2192,11 +2336,13 @@ static void pltsql_drop_view_definition(Oid objectId) { Relation bbf_view_def_rel; - HeapTuple reltuple, scantup; - Form_pg_class form; + HeapTuple reltuple, + scantup; + Form_pg_class form; int16 dbid; - char *physical_schemaname, *objectname; - char *logical_schemaname; + char *physical_schemaname, + *objectname; + char *logical_schemaname; /* return if it is not a view */ reltuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objectId)); @@ -2213,16 +2359,16 @@ pltsql_drop_view_definition(Oid objectId) if (physical_schemaname == NULL) { elog(ERROR, - "Could not find physical schemaname for %u", - form->relnamespace); + "Could not find physical schemaname for %u", + form->relnamespace); } dbid = get_dbid_from_physical_schema_name(physical_schemaname, true); logical_schemaname = (char *) get_logical_schema_name(physical_schemaname, true); objectname = NameStr(form->relname); /* - * If any of these entries are NULL then there - * must not be any entry in catalog + * If any of these entries are NULL then there must not be any entry in + * catalog */ if (!DbidIsValid(dbid) || logical_schemaname == NULL || objectname == NULL) { @@ -2252,7 +2398,7 @@ pltsql_drop_view_definition(Oid objectId) } static void -preserve_view_constraints_from_base_table(ColumnDef *col, Oid tableOid, AttrNumber colId) +preserve_view_constraints_from_base_table(ColumnDef *col, Oid tableOid, AttrNumber colId) { /* * In TSQL Dialect Preserve the constraints only for the internal view @@ -2260,19 +2406,19 @@ preserve_view_constraints_from_base_table(ColumnDef *col, Oid tableOid, AttrNum */ if (sp_describe_first_result_set_inprogress && sql_dialect == SQL_DIALECT_TSQL) { - HeapTuple tp; + HeapTuple tp; Form_pg_attribute att_tup; - tp = SearchSysCache2(ATTNUM, - ObjectIdGetDatum(tableOid), - Int16GetDatum(colId)); + tp = SearchSysCache2(ATTNUM, + ObjectIdGetDatum(tableOid), + Int16GetDatum(colId)); if (HeapTupleIsValid(tp)) { att_tup = (Form_pg_attribute) GETSTRUCT(tp); col->is_not_null = att_tup->attnotnull; - col->identity = att_tup->attidentity; - col->generated = att_tup->attgenerated; + col->identity = att_tup->attidentity; + col->generated = att_tup->attgenerated; ReleaseSysCache(tp); } } @@ -2285,37 +2431,38 @@ preserve_view_constraints_from_base_table(ColumnDef *col, Oid tableOid, AttrNum bool pltsql_detect_numeric_overflow(int weight, int dscale, int first_block, int numeric_base) { - int partially_filled_numeric_block = 0; - int total_digit_count = 0; + int partially_filled_numeric_block = 0; + int total_digit_count = 0; if (sql_dialect != SQL_DIALECT_TSQL) return false; total_digit_count = (dscale == 0) ? (weight * numeric_base) : - ((weight + 1) * numeric_base); + ((weight + 1) * numeric_base); + /* - * calculating exact #digits in the first partially filled numeric block, if any) - * Ex. - in 12345.12345 var is of type struct NumericVar; first_block = var->digits[0]= 1, - * var->digits[1] = 2345, var->digits[2] = 1234, - * var->digits[3] = 5000; numeric_base = 4, var->ndigits = #numeric blocks i.e., 4, - * var->weight = 1, var->dscale = 5 + * calculating exact #digits in the first partially filled numeric block, + * if any) Ex. - in 12345.12345 var is of type struct NumericVar; + * first_block = var->digits[0]= 1, var->digits[1] = 2345, var->digits[2] + * = 1234, var->digits[3] = 5000; numeric_base = 4, var->ndigits = + * #numeric blocks i.e., 4, var->weight = 1, var->dscale = 5 */ partially_filled_numeric_block = first_block; /* - * check if the first numeric block is partially filled - * If yes, add those digit count - * Else if fully filled, Ignore as those digits are already added to total_digit_count + * check if the first numeric block is partially filled If yes, add those + * digit count Else if fully filled, Ignore as those digits are already + * added to total_digit_count */ if (partially_filled_numeric_block < pow(10, numeric_base - 1)) total_digit_count += (partially_filled_numeric_block > 0) ? - log10(partially_filled_numeric_block) + 1 : 1; + log10(partially_filled_numeric_block) + 1 : 1; /* - * calculating exact #digits in last block if decimal point exists - * If dscale is an exact multiple of numeric_base, last block is not partially filled, - * then, ignore as those digits are already added to total_digit_count - * Else, add the remainder digits + * calculating exact #digits in last block if decimal point exists If + * dscale is an exact multiple of numeric_base, last block is not + * partially filled, then, ignore as those digits are already added to + * total_digit_count Else, add the remainder digits */ if (dscale > 0) total_digit_count += (dscale % numeric_base); @@ -2334,17 +2481,20 @@ pltsql_store_func_default_positions(ObjectAddress address, List *parameters, con Datum new_record[BBF_FUNCTION_EXT_NUM_COLS]; bool new_record_nulls[BBF_FUNCTION_EXT_NUM_COLS]; bool new_record_replaces[BBF_FUNCTION_EXT_NUM_COLS]; - HeapTuple tuple, proctup, oldtup; - Form_pg_proc form_proctup; - NameData *schema_name_NameData; - char *physical_schemaname; - char *func_signature; - char *original_name = NULL; - List *default_positions = NIL; - ListCell *x; + HeapTuple tuple, + proctup, + oldtup; + Form_pg_proc form_proctup; + NameData *schema_name_NameData; + char *physical_schemaname; + char *func_signature; + char *original_name = NULL; + List *default_positions = NIL; + ListCell *x; int idx; - uint64 flag_values = 0, flag_validity = 0; - char *original_query = get_original_query_string(); + uint64 flag_values = 0, + flag_validity = 0; + char *original_query = get_original_query_string(); /* Disallow extended catalog lookup during restore */ if (babelfish_dump_restore) @@ -2366,13 +2516,13 @@ pltsql_store_func_default_positions(ObjectAddress address, List *parameters, con if (physical_schemaname == NULL) { elog(ERROR, - "Could not find physical schemaname for %u", - form_proctup->pronamespace); + "Could not find physical schemaname for %u", + form_proctup->pronamespace); } /* - * Do not store data in case of sys, information_schema_tsql and - * other shared schemas. + * Do not store data in case of sys, information_schema_tsql and other + * shared schemas. */ if (is_shared_schema(physical_schemaname)) { @@ -2382,8 +2532,8 @@ pltsql_store_func_default_positions(ObjectAddress address, List *parameters, con } func_signature = (char *) get_pltsql_function_signature_internal(NameStr(form_proctup->proname), - form_proctup->pronargs, - form_proctup->proargtypes.values); + form_proctup->pronargs, + form_proctup->proargtypes.values); idx = 0; foreach(x, parameters) @@ -2398,7 +2548,7 @@ pltsql_store_func_default_positions(ObjectAddress address, List *parameters, con } if (!OidIsValid(get_bbf_function_ext_idx_oid())) - { + { pfree(func_signature); pfree(physical_schemaname); ReleaseSysCache(proctup); @@ -2413,23 +2563,27 @@ pltsql_store_func_default_positions(ObjectAddress address, List *parameters, con if (origname_location != -1 && queryString) { - /* To get original function name, utilize location of original name and query string. */ - char *func_name_start, *temp; + /* + * To get original function name, utilize location of original name + * and query string. + */ + char *func_name_start, + *temp; const char *funcname = NameStr(form_proctup->proname); func_name_start = (char *) queryString + origname_location; /* - * Could be the case that the fully qualified name is included, - * so just find the text after '.' in the identifier. - * We need to be careful as there can be '.' in the function name - * itself, so we will break the loop if current string matches - * with actual funcname. + * Could be the case that the fully qualified name is included, so + * just find the text after '.' in the identifier. We need to be + * careful as there can be '.' in the function name itself, so we will + * break the loop if current string matches with actual funcname. */ temp = strpbrk(func_name_start, ". "); while (temp && temp[0] != ' ' && - strncasecmp(funcname, func_name_start, strlen(funcname)) != 0 && - strncasecmp(funcname, func_name_start + 1, strlen(funcname)) != 0) /* match after skipping delimiter */ + strncasecmp(funcname, func_name_start, strlen(funcname)) != 0 && + strncasecmp(funcname, func_name_start + 1, strlen(funcname)) != 0) /* match after skipping + * delimiter */ { temp += 1; func_name_start = temp; @@ -2440,16 +2594,15 @@ pltsql_store_func_default_positions(ObjectAddress address, List *parameters, con if (original_name == NULL) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("can't extract original function name."))); + errmsg("can't extract original function name."))); } /* * To store certain flag, Set corresponding bit in flag_validity which * tracks currently supported flag bits and then set/unset flag_values bit - * according to flag settings. - * Used !Transform_null_equals instead of pltsql_ansi_nulls because NULL is - * being inserted in catalog if it is used. - * Currently, Only two flags are supported. + * according to flag settings. Used !Transform_null_equals instead of + * pltsql_ansi_nulls because NULL is being inserted in catalog if it is + * used. Currently, Only two flags are supported. */ flag_validity |= FLAG_IS_ANSI_NULLS_ON; if (!Transform_null_equals) @@ -2461,12 +2614,13 @@ pltsql_store_func_default_positions(ObjectAddress address, List *parameters, con schema_name_NameData = (NameData *) palloc0(NAMEDATALEN); snprintf(schema_name_NameData->data, NAMEDATALEN, "%s", physical_schemaname); - new_record[Anum_bbf_function_ext_nspname -1] = NameGetDatum(schema_name_NameData); - new_record[Anum_bbf_function_ext_funcname -1] = NameGetDatum(&form_proctup->proname); + new_record[Anum_bbf_function_ext_nspname - 1] = NameGetDatum(schema_name_NameData); + new_record[Anum_bbf_function_ext_funcname - 1] = NameGetDatum(&form_proctup->proname); if (original_name) - new_record[Anum_bbf_function_ext_orig_name -1] = CStringGetTextDatum(original_name); + new_record[Anum_bbf_function_ext_orig_name - 1] = CStringGetTextDatum(original_name); else - new_record_nulls[Anum_bbf_function_ext_orig_name -1] = true; /* TODO: Fill users' original input name */ + new_record_nulls[Anum_bbf_function_ext_orig_name - 1] = true; /* TODO: Fill users' + * original input name */ new_record[Anum_bbf_function_ext_funcsignature - 1] = CStringGetTextDatum(func_signature); if (default_positions != NIL) new_record[Anum_bbf_function_ext_default_positions - 1] = CStringGetTextDatum(nodeToString(default_positions)); @@ -2476,6 +2630,7 @@ pltsql_store_func_default_positions(ObjectAddress address, List *parameters, con new_record[Anum_bbf_function_ext_flag_values - 1] = UInt64GetDatum(flag_values); new_record[Anum_bbf_function_ext_create_date - 1] = TimestampGetDatum(GetSQLLocalTimestamp(3)); new_record[Anum_bbf_function_ext_modify_date - 1] = TimestampGetDatum(GetSQLLocalTimestamp(3)); + /* * Save the original query in the catalog. */ @@ -2499,14 +2654,15 @@ pltsql_store_func_default_positions(ObjectAddress address, List *parameters, con else { ObjectAddress index; + tuple = heap_form_tuple(bbf_function_ext_rel_dsc, new_record, new_record_nulls); CatalogTupleInsert(bbf_function_ext_rel, tuple); /* - * Add function's dependency on catalog table's index so - * that table gets restored before function during MVU. + * Add function's dependency on catalog table's index so that table + * gets restored before function during MVU. */ index.classId = IndexRelationId; index.objectId = get_bbf_function_ext_idx_oid(); @@ -2527,7 +2683,8 @@ pltsql_store_func_default_positions(ObjectAddress address, List *parameters, con static void pltsql_drop_func_default_positions(Oid objectId) { - HeapTuple proctuple, bbffunctuple; + HeapTuple proctuple, + bbffunctuple; /* return if it is not a PL/tsql function */ proctuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(objectId)); @@ -2538,7 +2695,7 @@ pltsql_drop_func_default_positions(Oid objectId) if (HeapTupleIsValid(bbffunctuple)) { - Relation bbf_function_ext_rel; + Relation bbf_function_ext_rel; /* Fetch the relation */ bbf_function_ext_rel = table_open(get_bbf_function_ext_oid(), RowExclusiveLock); @@ -2579,7 +2736,7 @@ match_pltsql_func_call(HeapTuple proctup, int nargs, List *argnames, /* * Check argument count. */ - Assert(nargs >= 0); /* -1 not supported with argnames */ + Assert(nargs >= 0); /* -1 not supported with argnames */ if (pronargs > nargs && expand_defaults) { @@ -2609,9 +2766,8 @@ match_pltsql_func_call(HeapTuple proctup, int nargs, List *argnames, /* * Call uses positional notation * - * Check if function is variadic, and get variadic element type if - * so. If expand_variadic is false, we should just ignore - * variadic-ness. + * Check if function is variadic, and get variadic element type if so. + * If expand_variadic is false, we should just ignore variadic-ness. */ if (pronargs <= nargs && expand_variadic) { @@ -2644,8 +2800,8 @@ match_pltsql_func_call(HeapTuple proctup, int nargs, List *argnames, return false; /* - * If call uses all positional arguments, then validate if all - * the remaining arguments have defaults. + * If call uses all positional arguments, then validate if all the + * remaining arguments have defaults. */ if (*use_defaults) { @@ -2653,8 +2809,8 @@ match_pltsql_func_call(HeapTuple proctup, int nargs, List *argnames, if (HeapTupleIsValid(bbffunctuple)) { - Datum arg_default_positions; - bool isnull; + Datum arg_default_positions; + bool isnull; /* Fetch default positions */ arg_default_positions = SysCacheGetAttr(PROCNSPSIGNATURE, @@ -2664,10 +2820,10 @@ match_pltsql_func_call(HeapTuple proctup, int nargs, List *argnames, if (!isnull) { - char *str; - List *default_positions = NIL; - ListCell *def_idx = NULL; - int idx = nargs; + char *str; + List *default_positions = NIL; + ListCell *def_idx = NULL; + int idx = nargs; str = TextDatumGetCString(arg_default_positions); default_positions = castNode(List, stringToNode(str)); @@ -2675,7 +2831,7 @@ match_pltsql_func_call(HeapTuple proctup, int nargs, List *argnames, foreach(def_idx, default_positions) { - int position = intVal((Node *) lfirst(def_idx)); + int position = intVal((Node *) lfirst(def_idx)); if (position == idx) idx++; @@ -2725,16 +2881,16 @@ PlTsqlMatchNamedCall(HeapTuple proctup, int nargs, List *argnames, int **argnumbers, List **defaults) { Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup); - int numposargs = nargs - list_length(argnames); - int pronallargs; - Oid *p_argtypes; - char **p_argnames; - char *p_argmodes; - bool arggiven[FUNC_MAX_ARGS]; - bool isnull; - int ap; /* call args position */ - int pp; /* proargs position */ - ListCell *lc; + int numposargs = nargs - list_length(argnames); + int pronallargs; + Oid *p_argtypes; + char **p_argnames; + char *p_argmodes; + bool arggiven[FUNC_MAX_ARGS]; + bool isnull; + int ap; /* call args position */ + int pp; /* proargs position */ + ListCell *lc; Assert(argnames != NIL); Assert(numposargs >= 0); @@ -2809,11 +2965,11 @@ PlTsqlMatchNamedCall(HeapTuple proctup, int nargs, List *argnames, { int first_arg_with_default = pronargs - procform->pronargdefaults; HeapTuple bbffunctuple = get_bbf_function_tuple_from_proctuple(proctup); - List *argdefaults = NIL, - *default_positions = NIL; + List *argdefaults = NIL, + *default_positions = NIL; bool default_positions_available = false; - ListCell *def_item = NULL, - *def_idx = NULL; + ListCell *def_item = NULL, + *def_idx = NULL; bool match_found = true; if (HeapTupleIsValid(bbffunctuple)) @@ -2823,12 +2979,12 @@ PlTsqlMatchNamedCall(HeapTuple proctup, int nargs, List *argnames, /* Fetch argument defaults */ proargdefaults = SysCacheGetAttr(PROCOID, proctup, - Anum_pg_proc_proargdefaults, - &isnull); + Anum_pg_proc_proargdefaults, + &isnull); if (!isnull) { - char *str; + char *str; str = TextDatumGetCString(proargdefaults); argdefaults = castNode(List, stringToNode(str)); @@ -2844,7 +3000,7 @@ PlTsqlMatchNamedCall(HeapTuple proctup, int nargs, List *argnames, if (!isnull) { - char *str; + char *str; str = TextDatumGetCString(arg_default_positions); default_positions = castNode(List, stringToNode(str)); @@ -2862,21 +3018,21 @@ PlTsqlMatchNamedCall(HeapTuple proctup, int nargs, List *argnames, continue; /* - * If the positions of default arguments are available then we need - * special handling. Look into default_positions list to find out - * the default expression for pp'th argument. + * If the positions of default arguments are available then we + * need special handling. Look into default_positions list to find + * out the default expression for pp'th argument. */ if (default_positions_available) { - bool has_default = false; + bool has_default = false; /* - * Iterate over argdefaults list to find out the default expression - * for current argument. + * Iterate over argdefaults list to find out the default + * expression for current argument. */ while (def_item != NULL && def_idx != NULL) { - int position = intVal((Node *) lfirst(def_idx)); + int position = intVal((Node *) lfirst(def_idx)); if (position == pp) { @@ -2939,8 +3095,8 @@ insert_pltsql_function_defaults(HeapTuple func_tuple, List *defaults, Node **arg if (HeapTupleIsValid(bbffunctuple)) { - Datum arg_default_positions; - bool isnull; + Datum arg_default_positions; + bool isnull; /* Fetch default positions */ arg_default_positions = SysCacheGetAttr(PROCNSPSIGNATURE, @@ -2950,10 +3106,10 @@ insert_pltsql_function_defaults(HeapTuple func_tuple, List *defaults, Node **arg if (!isnull) { - char *str; - List *default_positions = NIL; - ListCell *def_idx = NULL, - *def_item = NULL; + char *str; + List *default_positions = NIL; + ListCell *def_idx = NULL, + *def_item = NULL; str = TextDatumGetCString(arg_default_positions); default_positions = castNode(List, stringToNode(str)); @@ -2961,7 +3117,7 @@ insert_pltsql_function_defaults(HeapTuple func_tuple, List *defaults, Node **arg forboth(def_idx, default_positions, def_item, defaults) { - int position = intVal((Node *) lfirst(def_idx)); + int position = intVal((Node *) lfirst(def_idx)); if (argarray[position] == NULL) argarray[position] = (Node *) lfirst(def_item); @@ -2973,8 +3129,8 @@ insert_pltsql_function_defaults(HeapTuple func_tuple, List *defaults, Node **arg else { Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple); - int i; - ListCell *lc = NULL; + int i; + ListCell *lc = NULL; i = funcform->pronargs - funcform->pronargdefaults; foreach(lc, defaults) @@ -3148,8 +3304,8 @@ print_pltsql_function_arguments(StringInfo buf, HeapTuple proctup, { if (nextdefaultposition != NULL) { - int position = intVal((Node *) lfirst(nextdefaultposition)); - Node *defexpr; + int position = intVal((Node *) lfirst(nextdefaultposition)); + Node *defexpr; Assert(nextargdefault != NULL); defexpr = (Node *) lfirst(nextargdefault); @@ -3194,7 +3350,7 @@ print_pltsql_function_arguments(StringInfo buf, HeapTuple proctup, static PlannedStmt * pltsql_planner_hook(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams) { - PlannedStmt * plan; + PlannedStmt *plan; PLtsql_execstate *estate = NULL; if (pltsql_explain_analyze) @@ -3216,17 +3372,17 @@ pltsql_planner_hook(Query *parse, const char *query_string, int cursorOptions, P return plan; } -static Node* -transform_like_in_add_constraint (Node* node) +static Node * +transform_like_in_add_constraint(Node *node) { PG_TRY(); { - if (!babelfish_dump_restore && current_query_is_create_tbl_check_constraint - && has_ilike_node_and_ci_as_coll(node)) + if (!babelfish_dump_restore && current_query_is_create_tbl_check_constraint + && has_ilike_node_and_ci_as_coll(node)) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("nondeterministic collations are not supported for ILIKE"))); + errmsg("nondeterministic collations are not supported for ILIKE"))); } } PG_FINALLY(); @@ -3234,28 +3390,31 @@ transform_like_in_add_constraint (Node* node) current_query_is_create_tbl_check_constraint = false; } PG_END_TRY(); - + return pltsql_predicate_transformer(node); } /* * pltsql_validate_var_datatype_scale() - * - Checks whether variable length datatypes like numeric, decimal, time, datetime2, datetimeoffset + * - Checks whether variable length datatypes like numeric, decimal, time, datetime2, datetimeoffset * are declared with permissible datalength at the time of table or stored procedure creation */ -void pltsql_validate_var_datatype_scale(const TypeName *typeName, Type typ) +void +pltsql_validate_var_datatype_scale(const TypeName *typeName, Type typ) { - Oid datatype_oid = InvalidOid; - int count = 0; + Oid datatype_oid = InvalidOid; + int count = 0; ListCell *l; - int scale[2] = {-1, -1}; - char *dataTypeName, *schemaName; + int scale[2] = {-1, -1}; + char *dataTypeName, + *schemaName; DeconstructQualifiedName(typeName->names, &schemaName, &dataTypeName); foreach(l, typeName->typmods) { - Node *tm = (Node *) lfirst(l); + Node *tm = (Node *) lfirst(l); + if (IsA(tm, A_Const)) { A_Const *ac = (A_Const *) tm; @@ -3271,42 +3430,43 @@ void pltsql_validate_var_datatype_scale(const TypeName *typeName, Type typ) datatype_oid = ((Form_pg_type) GETSTRUCT(typ))->oid; if ((datatype_oid == DATEOID || - (*common_utility_plugin_ptr->is_tsql_timestamp_datatype)(datatype_oid) || - (*common_utility_plugin_ptr->is_tsql_smalldatetime_datatype)(datatype_oid)) && + (*common_utility_plugin_ptr->is_tsql_timestamp_datatype) (datatype_oid) || + (*common_utility_plugin_ptr->is_tsql_smalldatetime_datatype) (datatype_oid)) && scale[0] == -1) { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("Cannot specify a column width on datatype \'%s\'", - dataTypeName))); + dataTypeName))); } else if ((datatype_oid == TIMEOID || - (*common_utility_plugin_ptr->is_tsql_datetime2_datatype)(datatype_oid) || - (*common_utility_plugin_ptr->is_tsql_datetimeoffset_datatype)(datatype_oid)) && - (scale[0] < 0 || scale[0] > 7)) + (*common_utility_plugin_ptr->is_tsql_datetime2_datatype) (datatype_oid) || + (*common_utility_plugin_ptr->is_tsql_datetimeoffset_datatype) (datatype_oid)) && + (scale[0] < 0 || scale[0] > 7)) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Specified scale %d is invalid. \'%s\' datatype must have scale between 0 and 7", - scale[0], dataTypeName))); + scale[0], dataTypeName))); } else if (datatype_oid == NUMERICOID || - (*common_utility_plugin_ptr->is_tsql_decimal_datatype)(datatype_oid)) + (*common_utility_plugin_ptr->is_tsql_decimal_datatype) (datatype_oid)) { /* - * Since numeric/decimal datatype stores precision in scale[0] and scale in scale[1] + * Since numeric/decimal datatype stores precision in scale[0] and + * scale in scale[1] */ if (scale[0] < 1 || scale[0] > TDS_NUMERIC_MAX_PRECISION) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Specified column precision %d for \'%s\' datatype must be within the range 1 to maximum precision(38)", - scale[0], dataTypeName))); + scale[0], dataTypeName))); if (scale[1] < 0 || scale[1] > scale[0]) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("The scale %d for \'%s\' datatype must be within the range 0 to precision %d", - scale[1], dataTypeName, scale[0]))); + scale[1], dataTypeName, scale[0]))); } } @@ -3314,14 +3474,14 @@ void pltsql_validate_var_datatype_scale(const TypeName *typeName, Type typ) * Modify the Tuple Descriptor to match the expected * result set. Currently used only for T-SQL OPENQUERY. */ -static void +static void modify_RangeTblFunction_tupdesc(char *funcname, Node *expr, TupleDesc *tupdesc) { - char* linked_server; - char* query; + char *linked_server; + char *query; - FuncExpr *funcexpr; - List* arg_list; + FuncExpr *funcexpr; + List *arg_list; /* * Only override tupdesc for T-SQL OPENQUERY @@ -3329,17 +3489,17 @@ modify_RangeTblFunction_tupdesc(char *funcname, Node *expr, TupleDesc *tupdesc) if (!funcname || (strlen(funcname) != 9) || (strncasecmp(funcname, "openquery", 9) != 0)) return; - funcexpr = (FuncExpr*) expr; + funcexpr = (FuncExpr *) expr; arg_list = funcexpr->args; /* - * According to T-SQL OPENQUERY SQL definition, we will get - * linked server name and the query to execute as arguments. + * According to T-SQL OPENQUERY SQL definition, we will get linked server + * name and the query to execute as arguments. */ Assert(list_length(arg_list) == 2); - linked_server = TextDatumGetCString(((Const*)linitial(arg_list))->constvalue); - query = TextDatumGetCString(((Const*)lsecond(arg_list))->constvalue); + linked_server = TextDatumGetCString(((Const *) linitial(arg_list))->constvalue); + query = TextDatumGetCString(((Const *) lsecond(arg_list))->constvalue); GetOpenqueryTupdescFromMetadata(linked_server, query, tupdesc); @@ -3353,54 +3513,58 @@ modify_RangeTblFunction_tupdesc(char *funcname, Node *expr, TupleDesc *tupdesc) static int pltsql_set_target_table_alternative(ParseState *pstate, Node *stmt, CmdType command) { - RangeVar *target = NULL; - RangeVar *relation; - bool inh; - AclMode requiredPerms; + RangeVar *target = NULL; + RangeVar *relation; + bool inh; + AclMode requiredPerms; switch (command) { - /* - * For DELETE and UPDATE statement, we need to properly handle target table - * based on FROM clause and clean up the duplicate table references. - */ + /* + * For DELETE and UPDATE statement, we need to properly handle + * target table based on FROM clause and clean up the duplicate + * table references. + */ case CMD_DELETE: - { - DeleteStmt *delete_stmt = (DeleteStmt *) stmt; - - relation = delete_stmt->relation; - inh = delete_stmt->relation->inh; - requiredPerms = ACL_DELETE; + { + DeleteStmt *delete_stmt = (DeleteStmt *) stmt; - if (sql_dialect != SQL_DIALECT_TSQL || output_update_transformation) - break; + relation = delete_stmt->relation; + inh = delete_stmt->relation->inh; + requiredPerms = ACL_DELETE; - target = pltsql_get_target_table(relation, delete_stmt->usingClause); + if (sql_dialect != SQL_DIALECT_TSQL || output_update_transformation) + break; - break; - } + target = pltsql_get_target_table(relation, delete_stmt->usingClause); + + break; + } case CMD_UPDATE: - { - UpdateStmt *update_stmt = (UpdateStmt *) stmt; + { + UpdateStmt *update_stmt = (UpdateStmt *) stmt; - relation = update_stmt->relation; - inh = update_stmt->relation->inh; - requiredPerms = ACL_UPDATE; + relation = update_stmt->relation; + inh = update_stmt->relation->inh; + requiredPerms = ACL_UPDATE; - if (sql_dialect != SQL_DIALECT_TSQL) - break; + if (sql_dialect != SQL_DIALECT_TSQL) + break; - if (!output_update_transformation) - target = pltsql_get_target_table(relation, update_stmt->fromClause); + if (!output_update_transformation) + target = pltsql_get_target_table(relation, update_stmt->fromClause); - /* Special handling when target table contains a rowversion column */ - if (target) - handle_rowversion_target_in_update_stmt(target, update_stmt); - else - handle_rowversion_target_in_update_stmt(relation, update_stmt); + /* + * Special handling when target table contains a rowversion + * column + */ + if (target) + handle_rowversion_target_in_update_stmt(target, update_stmt); + else + handle_rowversion_target_in_update_stmt(relation, update_stmt); - break; - } + break; + } default: ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), @@ -3409,11 +3573,12 @@ pltsql_set_target_table_alternative(ParseState *pstate, Node *stmt, CmdType comm if (target) { - int res = setTargetTable(pstate, target, inh, false, requiredPerms); + int res = setTargetTable(pstate, target, inh, false, requiredPerms); + pstate->p_rtable = NIL; rewrite_update_outer_join(stmt, command, target); - + return res; } @@ -3427,15 +3592,16 @@ pltsql_set_target_table_alternative(ParseState *pstate, Node *stmt, CmdType comm static void fill_missing_values_in_copyfrom(Relation rel, Datum *values, bool *nulls) { - Oid relid; + Oid relid; if (!babelfish_dump_restore || IsBinaryUpgrade) return; relid = RelationGetRelid(rel); + /* - * Insert new dbid column value in babelfish catalog if dump did - * not provide it. + * Insert new dbid column value in babelfish catalog if dump did not + * provide it. */ if (relid == sysdatabases_oid || relid == namespace_ext_oid || @@ -3456,8 +3622,11 @@ fill_missing_values_in_copyfrom(Relation rel, Datum *values, bool *nulls) } } -static bool bbf_check_rowcount_hook(int es_processed){ +static bool +bbf_check_rowcount_hook(int es_processed) +{ if (pltsql_rowcount == es_processed && es_processed > 0) return true; - else return false; + else + return false; } diff --git a/contrib/babelfishpg_tsql/src/hooks.h b/contrib/babelfishpg_tsql/src/hooks.h index e68448d3a5..3efc536d44 100644 --- a/contrib/babelfishpg_tsql/src/hooks.h +++ b/contrib/babelfishpg_tsql/src/hooks.h @@ -11,14 +11,14 @@ extern void UninstallExtendedHooks(void); extern bool output_update_transformation; extern bool output_into_insert_transformation; -extern char* extract_identifier(const char *start); +extern char *extract_identifier(const char *start); extern void pltsql_store_func_default_positions(ObjectAddress address, List *parameters, const char *queryString, int origname_location); -extern Oid get_tsql_trigger_oid(List *object, - const char *tsql_trigger_name, - bool object_from_input); +extern Oid get_tsql_trigger_oid(List *object, + const char *tsql_trigger_name, + bool object_from_input); extern char *update_delete_target_alias; extern bool sp_describe_first_result_set_inprogress; diff --git a/contrib/babelfishpg_tsql/src/iterative_exec.c b/contrib/babelfishpg_tsql/src/iterative_exec.c index dc7d528f10..d6d5d4f079 100644 --- a/contrib/babelfishpg_tsql/src/iterative_exec.c +++ b/contrib/babelfishpg_tsql/src/iterative_exec.c @@ -10,24 +10,24 @@ * Execution Actions **************************************************************************************/ -static int exec_stmt_goto(PLtsql_execstate *estate, PLtsql_stmt_goto *stmt); -static int exec_stmt_set_explain_mode(PLtsql_execstate *estate, PLtsql_stmt_set_explain_mode *stmt); -static int exec_stmt_restore_ctx_full(PLtsql_execstate *estate, PLtsql_stmt_restore_ctx_full *stmt); -static int exec_stmt_restore_ctx_partial(PLtsql_execstate *estate, PLtsql_stmt_restore_ctx_partial *stmt); -static int exec_stmt_raiserror(PLtsql_execstate *estate, PLtsql_stmt_raiserror *stmt); -static int exec_stmt_throw(PLtsql_execstate *estate, PLtsql_stmt_throw *stmt); +static int exec_stmt_goto(PLtsql_execstate *estate, PLtsql_stmt_goto *stmt); +static int exec_stmt_set_explain_mode(PLtsql_execstate *estate, PLtsql_stmt_set_explain_mode *stmt); +static int exec_stmt_restore_ctx_full(PLtsql_execstate *estate, PLtsql_stmt_restore_ctx_full *stmt); +static int exec_stmt_restore_ctx_partial(PLtsql_execstate *estate, PLtsql_stmt_restore_ctx_partial *stmt); +static int exec_stmt_raiserror(PLtsql_execstate *estate, PLtsql_stmt_raiserror *stmt); +static int exec_stmt_throw(PLtsql_execstate *estate, PLtsql_stmt_throw *stmt); static void restore_ctx_full(PLtsql_execstate *estate); -static ErrorData * restore_ctx_partial1(PLtsql_execstate *estate); +static ErrorData *restore_ctx_partial1(PLtsql_execstate *estate); static void restore_ctx_partial2(PLtsql_execstate *estate); static void set_exec_error_data(char *procedure, int number, int severity, int state, bool rethrow); static void reset_exec_error_data(PLtsql_execstate *estate); static void assert_equal_estate_err(PLtsql_estate_err *err1, PLtsql_estate_err *err2); static void read_raiserror_params(PLtsql_execstate *estate, List *params, int paramno, char **msg, int *msg_id, int *severity, int *state); -static int read_raiserror_params_explain(List *params, int paramno); -static void read_throw_params(PLtsql_execstate *estate, List *params, +static int read_raiserror_params_explain(List *params, int paramno); +static void read_throw_params(PLtsql_execstate *estate, List *params, char **msg, int *err_no, int *state); -static int read_throw_params_explain(List *params); +static int read_throw_params_explain(List *params); static char *get_proc_name(PLtsql_execstate *estate); static bool is_seterror_on(PLtsql_stmt *stmt); @@ -35,49 +35,51 @@ static void process_explain(PLtsql_execstate *estate); static void process_explain_analyze(PLtsql_execstate *estate); extern PLtsql_estate_err *pltsql_clone_estate_err(PLtsql_estate_err *err); -extern void prepare_format_string(StringInfo buf, char *msg_string, int nargs, +extern void prepare_format_string(StringInfo buf, char *msg_string, int nargs, Datum *args, Oid *argtypes, bool *argisnull); -static int exec_stmt_goto(PLtsql_execstate *estate, PLtsql_stmt_goto *stmt) +static int +exec_stmt_goto(PLtsql_execstate *estate, PLtsql_stmt_goto *stmt) { if (pltsql_explain_only && stmt->cond) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Showing Estimated Execution Plan for CONDITIONAL GOTO statement is not yet supported"))); + errmsg("Showing Estimated Execution Plan for CONDITIONAL GOTO statement is not yet supported"))); } - if (stmt->cond) - { + if (stmt->cond) + { /* conditional jump */ - bool isnull = false; - bool value = exec_eval_boolean(estate, stmt->cond, &isnull); + bool isnull = false; + bool value = exec_eval_boolean(estate, stmt->cond, &isnull); - exec_eval_cleanup(estate); + exec_eval_cleanup(estate); /* jump if condition is NULL or false */ if (isnull || (value == false)) - estate->pc = (stmt->target_pc - 1); - } - else /* unconditional jump */ - estate->pc = (stmt->target_pc - 1); + estate->pc = (stmt->target_pc - 1); + } + else /* unconditional jump */ + estate->pc = (stmt->target_pc - 1); - return PLTSQL_RC_OK; + return PLTSQL_RC_OK; } -static int exec_stmt_set_explain_mode(PLtsql_execstate *estate, PLtsql_stmt_set_explain_mode *stmt) +static int +exec_stmt_set_explain_mode(PLtsql_execstate *estate, PLtsql_stmt_set_explain_mode *stmt) { - if (!stmt->is_explain_only^stmt->is_explain_analyze) + if (!stmt->is_explain_only ^ stmt->is_explain_analyze) { ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("Only EXPLAIN ONLY or EXPLAIN ANALYZE must be TRUE"))); + errmsg("Only EXPLAIN ONLY or EXPLAIN ANALYZE must be TRUE"))); } if (pltsql_explain_only) { if (stmt->is_explain_only && !stmt->val) - pltsql_explain_only = false; /* Turn off EXPLAIN ONLY MODE */ + pltsql_explain_only = false; /* Turn off EXPLAIN ONLY MODE */ else append_explain_info(NULL, stmt->query); } @@ -92,14 +94,15 @@ static int exec_stmt_set_explain_mode(PLtsql_execstate *estate, PLtsql_stmt_set_ return PLTSQL_RC_OK; } -static int exec_stmt_raiserror(PLtsql_execstate *estate, PLtsql_stmt_raiserror *stmt) +static int +exec_stmt_raiserror(PLtsql_execstate *estate, PLtsql_stmt_raiserror *stmt) { - int elevel; - char *msg = NULL; - char *proc_name = NULL; - int msg_id = 50000; - int severity = -1; - int state = -1; + int elevel; + char *msg = NULL; + char *proc_name = NULL; + int msg_id = 50000; + int severity = -1; + int state = -1; if (pltsql_explain_only) return read_raiserror_params_explain(stmt->params, stmt->paramno); @@ -112,10 +115,10 @@ static int exec_stmt_raiserror(PLtsql_execstate *estate, PLtsql_stmt_raiserror * if (severity < 0 || severity > 24) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("severity argument of RAISERROR should be in the range of 0 - 24"))); + errmsg("severity argument of RAISERROR should be in the range of 0 - 24"))); - if (stmt->seterror) - exec_set_error(estate, msg_id, 0, false /* error_mapping_failed */); + if (stmt->seterror) + exec_set_error(estate, msg_id, 0, false /* error_mapping_failed */ ); /* Simply print out the error message if severity <= 10 */ if (severity <= 10) @@ -123,17 +126,17 @@ static int exec_stmt_raiserror(PLtsql_execstate *estate, PLtsql_stmt_raiserror * /* Severity > 18 need sysadmin role using WITH LOG option */ else if (severity > 18 && !stmt->log) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("error severity levels greater than 18 require WITH LOG option."))); + errmsg("error severity levels greater than 18 require WITH LOG option."))); /* Otherwise, report error */ else { elevel = ERROR; proc_name = get_proc_name(estate); /* Update error data info in exec_state_call_stack */ - set_exec_error_data(proc_name, msg_id, severity, state, false /* rethrow */); + set_exec_error_data(proc_name, msg_id, severity, state, false /* rethrow */ ); } - ereport(elevel, (errcode(ERRCODE_PLTSQL_RAISERROR), - errmsg_internal("%s", msg))); + ereport(elevel, (errcode(ERRCODE_PLTSQL_RAISERROR), + errmsg_internal("%s", msg))); if (elevel == INFO && *pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->send_info) ((*pltsql_protocol_plugin_ptr)->send_info) (0, @@ -145,12 +148,13 @@ static int exec_stmt_raiserror(PLtsql_execstate *estate, PLtsql_stmt_raiserror * return PLTSQL_RC_OK; } -static int exec_stmt_throw(PLtsql_execstate *estate, PLtsql_stmt_throw *stmt) +static int +exec_stmt_throw(PLtsql_execstate *estate, PLtsql_stmt_throw *stmt) { - char *msg = NULL; - char *proc_name = NULL; - int err_no = -1; - int state = -1; + char *msg = NULL; + char *proc_name = NULL; + int err_no = -1; + int state = -1; /* THROW without params is to re-throw */ if (stmt->params == NIL) @@ -158,8 +162,12 @@ static int exec_stmt_throw(PLtsql_execstate *estate, PLtsql_stmt_throw *stmt) /* Check if we are inside a CATCH block */ if (estate->cur_error == NULL || estate->cur_error->error == NULL) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("THROW without parameters should be executed inside a CATCH block"))); - /* If only explaining, don't actually perform the throw, just append query text */ + errmsg("THROW without parameters should be executed inside a CATCH block"))); + + /* + * If only explaining, don't actually perform the throw, just append + * query text + */ if (pltsql_explain_only) { append_explain_info(NULL, "THROW"); @@ -170,7 +178,7 @@ static int exec_stmt_throw(PLtsql_execstate *estate, PLtsql_stmt_throw *stmt) estate->cur_error->number, estate->cur_error->severity, estate->cur_error->state, - true /* rethrow */); + true /* rethrow */ ); ReThrowError(estate->cur_error->error); } else @@ -186,150 +194,158 @@ static int exec_stmt_throw(PLtsql_execstate *estate, PLtsql_stmt_throw *stmt) exec_eval_cleanup(estate); /* Update error data info in exec_state_call_stack */ - set_exec_error_data(proc_name, err_no, 16, state, false /* rethrow */); - ereport(ERROR, (errcode(ERRCODE_PLTSQL_THROW), - errmsg_internal("%s", msg))); + set_exec_error_data(proc_name, err_no, 16, state, false /* rethrow */ ); + ereport(ERROR, (errcode(ERRCODE_PLTSQL_THROW), + errmsg_internal("%s", msg))); } return PLTSQL_RC_OK; } -static int exec_stmt_restore_ctx_full(PLtsql_execstate *estate, PLtsql_stmt_restore_ctx_full *stmt) +static int +exec_stmt_restore_ctx_full(PLtsql_execstate *estate, PLtsql_stmt_restore_ctx_full *stmt) { - estate->err_text = gettext_noop("during statement block exit"); - /* restore error context */ - restore_ctx_full(estate); - return PLTSQL_RC_OK; + estate->err_text = gettext_noop("during statement block exit"); + /* restore error context */ + restore_ctx_full(estate); + return PLTSQL_RC_OK; } -static int exec_stmt_restore_ctx_partial(PLtsql_execstate *estate, PLtsql_stmt_restore_ctx_partial *stmt) +static int +exec_stmt_restore_ctx_partial(PLtsql_execstate *estate, PLtsql_stmt_restore_ctx_partial *stmt) { - restore_ctx_partial2(estate); - estate->err_text = NULL; - return PLTSQL_RC_OK; + restore_ctx_partial2(estate); + estate->err_text = NULL; + return PLTSQL_RC_OK; } -static void restore_ctx_full(PLtsql_execstate *estate) +static void +restore_ctx_full(PLtsql_execstate *estate) { - int i; - PLtsql_errctx *cur_err_ctx = *(PLtsql_errctx **) vec_at(estate->err_ctx_stack, - estate->cur_err_ctx_idx); + int i; + PLtsql_errctx *cur_err_ctx = *(PLtsql_errctx **) vec_at(estate->err_ctx_stack, + estate->cur_err_ctx_idx); - MemoryContextSwitchTo(cur_err_ctx->oldcontext); + MemoryContextSwitchTo(cur_err_ctx->oldcontext); - /* Assert that the stmt_mcontext stack is unchanged */ - Assert(cur_err_ctx->stmt_mcontext == estate->stmt_mcontext); + /* Assert that the stmt_mcontext stack is unchanged */ + Assert(cur_err_ctx->stmt_mcontext == estate->stmt_mcontext); - /* PG_TRY_END */ - PG_exception_stack = cur_err_ctx->save_exception_stack; - error_context_stack = cur_err_ctx->save_context_stack; + /* PG_TRY_END */ + PG_exception_stack = cur_err_ctx->save_exception_stack; + error_context_stack = cur_err_ctx->save_context_stack; assert_equal_estate_err(cur_err_ctx->save_cur_error, estate->cur_error); estate->err_text = NULL; - vec_pop_back(estate->err_ctx_stack); - - /* find next active error context index */ - for ( i = (int) (estate->cur_err_ctx_idx) - 1; i >=0 ; i--) - { - PLtsql_errctx *context = *(PLtsql_errctx **) vec_at(estate->err_ctx_stack, i); - if (!context->partial_restored) - { - /* cur_err_ctx_idx is pointing to this error context */ - estate->cur_err_ctx_idx = i; - break; - } - } + vec_pop_back(estate->err_ctx_stack); + + /* find next active error context index */ + for (i = (int) (estate->cur_err_ctx_idx) - 1; i >= 0; i--) + { + PLtsql_errctx *context = *(PLtsql_errctx **) vec_at(estate->err_ctx_stack, i); + + if (!context->partial_restored) + { + /* cur_err_ctx_idx is pointing to this error context */ + estate->cur_err_ctx_idx = i; + break; + } + } } -static ErrorData *restore_ctx_partial1(PLtsql_execstate *estate) +static ErrorData * +restore_ctx_partial1(PLtsql_execstate *estate) { - ErrorData *edata; - PLtsql_errctx *cur_err_ctx = *(PLtsql_errctx **) vec_at(estate->err_ctx_stack, - estate->cur_err_ctx_idx); + ErrorData *edata; + PLtsql_errctx *cur_err_ctx = *(PLtsql_errctx **) vec_at(estate->err_ctx_stack, + estate->cur_err_ctx_idx); - PG_exception_stack = cur_err_ctx->save_exception_stack; - error_context_stack = cur_err_ctx->save_context_stack; + PG_exception_stack = cur_err_ctx->save_exception_stack; + error_context_stack = cur_err_ctx->save_context_stack; - estate->err_text = gettext_noop("during exception cleanup"); + estate->err_text = gettext_noop("during exception cleanup"); - /* Save error info in our stmt_mcontext */ - MemoryContextSwitchTo(cur_err_ctx->stmt_mcontext); + /* Save error info in our stmt_mcontext */ + MemoryContextSwitchTo(cur_err_ctx->stmt_mcontext); edata = CopyErrorData(); FlushErrorState(); - MemoryContextSwitchTo(cur_err_ctx->oldcontext); - - /* - * Set up the stmt_mcontext stack as though we had restored our - * previous state and then done push_stmt_mcontext(). The push is - * needed so that statements in the exception handler won't - * clobber the error data that's in our stmt_mcontext. - */ - estate->stmt_mcontext_parent = cur_err_ctx->stmt_mcontext; - estate->stmt_mcontext = NULL; - - /* - * Now we can delete any nested stmt_mcontexts that might have - * been created as children of ours. (Note: we do not immediately - * release any statement-lifespan data that might have been left - * behind in stmt_mcontext itself. We could attempt that by doing - * a MemoryContextReset on it before collecting the error data - * above, but it seems too risky to do any significant amount of - * work before collecting the error.) - */ - MemoryContextDeleteChildren(cur_err_ctx->stmt_mcontext); - - /* - * Must clean up the econtext too. However, any tuple table made - * in the subxact will have been thrown away by SPI during subxact - * abort, so we don't need to (and mustn't try to) free the - * eval_tuptable. - */ - estate->eval_tuptable = NULL; - exec_eval_cleanup(estate); - - cur_err_ctx->partial_restored = true; /* update status */ + MemoryContextSwitchTo(cur_err_ctx->oldcontext); + + /* + * Set up the stmt_mcontext stack as though we had restored our previous + * state and then done push_stmt_mcontext(). The push is needed so that + * statements in the exception handler won't clobber the error data that's + * in our stmt_mcontext. + */ + estate->stmt_mcontext_parent = cur_err_ctx->stmt_mcontext; + estate->stmt_mcontext = NULL; + + /* + * Now we can delete any nested stmt_mcontexts that might have been + * created as children of ours. (Note: we do not immediately release any + * statement-lifespan data that might have been left behind in + * stmt_mcontext itself. We could attempt that by doing a + * MemoryContextReset on it before collecting the error data above, but it + * seems too risky to do any significant amount of work before collecting + * the error.) + */ + MemoryContextDeleteChildren(cur_err_ctx->stmt_mcontext); + + /* + * Must clean up the econtext too. However, any tuple table made in the + * subxact will have been thrown away by SPI during subxact abort, so we + * don't need to (and mustn't try to) free the eval_tuptable. + */ + estate->eval_tuptable = NULL; + exec_eval_cleanup(estate); + + cur_err_ctx->partial_restored = true; /* update status */ return edata; } -static void restore_ctx_partial2(PLtsql_execstate *estate) +static void +restore_ctx_partial2(PLtsql_execstate *estate) { - /* partial1 cleaned all dangling errors, so vec_back is current error context */ - PLtsql_errctx *cur_err_ctx = *(PLtsql_errctx **) vec_back(estate->err_ctx_stack); - - /* - * Restore previous state of cur_error, whether or not we executed - * a handler. This is needed in case an error got thrown from - * some inner block's exception handler. - */ + /* + * partial1 cleaned all dangling errors, so vec_back is current error + * context + */ + PLtsql_errctx *cur_err_ctx = *(PLtsql_errctx **) vec_back(estate->err_ctx_stack); + + /* + * Restore previous state of cur_error, whether or not we executed a + * handler. This is needed in case an error got thrown from some inner + * block's exception handler. + */ *estate->cur_error = *cur_err_ctx->save_cur_error; - /* Restore stmt_mcontext stack and release the error data */ - pop_stmt_mcontext(estate); - MemoryContextReset(cur_err_ctx->stmt_mcontext); + /* Restore stmt_mcontext stack and release the error data */ + pop_stmt_mcontext(estate); + MemoryContextReset(cur_err_ctx->stmt_mcontext); - /* end of current error handling */ - vec_pop_back(estate->err_ctx_stack); + /* end of current error handling */ + vec_pop_back(estate->err_ctx_stack); if (cur_err_ctx->save_cur_error) { if (cur_err_ctx->save_cur_error->procedure) pfree(cur_err_ctx->save_cur_error->procedure); pfree(cur_err_ctx->save_cur_error); } - pfree(cur_err_ctx); + pfree(cur_err_ctx); } /*************************************************************************************** - * STATISTICS & TRACING + * STATISTICS & TRACING **************************************************************************************/ typedef struct { - DynaVec *counts; - DynaVec *durations; - uint64_t total_duration; - uint64_t code_size; + DynaVec *counts; + DynaVec *durations; + uint64_t total_duration; + uint64_t code_size; } ExecStat; static inline bool trace_exec_enabled(uint64_t trace_mode); @@ -342,12 +358,12 @@ static inline void pre_exec_measure(uint64_t trace_mode, ExecStat *stat, struct static inline void post_exec_measure(uint64_t trace_mode, ExecStat *stat, struct timeval *stmt_end, int pc); static inline void initialize_trace(uint64_t trace_mode, ExecStat **stat, struct timeval *proc_begin, size_t size); static inline void finalize_trace(uint64_t trace_mode, ExecCodes *exec_codes, ExecStat *stat, struct timeval *proc_begin); - -ExecStat *create_stat(size_t code_size, uint64_t trace_mode); -void destroy_stat(ExecStat *stat); + +ExecStat *create_stat(size_t code_size, uint64_t trace_mode); +void destroy_stat(ExecStat *stat); #define TRACE_LOCAL_BUF_SIZE 256 -static void get_code_desc(PLtsql_stmt *stmt, const char *namespace, const char * name, StringInfo buf); +static void get_code_desc(PLtsql_stmt *stmt, const char *namespace, const char *name, StringInfo buf); static void get_stat_desc(ExecStat *stat, size_t index, StringInfo buf); static void get_stat_trace(ExecCodes *exec_code, ExecStat *stat, StringInfo buf); @@ -355,231 +371,248 @@ static void get_stat_trace(ExecCodes *exec_code, ExecStat *stat, StringInfo buf) static void desc_stmt_goto(PLtsql_stmt_goto *stmt, char *buf); static void desc_stmt_save_ctx(PLtsql_stmt_save_ctx *stmt, char *buf); -static inline bool trace_exec_enabled(uint64_t trace_mode) +static inline bool +trace_exec_enabled(uint64_t trace_mode) { - return trace_mode > 0; + return trace_mode > 0; } -static inline bool trace_exec_codes_enabled(uint64_t trace_mode) +static inline bool +trace_exec_codes_enabled(uint64_t trace_mode) { - return trace_mode & TRACE_EXEC_CODES; + return trace_mode & TRACE_EXEC_CODES; } -static inline bool trace_exec_counts_enabled(uint64_t trace_mode) +static inline bool +trace_exec_counts_enabled(uint64_t trace_mode) { - return (trace_mode & TRACE_EXEC_COUNTS) == TRACE_EXEC_COUNTS; + return (trace_mode & TRACE_EXEC_COUNTS) == TRACE_EXEC_COUNTS; } -static inline bool trace_exec_time_enabled(uint64_t trace_mode) +static inline bool +trace_exec_time_enabled(uint64_t trace_mode) { - return (trace_mode & TRACE_EXEC_TIME) == TRACE_EXEC_TIME; + return (trace_mode & TRACE_EXEC_TIME) == TRACE_EXEC_TIME; } -static inline void +static inline void pre_exec_measure(uint64_t trace_mode, ExecStat *stat, struct timeval *stmt_begin, int pc) { if (trace_exec_counts_enabled(trace_mode)) { - size_t *cur_cnt = (size_t *) vec_at(stat->counts, pc); + size_t *cur_cnt = (size_t *) vec_at(stat->counts, pc); + ++(*cur_cnt); } if (trace_exec_time_enabled(trace_mode)) gettimeofday(stmt_begin, NULL); } -static inline void +static inline void post_exec_measure(uint64_t trace_mode, ExecStat *stat, struct timeval *stmt_begin, int pc) { if (trace_exec_time_enabled(trace_mode)) { struct timeval stmt_end; - long seconds, microseconds; - size_t *cur_duration = (size_t *) vec_at(stat->durations, pc); + long seconds, + microseconds; + size_t *cur_duration = (size_t *) vec_at(stat->durations, pc); + gettimeofday(&stmt_end, NULL); seconds = stmt_end.tv_sec - stmt_begin->tv_sec; microseconds = stmt_end.tv_usec - stmt_begin->tv_usec; - *(cur_duration) += seconds*1000 + microseconds/1000; /* in ms unit */ + *(cur_duration) += seconds * 1000 + microseconds / 1000; /* in ms unit */ } } -static inline void +static inline void initialize_trace(uint64_t trace_mode, ExecStat **stat, struct timeval *proc_begin, size_t size) { - if (trace_exec_enabled(trace_mode)) - { - *stat = create_stat(size, trace_mode); - gettimeofday(proc_begin, NULL); - } + if (trace_exec_enabled(trace_mode)) + { + *stat = create_stat(size, trace_mode); + gettimeofday(proc_begin, NULL); + } } -static inline void +static inline void finalize_trace(uint64_t trace_mode, ExecCodes *exec_codes, ExecStat *stat, struct timeval *proc_begin) { if (trace_exec_enabled(trace_mode)) - { - long seconds, microseconds; - StringInfoData buf; - struct timeval proc_end; - - gettimeofday(&proc_end, NULL); - seconds = proc_end.tv_sec - proc_begin->tv_sec; - microseconds = proc_end.tv_usec - proc_begin->tv_usec; - - stat->total_duration = seconds*1000 + microseconds/1000; /* in ms unit */ - initStringInfo(&buf); - get_stat_trace(exec_codes, stat, &buf); - ereport(LOG, (errmsg("Execution Trace: \n%s", buf.data))); - pfree(buf.data); - destroy_stat(stat); - } + { + long seconds, + microseconds; + StringInfoData buf; + struct timeval proc_end; + + gettimeofday(&proc_end, NULL); + seconds = proc_end.tv_sec - proc_begin->tv_sec; + microseconds = proc_end.tv_usec - proc_begin->tv_usec; + + stat->total_duration = seconds * 1000 + microseconds / 1000; /* in ms unit */ + initStringInfo(&buf); + get_stat_trace(exec_codes, stat, &buf); + ereport(LOG, (errmsg("Execution Trace: \n%s", buf.data))); + pfree(buf.data); + destroy_stat(stat); + } } - -ExecStat *create_stat(size_t code_size, uint64_t trace_mode) + +ExecStat * +create_stat(size_t code_size, uint64_t trace_mode) { - static size_t init_val = 0; - ExecStat *stat; - - if (!trace_exec_enabled(trace_mode)) - return NULL; - - stat = palloc(sizeof(ExecStat)); - stat->counts = NULL; - stat->durations = NULL; - stat->total_duration = 0; - stat->code_size = code_size; - - if (trace_exec_counts_enabled(trace_mode)) - { - stat->counts = create_vector3(sizeof(size_t), code_size, &init_val); - } - if (trace_exec_time_enabled(trace_mode)) - { - stat->durations = create_vector3(sizeof(time_t), code_size, &init_val); - } - - return stat; + static size_t init_val = 0; + ExecStat *stat; + + if (!trace_exec_enabled(trace_mode)) + return NULL; + + stat = palloc(sizeof(ExecStat)); + stat->counts = NULL; + stat->durations = NULL; + stat->total_duration = 0; + stat->code_size = code_size; + + if (trace_exec_counts_enabled(trace_mode)) + { + stat->counts = create_vector3(sizeof(size_t), code_size, &init_val); + } + if (trace_exec_time_enabled(trace_mode)) + { + stat->durations = create_vector3(sizeof(time_t), code_size, &init_val); + } + + return stat; } -void destroy_stat(ExecStat *stat) +void +destroy_stat(ExecStat *stat) { - if (!stat) - return; - if (stat->counts) - destroy_vector(stat->counts); - if (stat->durations) - destroy_vector(stat->durations); - pfree(stat); + if (!stat) + return; + if (stat->counts) + destroy_vector(stat->counts); + if (stat->durations) + destroy_vector(stat->durations); + pfree(stat); } -static void desc_stmt_goto(PLtsql_stmt_goto *stmt, char *buf) +static void +desc_stmt_goto(PLtsql_stmt_goto *stmt, char *buf) { - if (stmt->cond) - snprintf(buf, TRACE_LOCAL_BUF_SIZE, "COND GOTO %d", stmt->target_pc); - else - snprintf(buf, TRACE_LOCAL_BUF_SIZE, "GOTO %d", stmt->target_pc); + if (stmt->cond) + snprintf(buf, TRACE_LOCAL_BUF_SIZE, "COND GOTO %d", stmt->target_pc); + else + snprintf(buf, TRACE_LOCAL_BUF_SIZE, "GOTO %d", stmt->target_pc); } -static void desc_stmt_save_ctx(PLtsql_stmt_save_ctx *stmt, char *buf) +static void +desc_stmt_save_ctx(PLtsql_stmt_save_ctx *stmt, char *buf) { - snprintf(buf, TRACE_LOCAL_BUF_SIZE, "SAVE CONTEXT, GOTO %d", stmt->target_pc); + snprintf(buf, TRACE_LOCAL_BUF_SIZE, "SAVE CONTEXT, GOTO %d", stmt->target_pc); } -static void get_code_desc(PLtsql_stmt *stmt, const char *namespace, const char * name, StringInfo buf) +static void +get_code_desc(PLtsql_stmt *stmt, const char *namespace, const char *name, StringInfo buf) { - char local_buf[TRACE_LOCAL_BUF_SIZE]; - char detail_buf[TRACE_LOCAL_BUF_SIZE]; - char line_detail_buf[TRACE_LOCAL_BUF_SIZE]; - - if (!namespace && !name) - snprintf(line_detail_buf, TRACE_LOCAL_BUF_SIZE, - "(DO STMT:%d)", stmt->lineno); - else - snprintf(line_detail_buf, TRACE_LOCAL_BUF_SIZE, - "(%s.%s:%d)", namespace, name, stmt->lineno); - - switch (stmt->cmd_type) - { - case PLTSQL_STMT_GOTO: - desc_stmt_goto((PLtsql_stmt_goto *) stmt, detail_buf); - snprintf(local_buf, TRACE_LOCAL_BUF_SIZE, "%s %s", - detail_buf, line_detail_buf); - break; - case PLTSQL_STMT_SAVE_CTX: - desc_stmt_save_ctx((PLtsql_stmt_save_ctx *) stmt, detail_buf); - snprintf(local_buf, TRACE_LOCAL_BUF_SIZE, "%s %s", - detail_buf, line_detail_buf); - break; - default: - snprintf(local_buf, TRACE_LOCAL_BUF_SIZE, "%s %s", - pltsql_stmt_typename(stmt), line_detail_buf); - break; - } - - appendStringInfoString(buf, local_buf); + char local_buf[TRACE_LOCAL_BUF_SIZE]; + char detail_buf[TRACE_LOCAL_BUF_SIZE]; + char line_detail_buf[TRACE_LOCAL_BUF_SIZE]; + + if (!namespace && !name) + snprintf(line_detail_buf, TRACE_LOCAL_BUF_SIZE, + "(DO STMT:%d)", stmt->lineno); + else + snprintf(line_detail_buf, TRACE_LOCAL_BUF_SIZE, + "(%s.%s:%d)", namespace, name, stmt->lineno); + + switch (stmt->cmd_type) + { + case PLTSQL_STMT_GOTO: + desc_stmt_goto((PLtsql_stmt_goto *) stmt, detail_buf); + snprintf(local_buf, TRACE_LOCAL_BUF_SIZE, "%s %s", + detail_buf, line_detail_buf); + break; + case PLTSQL_STMT_SAVE_CTX: + desc_stmt_save_ctx((PLtsql_stmt_save_ctx *) stmt, detail_buf); + snprintf(local_buf, TRACE_LOCAL_BUF_SIZE, "%s %s", + detail_buf, line_detail_buf); + break; + default: + snprintf(local_buf, TRACE_LOCAL_BUF_SIZE, "%s %s", + pltsql_stmt_typename(stmt), line_detail_buf); + break; + } + + appendStringInfoString(buf, local_buf); } -static void get_stat_desc(ExecStat *stat, size_t index, StringInfo buf) +static void +get_stat_desc(ExecStat *stat, size_t index, StringInfo buf) { - bool first = true; - char local_buf[TRACE_LOCAL_BUF_SIZE]; - - if (!stat->counts && !stat->durations) - return; - - appendStringInfoString(buf, "("); - - /* Count */ - if (stat->counts) - { - snprintf(local_buf, TRACE_LOCAL_BUF_SIZE, "C:%3zu", *(size_t *) vec_at(stat->counts, index)); - appendStringInfoString(buf, local_buf); - first = false; - } - - /* Duration */ - if (stat->durations) - { - if (!first) - appendStringInfoString(buf, ", "); - snprintf(local_buf, TRACE_LOCAL_BUF_SIZE, "T:%6zums", *(size_t *) vec_at(stat->durations, index)); - appendStringInfoString(buf, local_buf); - first = false; - } - appendStringInfoString(buf, ")"); + bool first = true; + char local_buf[TRACE_LOCAL_BUF_SIZE]; + + if (!stat->counts && !stat->durations) + return; + + appendStringInfoString(buf, "("); + + /* Count */ + if (stat->counts) + { + snprintf(local_buf, TRACE_LOCAL_BUF_SIZE, "C:%3zu", *(size_t *) vec_at(stat->counts, index)); + appendStringInfoString(buf, local_buf); + first = false; + } + + /* Duration */ + if (stat->durations) + { + if (!first) + appendStringInfoString(buf, ", "); + snprintf(local_buf, TRACE_LOCAL_BUF_SIZE, "T:%6zums", *(size_t *) vec_at(stat->durations, index)); + appendStringInfoString(buf, local_buf); + first = false; + } + appendStringInfoString(buf, ")"); } -static void get_stat_trace(ExecCodes *exec_code, ExecStat *stat, StringInfo buf) +static void +get_stat_trace(ExecCodes *exec_code, ExecStat *stat, StringInfo buf) { - size_t code_size = vec_size(exec_code->codes); - size_t i; - char local_buf[TRACE_LOCAL_BUF_SIZE]; - PLtsql_stmt *stmt; - - StringInfoData code_desc, stat_desc; - initStringInfo(&code_desc); - initStringInfo(&stat_desc); - - /* Header */ - snprintf(local_buf, TRACE_LOCAL_BUF_SIZE, - "Execution Summary: %s.%s total execution code size %zu, total execution time %zums\n", - exec_code->proc_namespace, exec_code->proc_name, - code_size, stat->total_duration); - appendStringInfoString(buf, local_buf); - - /* Body */ - for (i=0 ; i < code_size; i++) - { - stmt = *(PLtsql_stmt **) vec_at(exec_code->codes, i); - resetStringInfo(&code_desc); - resetStringInfo(&stat_desc); - get_code_desc(stmt, exec_code->proc_namespace, exec_code->proc_name, &code_desc); - get_stat_desc(stat, i, &stat_desc); - snprintf(local_buf, TRACE_LOCAL_BUF_SIZE, "[%3zu] %-69s %s\n", i, code_desc.data, stat_desc.data); - appendStringInfoString(buf, local_buf); - } - - pfree(code_desc.data); - pfree(stat_desc.data); + size_t code_size = vec_size(exec_code->codes); + size_t i; + char local_buf[TRACE_LOCAL_BUF_SIZE]; + PLtsql_stmt *stmt; + + StringInfoData code_desc, + stat_desc; + + initStringInfo(&code_desc); + initStringInfo(&stat_desc); + + /* Header */ + snprintf(local_buf, TRACE_LOCAL_BUF_SIZE, + "Execution Summary: %s.%s total execution code size %zu, total execution time %zums\n", + exec_code->proc_namespace, exec_code->proc_name, + code_size, stat->total_duration); + appendStringInfoString(buf, local_buf); + + /* Body */ + for (i = 0; i < code_size; i++) + { + stmt = *(PLtsql_stmt **) vec_at(exec_code->codes, i); + resetStringInfo(&code_desc); + resetStringInfo(&stat_desc); + get_code_desc(stmt, exec_code->proc_namespace, exec_code->proc_name, &code_desc); + get_stat_desc(stat, i, &stat_desc); + snprintf(local_buf, TRACE_LOCAL_BUF_SIZE, "[%3zu] %-69s %s\n", i, code_desc.data, stat_desc.data); + appendStringInfoString(buf, local_buf); + } + + pfree(code_desc.data); + pfree(stat_desc.data); } /*************************************************************************************** @@ -589,43 +622,47 @@ static void get_stat_trace(ExecCodes *exec_code, ExecStat *stat, StringInfo buf) static inline int dispatch_stmt(PLtsql_execstate *estate, PLtsql_stmt *stmt); static PLtsql_errctx *create_error_ctx(PLtsql_execstate *estate, int target_pc); -static inline int dispatch_stmt(PLtsql_execstate *estate, PLtsql_stmt *stmt) +static inline int +dispatch_stmt(PLtsql_execstate *estate, PLtsql_stmt *stmt) { - int rc = PLTSQL_RC_OK; /* only used to test return is called */ + int rc = PLTSQL_RC_OK; /* only used to test return is called */ - /* Store the Current Line Number of the current query, incase we stumble upon a runtime error. */ + /* + * Store the Current Line Number of the current query, incase we stumble + * upon a runtime error. + */ CurrentLineNumber = stmt->lineno; estate->err_stmt = stmt; /* reset number of tuple processed in previous command */ estate->eval_processed = 0; - switch(stmt->cmd_type) - { - case PLTSQL_STMT_ASSIGN: - exec_stmt_assign(estate, (PLtsql_stmt_assign *) stmt); - break; - case PLTSQL_STMT_RETURN: - rc = exec_stmt_return(estate, (PLtsql_stmt_return *)stmt); - break; - case PLTSQL_STMT_RETURN_QUERY: + switch (stmt->cmd_type) + { + case PLTSQL_STMT_ASSIGN: + exec_stmt_assign(estate, (PLtsql_stmt_assign *) stmt); + break; + case PLTSQL_STMT_RETURN: + rc = exec_stmt_return(estate, (PLtsql_stmt_return *) stmt); + break; + case PLTSQL_STMT_RETURN_QUERY: if (pltsql_explain_only) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Showing Estimated Execution Plan for RETURN QUERY statment is not yet supported"))); + errmsg("Showing Estimated Execution Plan for RETURN QUERY statment is not yet supported"))); } - exec_stmt_return_query(estate, (PLtsql_stmt_return_query *)stmt); - break; - case PLTSQL_STMT_EXECSQL: - exec_stmt_execsql(estate, (PLtsql_stmt_execsql *) stmt); - break; + exec_stmt_return_query(estate, (PLtsql_stmt_return_query *) stmt); + break; + case PLTSQL_STMT_EXECSQL: + exec_stmt_execsql(estate, (PLtsql_stmt_execsql *) stmt); + break; case PLTSQL_STMT_OPEN: if (pltsql_explain_only) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Showing Estimated Execution Plan for OPEN statment is not yet supported"))); + errmsg("Showing Estimated Execution Plan for OPEN statment is not yet supported"))); } exec_stmt_open(estate, (PLtsql_stmt_open *) stmt); break; @@ -634,7 +671,7 @@ static inline int dispatch_stmt(PLtsql_execstate *estate, PLtsql_stmt *stmt) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Showing Estimated Execution Plan for FETCH statment is not yet supported"))); + errmsg("Showing Estimated Execution Plan for FETCH statment is not yet supported"))); } exec_stmt_fetch(estate, (PLtsql_stmt_fetch *) stmt); break; @@ -643,7 +680,7 @@ static inline int dispatch_stmt(PLtsql_execstate *estate, PLtsql_stmt *stmt) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Showing Estimated Execution Plan for CLOSE statment is not yet supported"))); + errmsg("Showing Estimated Execution Plan for CLOSE statment is not yet supported"))); } exec_stmt_close(estate, (PLtsql_stmt_close *) stmt); break; @@ -652,7 +689,7 @@ static inline int dispatch_stmt(PLtsql_execstate *estate, PLtsql_stmt *stmt) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Showing Estimated Execution Plan for COMMIT statment is not yet supported"))); + errmsg("Showing Estimated Execution Plan for COMMIT statment is not yet supported"))); } exec_stmt_commit(estate, (PLtsql_stmt_commit *) stmt); break; @@ -661,38 +698,38 @@ static inline int dispatch_stmt(PLtsql_execstate *estate, PLtsql_stmt *stmt) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Showing Estimated Execution Plan for ROLLBACK statment is not yet supported"))); + errmsg("Showing Estimated Execution Plan for ROLLBACK statment is not yet supported"))); } exec_stmt_rollback(estate, (PLtsql_stmt_rollback *) stmt); break; - /* TSQL-only statement types follow */ - case PLTSQL_STMT_GOTO: - exec_stmt_goto(estate, (PLtsql_stmt_goto *) stmt); - break; + /* TSQL-only statement types follow */ + case PLTSQL_STMT_GOTO: + exec_stmt_goto(estate, (PLtsql_stmt_goto *) stmt); + break; case PLTSQL_STMT_SET_EXPLAIN_MODE: exec_stmt_set_explain_mode(estate, (PLtsql_stmt_set_explain_mode *) stmt); break; - case PLTSQL_STMT_PRINT: - exec_stmt_print(estate, (PLtsql_stmt_print *)stmt); - break; + case PLTSQL_STMT_PRINT: + exec_stmt_print(estate, (PLtsql_stmt_print *) stmt); + break; case PLTSQL_STMT_QUERY_SET: if (pltsql_explain_only) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Showing Estimated Execution Plan for QUERY SET statment is not yet supported"))); + errmsg("Showing Estimated Execution Plan for QUERY SET statment is not yet supported"))); } exec_stmt_query_set(estate, (PLtsql_stmt_query_set *) stmt); break; - case PLTSQL_STMT_PUSH_RESULT: + case PLTSQL_STMT_PUSH_RESULT: if (pltsql_explain_only) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Showing Estimated Execution Plan for PUSH RESULT statment is not yet supported"))); + errmsg("Showing Estimated Execution Plan for PUSH RESULT statment is not yet supported"))); } - exec_stmt_push_result(estate, (PLtsql_stmt_push_result *) stmt); - break; + exec_stmt_push_result(estate, (PLtsql_stmt_push_result *) stmt); + break; case PLTSQL_STMT_EXEC: exec_stmt_exec(estate, (PLtsql_stmt_exec *) stmt); break; @@ -701,7 +738,7 @@ static inline int dispatch_stmt(PLtsql_execstate *estate, PLtsql_stmt *stmt) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Showing Estimated Execution Plan for EXEC BATCH statment is not yet supported"))); + errmsg("Showing Estimated Execution Plan for EXEC BATCH statment is not yet supported"))); } exec_stmt_exec_batch(estate, (PLtsql_stmt_exec_batch *) stmt); break; @@ -710,7 +747,7 @@ static inline int dispatch_stmt(PLtsql_execstate *estate, PLtsql_stmt *stmt) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Showing Estimated Execution Plan for EXEC SP statment is not yet supported"))); + errmsg("Showing Estimated Execution Plan for EXEC SP statment is not yet supported"))); } exec_stmt_exec_sp(estate, (PLtsql_stmt_exec_sp *) stmt); break; @@ -722,28 +759,28 @@ static inline int dispatch_stmt(PLtsql_execstate *estate, PLtsql_stmt *stmt) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Showing Estimated Execution Plan for RETURN TABLE statment is not yet supported"))); + errmsg("Showing Estimated Execution Plan for RETURN TABLE statment is not yet supported"))); } exec_stmt_return_table(estate, (PLtsql_stmt_return_query *) stmt); break; - case PLTSQL_STMT_DEALLOCATE: + case PLTSQL_STMT_DEALLOCATE: if (pltsql_explain_only) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Showing Estimated Execution Plan for DEALLOCATE statment is not yet supported"))); + errmsg("Showing Estimated Execution Plan for DEALLOCATE statment is not yet supported"))); } - exec_stmt_deallocate(estate, (PLtsql_stmt_deallocate *) stmt); - break; - case PLTSQL_STMT_DECL_CURSOR: + exec_stmt_deallocate(estate, (PLtsql_stmt_deallocate *) stmt); + break; + case PLTSQL_STMT_DECL_CURSOR: if (pltsql_explain_only) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Showing Estimated Execution Plan for DECL CURSOR statment is not yet supported"))); + errmsg("Showing Estimated Execution Plan for DECL CURSOR statment is not yet supported"))); } - exec_stmt_decl_cursor(estate, (PLtsql_stmt_decl_cursor *) stmt); - break; + exec_stmt_decl_cursor(estate, (PLtsql_stmt_decl_cursor *) stmt); + break; case PLTSQL_STMT_RAISERROR: exec_stmt_raiserror(estate, (PLtsql_stmt_raiserror *) stmt); break; @@ -758,74 +795,76 @@ static inline int dispatch_stmt(PLtsql_execstate *estate, PLtsql_stmt *stmt) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Showing Estimated Execution Plan for GRANT DB statment is not yet supported"))); + errmsg("Showing Estimated Execution Plan for GRANT DB statment is not yet supported"))); } exec_stmt_grantdb(estate, (PLtsql_stmt_grantdb *) stmt); break; - case PLTSQL_STMT_INSERT_BULK: + case PLTSQL_STMT_INSERT_BULK: if (pltsql_explain_only) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Showing Estimated Execution Plan for INSERT BULK statment is not yet supported"))); + errmsg("Showing Estimated Execution Plan for INSERT BULK statment is not yet supported"))); } - exec_stmt_insert_bulk(estate, (PLtsql_stmt_insert_bulk *) stmt); - break; - /* TSQL-only executable node */ - case PLTSQL_STMT_RESTORE_CTX_FULL: + exec_stmt_insert_bulk(estate, (PLtsql_stmt_insert_bulk *) stmt); + break; + /* TSQL-only executable node */ + case PLTSQL_STMT_RESTORE_CTX_FULL: if (pltsql_explain_only) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Showing Estimated Execution Plan for RESTORE CTX FULL statment is not yet supported"))); + errmsg("Showing Estimated Execution Plan for RESTORE CTX FULL statment is not yet supported"))); } - exec_stmt_restore_ctx_full(estate, (PLtsql_stmt_restore_ctx_full *) stmt); - break; - case PLTSQL_STMT_RESTORE_CTX_PARTIAL: + exec_stmt_restore_ctx_full(estate, (PLtsql_stmt_restore_ctx_full *) stmt); + break; + case PLTSQL_STMT_RESTORE_CTX_PARTIAL: if (pltsql_explain_only) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Showing Estimated Execution Plan for RESTORE CTX PARTIAL statment is not yet supported"))); + errmsg("Showing Estimated Execution Plan for RESTORE CTX PARTIAL statment is not yet supported"))); } - exec_stmt_restore_ctx_partial(estate, (PLtsql_stmt_restore_ctx_partial *) stmt); - break; - default: - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Unsupported statement type %d in executor", stmt->cmd_type))); - } - - return rc; + exec_stmt_restore_ctx_partial(estate, (PLtsql_stmt_restore_ctx_partial *) stmt); + break; + default: + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Unsupported statement type %d in executor", stmt->cmd_type))); + } + + return rc; } -static PLtsql_errctx *create_error_ctx(PLtsql_execstate *estate, int target_pc) +static PLtsql_errctx * +create_error_ctx(PLtsql_execstate *estate, int target_pc) { - PLtsql_errctx *context = palloc(sizeof(PLtsql_errctx)); + PLtsql_errctx *context = palloc(sizeof(PLtsql_errctx)); + + context->save_exception_stack = PG_exception_stack; + context->save_context_stack = error_context_stack; + context->target_pc = target_pc; - context->save_exception_stack = PG_exception_stack; - context->save_context_stack = error_context_stack; - context->target_pc = target_pc; + context->oldcontext = CurrentMemoryContext; + context->oldowner = CurrentResourceOwner; + context->old_eval_econtext = estate->eval_econtext; - context->oldcontext = CurrentMemoryContext; - context->oldowner = CurrentResourceOwner; - context->old_eval_econtext = estate->eval_econtext; - context->save_cur_error = pltsql_clone_estate_err(estate->cur_error); - /* - * We will need a stmt_mcontext to hold the error data if an error - * occurs. It seems best to force it to exist before entering the - * subtransaction, so that we reduce the risk of out-of-memory during - * error recovery, and because this greatly simplifies restoring the - * stmt_mcontext stack to the correct state after an error. We can - * ameliorate the cost of this by allowing the called statements to - * use this mcontext too; so we don't push it down here. - */ - context->stmt_mcontext = get_stmt_mcontext(estate); + + /* + * We will need a stmt_mcontext to hold the error data if an error occurs. + * It seems best to force it to exist before entering the subtransaction, + * so that we reduce the risk of out-of-memory during error recovery, and + * because this greatly simplifies restoring the stmt_mcontext stack to + * the correct state after an error. We can ameliorate the cost of this + * by allowing the called statements to use this mcontext too; so we don't + * push it down here. + */ + context->stmt_mcontext = get_stmt_mcontext(estate); context->partial_restored = false; - return context; + return context; } /* @@ -835,7 +874,8 @@ static PLtsql_errctx *create_error_ctx(PLtsql_execstate *estate, int target_pc) * procedures/functions */ static -bool is_part_of_pltsql_trycatch_block(PLtsql_execstate *estate) +bool +is_part_of_pltsql_trycatch_block(PLtsql_execstate *estate) { PLExecStateCallStack *cur; @@ -850,6 +890,7 @@ bool is_part_of_pltsql_trycatch_block(PLtsql_execstate *estate) if (vec_size(cur->estate->err_ctx_stack) == 1) { PLtsql_errctx *err_ctx = *(PLtsql_errctx **) vec_at(cur->estate->err_ctx_stack, 0); + /* Make sure that we are not inside the catch block */ if (!err_ctx->partial_restored) return true; @@ -864,7 +905,8 @@ bool is_part_of_pltsql_trycatch_block(PLtsql_execstate *estate) * at current or any higher batch level */ static -bool is_part_of_pltsql_trigger(PLtsql_execstate *estate) +bool +is_part_of_pltsql_trigger(PLtsql_execstate *estate) { PLExecStateCallStack *cur; @@ -881,9 +923,10 @@ bool is_part_of_pltsql_trigger(PLtsql_execstate *estate) /* Control command like GOTO, RETURN */ static -bool is_control_command(PLtsql_stmt *stmt) +bool +is_control_command(PLtsql_stmt *stmt) { - switch(stmt->cmd_type) + switch (stmt->cmd_type) { case PLTSQL_STMT_GOTO: case PLTSQL_STMT_RETURN: @@ -896,7 +939,8 @@ bool is_control_command(PLtsql_stmt *stmt) } static -bool is_start_implicit_txn_command(PLtsql_stmt *stmt) +bool +is_start_implicit_txn_command(PLtsql_stmt *stmt) { switch (stmt->cmd_type) { @@ -908,30 +952,32 @@ bool is_start_implicit_txn_command(PLtsql_stmt *stmt) case PLTSQL_STMT_RETURN_QUERY: case PLTSQL_STMT_PUSH_RESULT: return true; - default : + default: return false; } } /* Batch commands like EXEC, SP_EXECUTESQL */ static -bool is_batch_command(PLtsql_stmt *stmt) +bool +is_batch_command(PLtsql_stmt *stmt) { - switch(stmt->cmd_type) - { + switch (stmt->cmd_type) + { case PLTSQL_STMT_EXEC: case PLTSQL_STMT_EXEC_BATCH: case PLTSQL_STMT_EXEC_SP: return true; case PLTSQL_STMT_EXECSQL: - return ((PLtsql_stmt_execsql *)stmt)->insert_exec; + return ((PLtsql_stmt_execsql *) stmt)->insert_exec; default: return false; } } static -void record_error_state(PLtsql_execstate *estate) +void +record_error_state(PLtsql_execstate *estate) { if (exec_state_call_stack->error_data.error_estate == NULL) { @@ -950,7 +996,8 @@ void record_error_state(PLtsql_execstate *estate) * like statement terminating errors */ static -bool is_error_raising_batch(PLtsql_execstate *estate) +bool +is_error_raising_batch(PLtsql_execstate *estate) { if (exec_state_call_stack->error_data.error_estate == estate) return true; @@ -958,7 +1005,8 @@ bool is_error_raising_batch(PLtsql_execstate *estate) } static -bool is_xact_abort_on_error(PLtsql_execstate *estate) +bool +is_xact_abort_on_error(PLtsql_execstate *estate) { if (exec_state_call_stack->error_data.xact_abort_on) return true; @@ -967,7 +1015,8 @@ bool is_xact_abort_on_error(PLtsql_execstate *estate) /* Cases where transaction is no longer committable */ static -bool abort_transaction(PLtsql_execstate *estate, ErrorData *edata, uint8_t override_flag) +bool +abort_transaction(PLtsql_execstate *estate, ErrorData *edata, uint8_t override_flag) { /* Batch aborting errors which also terminate the transaction */ if (is_batch_txn_aborting_error(edata->sqlerrcode, override_flag)) @@ -998,7 +1047,8 @@ bool abort_transaction(PLtsql_execstate *estate, ErrorData *edata, uint8_t overr /* If error only terminates current batch */ static -bool abort_only_current_batch(PLtsql_execstate *estate, ErrorData *edata, uint8_t override_flag) +bool +abort_only_current_batch(PLtsql_execstate *estate, ErrorData *edata, uint8_t override_flag) { if (is_current_batch_aborting_error(edata->sqlerrcode, override_flag) && is_error_raising_batch(estate)) @@ -1008,7 +1058,8 @@ bool abort_only_current_batch(PLtsql_execstate *estate, ErrorData *edata, uint8_ /* Cases where execution needs to terminate */ static -bool abort_execution(PLtsql_execstate *estate, ErrorData *edata, bool *terminate_batch, uint8_t override_flag) +bool +abort_execution(PLtsql_execstate *estate, ErrorData *edata, bool *terminate_batch, uint8_t override_flag) { /* Exclude ignorable errors */ if (!is_ignorable_error(edata->sqlerrcode, override_flag)) @@ -1044,15 +1095,16 @@ bool abort_execution(PLtsql_execstate *estate, ErrorData *edata, bool *terminate * like transactions, try/catch, xact_abort */ static -void handle_error(PLtsql_execstate *estate, - PLtsql_stmt *stmt, - ErrorData *edata, - SimpleEcontextStackEntry *volatile topEntry, - bool *terminate_batch, - bool ro_func) +void +handle_error(PLtsql_execstate *estate, + PLtsql_stmt *stmt, + ErrorData *edata, + SimpleEcontextStackEntry *volatile topEntry, + bool *terminate_batch, + bool ro_func) { /* Determine if we want to override the transactional behaviour. */ - uint8_t override_flag = override_txn_behaviour(stmt); + uint8_t override_flag = override_txn_behaviour(stmt); record_error_state(estate); /* Mark transaction for termination */ @@ -1088,31 +1140,31 @@ void handle_error(PLtsql_execstate *estate, * internal savepiont wrapper. */ static -int dispatch_stmt_handle_error(PLtsql_execstate *estate, - PLtsql_stmt *stmt, - bool *terminate_batch, - int active_non_tsql_procs, - int active_sys_functions) +int +dispatch_stmt_handle_error(PLtsql_execstate *estate, + PLtsql_stmt *stmt, + bool *terminate_batch, + int active_non_tsql_procs, + int active_sys_functions) { - int rc = PLTSQL_RC_OK; + int rc = PLTSQL_RC_OK; volatile bool internal_sp_started; volatile int before_lxid = MyProc->lxid; volatile int before_subtxn_id; MemoryContext cur_ctxt = CurrentMemoryContext; ResourceOwner oldowner = CurrentResourceOwner; SimpleEcontextStackEntry *volatile topEntry = simple_econtext_stack; - bool support_tsql_trans = pltsql_support_tsql_transactions(); - uint32 before_tran_count = NestedTranCount; - bool ro_func = (estate->func->fn_prokind == PROKIND_FUNCTION) && - (estate->func->fn_is_trigger == PLTSQL_NOT_TRIGGER) && - (strcmp(estate->func->fn_signature, "inline_code_block") != 0); + bool support_tsql_trans = pltsql_support_tsql_transactions(); + uint32 before_tran_count = NestedTranCount; + bool ro_func = (estate->func->fn_prokind == PROKIND_FUNCTION) && + (estate->func->fn_is_trigger == PLTSQL_NOT_TRIGGER) && + (strcmp(estate->func->fn_signature, "inline_code_block") != 0); PG_TRY(); { /* - * If no transaction is running, start implicit transaction - * for qualified commands when implicit_transactions config - * option is on + * If no transaction is running, start implicit transaction for + * qualified commands when implicit_transactions config option is on */ if (support_tsql_trans && pltsql_implicit_transactions && @@ -1129,13 +1181,12 @@ int dispatch_stmt_handle_error(PLtsql_execstate *estate, estate->tsql_trigger_flags = 0; /* - * Start an internal savepoint if transaction block - * is active to handle undo of failed command - * We do not start savepoint for batch commands as - * error handling must be taken care of at statement - * level. - * For statements inside an RO functions we do not start - * savepoints and let the caller be responsible for handling the error. + * Start an internal savepoint if transaction block is active to + * handle undo of failed command We do not start savepoint for batch + * commands as error handling must be taken care of at statement + * level. For statements inside an RO functions we do not start + * savepoints and let the caller be responsible for handling the + * error. */ if (!ro_func && !pltsql_disable_internal_savepoint && !is_batch_command(stmt) && IsTransactionBlockActive()) { @@ -1167,7 +1218,10 @@ int dispatch_stmt_handle_error(PLtsql_execstate *estate, estate->impl_txn_type = PLTSQL_IMPL_TRAN_OFF; - /* Handle transaction count mismatch for batch execution if implicit_transaction config is off*/ + /* + * Handle transaction count mismatch for batch execution if + * implicit_transaction config is off + */ topEntry = simple_econtext_stack; if (!pltsql_implicit_transactions && is_batch_command(stmt) && @@ -1179,9 +1233,10 @@ int dispatch_stmt_handle_error(PLtsql_execstate *estate, } PG_CATCH(); { - ErrorData *edata; - int last_error; - bool error_mapped; + ErrorData *edata; + int last_error; + bool error_mapped; + support_tsql_trans = pltsql_support_tsql_transactions(); /* Close trigger nesting in engine */ @@ -1252,8 +1307,8 @@ int dispatch_stmt_handle_error(PLtsql_execstate *estate, else if (!IsTransactionBlockActive()) { /* - * In case of no transaction, rollback the whole transaction - * to match auto commit behavior + * In case of no transaction, rollback the whole transaction to + * match auto commit behavior */ elog(DEBUG1, "TSQL TXN TSQL semantics : Rollback current transaction"); @@ -1266,8 +1321,8 @@ int dispatch_stmt_handle_error(PLtsql_execstate *estate, else if (estate->tsql_trigger_flags & TSQL_TRAN_STARTED) { /* - * Trigger must run inside an explicit transaction - * In case of error, rollback the transaction + * Trigger must run inside an explicit transaction In case of + * error, rollback the transaction */ elog(DEBUG1, "TSQL TXN TSQL semantics : Rollback internal transaction"); HoldPinnedPortals(); @@ -1278,15 +1333,15 @@ int dispatch_stmt_handle_error(PLtsql_execstate *estate, /* - * If we started an implicit transaction in the iterative executor - * but we encounter an error before we prepare the plan, we rollback - * the transaction to align with the default autocommit behaviour + * If we started an implicit transaction in the iterative executor but + * we encounter an error before we prepare the plan, we rollback the + * transaction to align with the default autocommit behaviour * * TODO: Test this * */ if (pltsql_implicit_transactions && - IsTransactionBlockActive() && (estate->impl_txn_type == PLTSQL_IMPL_TRAN_START)) + IsTransactionBlockActive() && (estate->impl_txn_type == PLTSQL_IMPL_TRAN_START)) { elog(DEBUG1, "TSQL TXN TSQL semantics : Rollback implicit transaction"); pltsql_rollback_txn(); @@ -1303,53 +1358,61 @@ int dispatch_stmt_handle_error(PLtsql_execstate *estate, return rc; } -bool is_recursive_trigger(PLtsql_execstate *estate){ +bool +is_recursive_trigger(PLtsql_execstate *estate) +{ if (estate == NULL) return false; - return is_part_of_pltsql_trigger(estate); + return is_part_of_pltsql_trigger(estate); } #define INITIAL_ERR_STACK_SIZE 8 -int exec_stmt_iterative(PLtsql_execstate *estate, ExecCodes *exec_codes, ExecConfig_t *config) +int +exec_stmt_iterative(PLtsql_execstate *estate, ExecCodes *exec_codes, ExecConfig_t *config) { - size_t *pc = &(estate->pc); - size_t size; - int rc = PLTSQL_RC_OK; - ExecStat *stat = NULL; - struct timeval proc_begin, stmt_begin; + size_t *pc = &(estate->pc); + size_t size; + int rc = PLTSQL_RC_OK; + ExecStat *stat = NULL; + struct timeval proc_begin, + stmt_begin; PLtsql_stmt *stmt = NULL; bool terminate_batch = false; int active_non_tsql_procs = pltsql_non_tsql_proc_entry_count; - int active_sys_functions = pltsql_sys_func_entry_count ; + int active_sys_functions = pltsql_sys_func_entry_count; - if (!exec_codes) - ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("Empty execution code"))); + if (!exec_codes) + ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("Empty execution code"))); - size = vec_size(exec_codes->codes); - initialize_trace(config->trace_mode, &stat, &proc_begin, size); + size = vec_size(exec_codes->codes); + initialize_trace(config->trace_mode, &stat, &proc_begin, size); /* Guard against stack overflow due to complex, recursive statements */ check_stack_depth(); - /* execution starts from here */ + /* execution starts from here */ - /* initialize error context and stacks */ - estate->err_ctx_stack = create_vector2(sizeof(PLtsql_errctx* ), INITIAL_ERR_STACK_SIZE); + /* initialize error context and stacks */ + estate->err_ctx_stack = create_vector2(sizeof(PLtsql_errctx *), INITIAL_ERR_STACK_SIZE); PG_TRY(); - { + { - for ( *pc = 0 ; *pc < size; (*pc)++ ) + for (*pc = 0; *pc < size; (*pc)++) { - int cur_pc = *pc; + int cur_pc = *pc; + stmt = *(PLtsql_stmt **) vec_at(exec_codes->codes, cur_pc); pre_exec_measure(config->trace_mode, stat, &stmt_begin, cur_pc); reset_exec_error_data(estate); - /* Let the protocol plugin know that we are about to execute this statement */ + /* + * Let the protocol plugin know that we are about to execute this + * statement + */ if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->stmt_beg) ((*pltsql_protocol_plugin_ptr)->stmt_beg) (estate, stmt); @@ -1358,11 +1421,13 @@ int exec_stmt_iterative(PLtsql_execstate *estate, ExecCodes *exec_codes, ExecCon if (stmt->cmd_type == PLTSQL_STMT_SAVE_CTX) { /* - * This stmt is handled by executor's main loop, - * because sigsetjmp MUST be called in uppper stack without a function return + * This stmt is handled by executor's main loop, because + * sigsetjmp MUST be called in uppper stack without a function + * return */ PLtsql_stmt_save_ctx *save_err = (PLtsql_stmt_save_ctx *) stmt; PLtsql_errctx *cur_err_ctx = create_error_ctx(estate, save_err->target_pc); + estate->err_text = gettext_noop("during statement block entry"); /* Want to run statements inside function's memory context */ @@ -1380,22 +1445,22 @@ int exec_stmt_iterative(PLtsql_execstate *estate, ExecCodes *exec_codes, ExecCon } else { - int err_handler_pc; - int i; + int err_handler_pc; + int i; PLtsql_errctx *cur_err_ctx = *(PLtsql_errctx **) vec_at(estate->err_ctx_stack, estate->cur_err_ctx_idx); /* restore error context */ err_handler_pc = cur_err_ctx->target_pc; - /* Cleanup dangling errors */ - for (i = (int) vec_size(estate->err_ctx_stack) - 1 ; i > (int) estate->cur_err_ctx_idx; i--) + /* Cleanup dangling errors */ + for (i = (int) vec_size(estate->err_ctx_stack) - 1; i > (int) estate->cur_err_ctx_idx; i--) restore_ctx_partial2(estate); - /* - * partial1 is called here to avoid adding a new node to the exec code - * Also set up cur_error so the error data is accessible - * inside the CATCH block. + /* + * partial1 is called here to avoid adding a new node to + * the exec code Also set up cur_error so the error data + * is accessible inside the CATCH block. */ estate->cur_error->error = restore_ctx_partial1(estate); estate->cur_error->procedure = exec_state_call_stack->error_data.error_procedure; @@ -1404,16 +1469,18 @@ int exec_stmt_iterative(PLtsql_execstate *estate, ExecCodes *exec_codes, ExecCon estate->cur_error->state = exec_state_call_stack->error_data.error_state; /* Goto error handling blocks */ - *pc = err_handler_pc - 1; /* same as how goto handles PC */ + *pc = err_handler_pc - 1; /* same as how goto handles PC */ /* find new active index */ - for (i = (int) (estate->cur_err_ctx_idx) -1 ; i >= 0; i--) + for (i = (int) (estate->cur_err_ctx_idx) - 1; i >= 0; i--) { PLtsql_errctx *err_ctx = *(PLtsql_errctx **) vec_at(estate->err_ctx_stack, i); + if (!err_ctx->partial_restored) { estate->cur_err_ctx_idx = i; - break; /* cur_err_ctx_idx is pointing to this error context */ + break; /* cur_err_ctx_idx is pointing to this + * error context */ } } if (last_error_mapping_failed || terminate_batch) @@ -1433,9 +1500,10 @@ int exec_stmt_iterative(PLtsql_execstate *estate, ExecCodes *exec_codes, ExecCon /* Restore context cannot run inside TRY/CATCH block */ dispatch_stmt(estate, stmt); } - else /* normal execution */ + else /* normal execution */ { - int cur_rc; + int cur_rc; + cur_rc = dispatch_stmt_handle_error(estate, stmt, &terminate_batch, active_non_tsql_procs, active_sys_functions); if (cur_rc == PLTSQL_RC_RETURN) rc = cur_rc; @@ -1445,23 +1513,23 @@ int exec_stmt_iterative(PLtsql_execstate *estate, ExecCodes *exec_codes, ExecCon post_exec_measure(config->trace_mode, stat, &stmt_begin, cur_pc); /* - * We do not want to reset error code when - * executing control commands like RETURN, - * GOTO, CTX RESTORE etc. Batch commands will - * also not reset the error code for underlying - * statements. - * We check error_state to make sure that we do - * not reset error right after setting it. - * Also, we'll skip the reset if the SETERROR - * option is specified in RAISERROR stmt. + * We do not want to reset error code when executing control + * commands like RETURN, GOTO, CTX RESTORE etc. Batch commands + * will also not reset the error code for underlying statements. + * We check error_state to make sure that we do not reset error + * right after setting it. Also, we'll skip the reset if the + * SETERROR option is specified in RAISERROR stmt. */ - if (!is_seterror_on(stmt) && + if (!is_seterror_on(stmt) && !is_control_command(stmt) && !is_batch_command(stmt) && exec_state_call_stack->error_data.error_estate == NULL) - exec_set_error(estate, 0, 0, false /* error_mapping_failed */); + exec_set_error(estate, 0, 0, false /* error_mapping_failed */ ); - /* Let the protocol plugin know that we have finished executing this statement */ + /* + * Let the protocol plugin know that we have finished executing + * this statement + */ if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->stmt_end) ((*pltsql_protocol_plugin_ptr)->stmt_end) (estate, stmt); @@ -1472,14 +1540,12 @@ int exec_stmt_iterative(PLtsql_execstate *estate, ExecCodes *exec_codes, ExecCon PG_CATCH(); { /* - * Let the protocol plugin know that there is an exception while executing - * this statement. - * N.B. We can reach here for three error cases: - * 1. error that should terminate the entire batch - * 2. error that cannot be ignored inside the current exec_stmt_execsql - * 3. non-trivial server errors - * 4. there is a try-catch in the path - * It seems in all of the cases apart from 4, we terminate the entire + * Let the protocol plugin know that there is an exception while + * executing this statement. N.B. We can reach here for three error + * cases: 1. error that should terminate the entire batch 2. error + * that cannot be ignored inside the current exec_stmt_execsql 3. + * non-trivial server errors 4. there is a try-catch in the path It + * seems in all of the cases apart from 4, we terminate the entire * batch of execution. So, let the protocol layer know that we're * terminating this batch and it should not send any done token from * this level. @@ -1487,7 +1553,7 @@ int exec_stmt_iterative(PLtsql_execstate *estate, ExecCodes *exec_codes, ExecCon if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->stmt_exception) ((*pltsql_protocol_plugin_ptr)->stmt_exception) (estate, stmt, (terminate_batch || - !is_part_of_pltsql_trycatch_block(estate))); + !is_part_of_pltsql_trycatch_block(estate))); destroy_vector(estate->err_ctx_stack); /* execution ends here */ @@ -1509,17 +1575,18 @@ int exec_stmt_iterative(PLtsql_execstate *estate, ExecCodes *exec_codes, ExecCon * Execution Code Cleanup **************************************************************************************/ -void free_exec_codes(ExecCodes *exec_codes) +void +free_exec_codes(ExecCodes *exec_codes) { - if (!exec_codes) - return; - - destroy_vector(exec_codes->codes); - if (exec_codes->proc_namespace) - pfree(exec_codes->proc_namespace); - if (exec_codes->proc_name) - pfree(exec_codes->proc_name); - pfree(exec_codes); + if (!exec_codes) + return; + + destroy_vector(exec_codes->codes); + if (exec_codes->proc_namespace) + pfree(exec_codes->proc_namespace); + if (exec_codes->proc_name) + pfree(exec_codes->proc_name); + pfree(exec_codes); } /*************************************************************************************** @@ -1527,14 +1594,15 @@ void free_exec_codes(ExecCodes *exec_codes) **************************************************************************************/ static -void process_explain(PLtsql_execstate *estate) +void +process_explain(PLtsql_execstate *estate) { ExplainInfo *einfo; - TupleDesc tupdesc; + TupleDesc tupdesc; DestReceiver *receiver; - Portal portal; + Portal portal; TupOutputState *tstate; - ListCell *lc; + ListCell *lc; StringInfoData planstr; if (!estate || !estate->explain_infos || estate->explain_infos->length == 0) @@ -1546,13 +1614,17 @@ void process_explain(PLtsql_execstate *estate) if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->stmt_beg) ((*pltsql_protocol_plugin_ptr)->stmt_beg) (estate, NULL); - /* If use_db changed db during the query, return it back to the starting database */ + /* + * If use_db changed db during the query, return it back to the starting + * database + */ if (estate->explain_infos) { einfo = (ExplainInfo *) llast(estate->explain_infos); if (einfo->initial_database) { PLtsql_stmt_usedb *initial_db = palloc0(sizeof(PLtsql_stmt_usedb)); + initial_db->db_name = (char *) einfo->initial_database; exec_stmt_usedb_explain(estate, initial_db, true); } @@ -1587,15 +1659,16 @@ void process_explain(PLtsql_execstate *estate) /* We need to manually send DONE token because the current stmt is NULL */ if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->send_done) ((*pltsql_protocol_plugin_ptr)->send_done) ( - 0xFD /*TDS_TOKEN_DONE*/, - 0x00 /*TDS_DONE_FINAL*/, - 0xF7 /*TDS_CMD_INFO*/, - 0 /*nprocessed*/ - ); + 0xFD /* TDS_TOKEN_DONE */ , + 0x00 /* TDS_DONE_FINAL */ , + 0xF7 /* TDS_CMD_INFO */ , + 0 /* nprocessed */ + ); } static -void process_explain_analyze(PLtsql_execstate *estate) +void +process_explain_analyze(PLtsql_execstate *estate) { if (!estate || !estate->explain_infos || estate->explain_infos->length == 0) return; @@ -1605,17 +1678,20 @@ void process_explain_analyze(PLtsql_execstate *estate) /* Send query plans to a client */ PG_TRY(); { - Oid restype; - TupleDesc tupdesc; + Oid restype; + TupleDesc tupdesc; DestReceiver *receiver; - Portal portal; + Portal portal; TupOutputState *tstate; ExplainInfo *einfo; - ListCell *lc; + ListCell *lc; foreach(lc, estate->explain_infos) { - /* Let the protocol plugin know that we are about to start execution */ + /* + * Let the protocol plugin know that we are about to start + * execution + */ if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->stmt_beg) ((*pltsql_protocol_plugin_ptr)->stmt_beg) (estate, NULL); @@ -1646,29 +1722,34 @@ void process_explain_analyze(PLtsql_execstate *estate) if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->stmt_end) ((*pltsql_protocol_plugin_ptr)->stmt_end) (estate, NULL); - /* We need to manually send DONE token because there is no associated stmt */ + /* + * We need to manually send DONE token because there is no + * associated stmt + */ if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->send_done) ((*pltsql_protocol_plugin_ptr)->send_done) ( - 0xFD /*TDS_TOKEN_DONE*/, - 0x00 /*TDS_DONE_FINAL*/, - 0xF7 /*TDS_CMD_INFO*/, - 0 /*nprocessed*/ - ); + 0xFD /* TDS_TOKEN_DONE */ , + 0x00 /* TDS_DONE_FINAL */ , + 0xF7 /* TDS_CMD_INFO */ , + 0 /* nprocessed */ + ); } } PG_FINALLY(); { - /* Because this function is called at the end of each top level statement, - * we need to clear it so that the next top level statements - * can use it for their query plans. + /* + * Because this function is called at the end of each top level + * statement, we need to clear it so that the next top level + * statements can use it for their query plans. */ estate->explain_infos = NIL; } PG_END_TRY(); } -static -void set_exec_error_data(char *procedure, int number, int severity, int state, bool rethrow) +static +void +set_exec_error_data(char *procedure, int number, int severity, int state, bool rethrow) { exec_state_call_stack->error_data.rethrow_error = rethrow; exec_state_call_stack->error_data.error_procedure = procedure; @@ -1678,7 +1759,8 @@ void set_exec_error_data(char *procedure, int number, int severity, int state, b } static -void reset_exec_error_data(PLtsql_execstate *estate) +void +reset_exec_error_data(PLtsql_execstate *estate) { exec_state_call_stack->error_data.xact_abort_on = false; exec_state_call_stack->error_data.rethrow_error = false; @@ -1692,7 +1774,8 @@ void reset_exec_error_data(PLtsql_execstate *estate) } static -void assert_equal_estate_err(PLtsql_estate_err *err1, PLtsql_estate_err *err2) +void +assert_equal_estate_err(PLtsql_estate_err *err1, PLtsql_estate_err *err2) { Assert(err1->error == err2->error && err1->procedure == err2->procedure && @@ -1701,12 +1784,13 @@ void assert_equal_estate_err(PLtsql_estate_err *err1, PLtsql_estate_err *err2) err1->state == err2->state); } static -int read_raiserror_params_explain(List *params, int paramno) +int +read_raiserror_params_explain(List *params, int paramno) { PLtsql_expr *expr_temp; StringInfoData query_string; - const char * param_text; - + const char *param_text; + if (!pltsql_explain_only) return PLTSQL_RC_OK; @@ -1719,26 +1803,27 @@ int read_raiserror_params_explain(List *params, int paramno) appendStringInfoString(&query_string, param_text); /* no comma on final item */ - if (i < paramno-1) + if (i < paramno - 1) appendStringInfo(&query_string, ","); } appendStringInfo(&query_string, ")"); append_explain_info(NULL, query_string.data); return PLTSQL_RC_OK; } -static void read_raiserror_params(PLtsql_execstate *estate, List *params, int paramno, - char **msg, int *msg_id, int *severity, int *state) +static void +read_raiserror_params(PLtsql_execstate *estate, List *params, int paramno, + char **msg, int *msg_id, int *severity, int *state) { - PLtsql_expr *expr; - Datum val; - bool isnull = true; - Oid restype; - int32 restypmod; + PLtsql_expr *expr; + Datum val; + bool isnull = true; + Oid restype; + int32 restypmod; - Datum *args; - Oid *argtypes; - bool *argisnull; - StringInfoData buf; + Datum *args; + Oid *argtypes; + bool *argisnull; + StringInfoData buf; Assert(paramno <= 23); @@ -1747,17 +1832,17 @@ static void read_raiserror_params(PLtsql_execstate *estate, List *params, int pa val = exec_eval_expr(estate, expr, &isnull, &restype, &restypmod); if (isnull) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("msg_id/msg_str argument of RAISERROR is null"))); + errmsg("msg_id/msg_str argument of RAISERROR is null"))); /* Check if the input type is convertible to INT */ if (TypeCategory(restype) == TYPCATEGORY_NUMERIC) { - *msg_id = DatumGetInt32(exec_cast_value(estate, val, &isnull, - restype, restypmod, + *msg_id = DatumGetInt32(exec_cast_value(estate, val, &isnull, + restype, restypmod, INT4OID, -1)); if (*msg_id < 50000) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("msg_id argument of RAISERROR should be no less than 50000"))); + errmsg("msg_id argument of RAISERROR should be no less than 50000"))); *msg = psprintf("No. %d in sys.messages", *msg_id); } /* If not convertible to INT, try convert to string */ @@ -1772,14 +1857,14 @@ static void read_raiserror_params(PLtsql_execstate *estate, List *params, int pa *severity = exec_eval_int(estate, expr, &isnull); if (isnull) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("severity argument of RAISERROR is null"))); + errmsg("severity argument of RAISERROR is null"))); /* state */ expr = (PLtsql_expr *) list_nth(params, 2); *state = exec_eval_int(estate, expr, &isnull); if (isnull) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("state argument of RAISERROR is null"))); + errmsg("state argument of RAISERROR is null"))); /* substitution arguments */ args = (Datum *) palloc(sizeof(Datum) * (paramno - 3)); @@ -1794,15 +1879,16 @@ static void read_raiserror_params(PLtsql_execstate *estate, List *params, int pa argtypes[i] = restype; argisnull[i] = isnull; } - + initStringInfo(&buf); prepare_format_string(&buf, *msg, paramno - 3, args, argtypes, argisnull); *msg = buf.data; } -static int read_throw_params_explain(List *params) +static int +read_throw_params_explain(List *params) { - PLtsql_expr *expr_temp; + PLtsql_expr *expr_temp; StringInfoData query_text; const char *param_text; @@ -1824,30 +1910,31 @@ static int read_throw_params_explain(List *params) return PLTSQL_RC_OK; } -static void read_throw_params(PLtsql_execstate *estate, List *params, - char **msg, int *err_no, int *state) +static void +read_throw_params(PLtsql_execstate *estate, List *params, + char **msg, int *err_no, int *state) { PLtsql_expr *expr; - Datum val; - bool isnull = true; - Oid restype; - int32 restypmod; + Datum val; + bool isnull = true; + Oid restype; + int32 restypmod; /* error number */ expr = (PLtsql_expr *) list_nth(params, 0); *err_no = exec_eval_int(estate, expr, &isnull); if (isnull) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("err_no argument of THROW is null"))); + errmsg("err_no argument of THROW is null"))); if (*err_no < 50000) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("err_no argument of THROW should be no less than 50000"))); - + errmsg("err_no argument of THROW should be no less than 50000"))); + expr = (PLtsql_expr *) list_nth(params, 1); val = exec_eval_expr(estate, expr, &isnull, &restype, &restypmod); if (isnull) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("message argument of THROW is null"))); + errmsg("message argument of THROW is null"))); *msg = convert_value_to_string(estate, val, restype); /* state */ @@ -1855,19 +1942,22 @@ static void read_throw_params(PLtsql_execstate *estate, List *params, *state = exec_eval_int(estate, expr, &isnull); if (isnull) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("state argument of THROW is null"))); + errmsg("state argument of THROW is null"))); } -static char *get_proc_name(PLtsql_execstate *estate) +static char * +get_proc_name(PLtsql_execstate *estate) { - char *result = NULL; + char *result = NULL; + if (estate && estate->func && estate->func->exec_codes && estate->func->exec_codes->proc_name) result = pstrdup(estate->func->exec_codes->proc_name); return result; } -static bool is_seterror_on(PLtsql_stmt *stmt) +static bool +is_seterror_on(PLtsql_stmt *stmt) { if (stmt->cmd_type != PLTSQL_STMT_RAISERROR) return false; diff --git a/contrib/babelfishpg_tsql/src/iterative_exec.h b/contrib/babelfishpg_tsql/src/iterative_exec.h index f6d14d69ac..bf70efb81e 100644 --- a/contrib/babelfishpg_tsql/src/iterative_exec.h +++ b/contrib/babelfishpg_tsql/src/iterative_exec.h @@ -13,25 +13,26 @@ typedef struct ExecCodes { - DynaVec *codes; + DynaVec *codes; - char * proc_namespace; - char * proc_name; + char *proc_namespace; + char *proc_name; } ExecCodes; #define TRACE_EXEC_CODES 0x0001 -#define TRACE_EXEC_COUNTS 0x0003 /* Must combine trace codes with hit counts */ -#define TRACE_EXEC_TIME 0x0005 /* Must combine trace codes with exec time */ +#define TRACE_EXEC_COUNTS 0x0003 /* Must combine trace codes with hit + * counts */ +#define TRACE_EXEC_TIME 0x0005 /* Must combine trace codes with exec time */ typedef struct ExecConfig { - uint64_t trace_mode; + uint64_t trace_mode; } ExecConfig_t; -extern int exec_stmt_iterative(PLtsql_execstate *estate, ExecCodes *exec_codes, - ExecConfig_t *config); +extern int exec_stmt_iterative(PLtsql_execstate *estate, ExecCodes *exec_codes, + ExecConfig_t *config); extern void free_exec_codes(ExecCodes *exec_codes); extern bool is_recursive_trigger(PLtsql_execstate *estate); -#endif /* EXECUTOR_H */ +#endif /* EXECUTOR_H */ diff --git a/contrib/babelfishpg_tsql/src/json_funcs.c b/contrib/babelfishpg_tsql/src/json_funcs.c index d02f38a2c8..ffabf0fe86 100644 --- a/contrib/babelfishpg_tsql/src/json_funcs.c +++ b/contrib/babelfishpg_tsql/src/json_funcs.c @@ -19,8 +19,8 @@ #include "utils/varlena.h" #include "catalog/pg_collation_d.h" -Datum tsql_jsonb_in(text *json_text); -Datum tsql_jsonb_path_query_first(Datum jsonb_datum, Datum jsonpath_datum); +Datum tsql_jsonb_in(text *json_text); +Datum tsql_jsonb_path_query_first(Datum jsonb_datum, Datum jsonpath_datum); JsonParseErrorType tsql_parse_json(text *json_text, JsonLexContext *lex, JsonSemAction *sem); static Datum tsql_openjson_with_internal(PG_FUNCTION_ARGS); @@ -31,22 +31,22 @@ PG_FUNCTION_INFO_V1(tsql_json_query); /* * tsql_isjson() * - * Returns 1 if the string contains valid JSON; otherwise, returns 0. - * + * Returns 1 if the string contains valid JSON; otherwise, returns 0. + * * Returns null if expression is null and does not return errors. */ Datum tsql_isjson(PG_FUNCTION_ARGS) { - JsonParseErrorType result; - JsonLexContext *lex; - text *json_text = PG_GETARG_TEXT_PP(0); + JsonParseErrorType result; + JsonLexContext *lex; + text *json_text = PG_GETARG_TEXT_PP(0); - /* set up lex context and parse json expression */ - lex = makeJsonLexContext(json_text, false); - result = tsql_parse_json(json_text, lex, &nullSemAction); + /* set up lex context and parse json expression */ + lex = makeJsonLexContext(json_text, false); + result = tsql_parse_json(json_text, lex, &nullSemAction); - PG_RETURN_INT32((result == JSON_SUCCESS) ? 1 : 0); + PG_RETURN_INT32((result == JSON_SUCCESS) ? 1 : 0); } /* @@ -57,21 +57,21 @@ tsql_isjson(PG_FUNCTION_ARGS) */ JsonParseErrorType tsql_parse_json(text *json_text, JsonLexContext *lex, JsonSemAction *sem) -{ - JsonParseErrorType result_first_token; - JsonLexContext *lex_first_token; - JsonTokenType tok; +{ + JsonParseErrorType result_first_token; + JsonLexContext *lex_first_token; + JsonTokenType tok; - /* Short circuit when first token is scalar */ - lex_first_token = makeJsonLexContext(json_text, false); + /* Short circuit when first token is scalar */ + lex_first_token = makeJsonLexContext(json_text, false); result_first_token = json_lex(lex_first_token); tok = lex_first_token->token_type; - if (result_first_token != JSON_SUCCESS || - (tok != JSON_TOKEN_OBJECT_START && tok != JSON_TOKEN_ARRAY_START)) - return JSON_EXPECTED_JSON; - - /* validate rest of json expression */ - return pg_parse_json(lex, sem); + if (result_first_token != JSON_SUCCESS || + (tok != JSON_TOKEN_OBJECT_START && tok != JSON_TOKEN_ARRAY_START)) + return JSON_EXPECTED_JSON; + + /* validate rest of json expression */ + return pg_parse_json(lex, sem); } /* @@ -85,17 +85,17 @@ Datum tsql_jsonb_in(text *json_text) { JsonParseErrorType result_first_token; - JsonLexContext *lex_first_token; - JsonTokenType tok; + JsonLexContext *lex_first_token; + JsonTokenType tok; - /* Short circuit when first token is scalar */ - lex_first_token = makeJsonLexContext(json_text, false); + /* Short circuit when first token is scalar */ + lex_first_token = makeJsonLexContext(json_text, false); result_first_token = json_lex(lex_first_token); tok = lex_first_token->token_type; - if (result_first_token != JSON_SUCCESS || + if (result_first_token != JSON_SUCCESS || (tok != JSON_TOKEN_OBJECT_START && tok != JSON_TOKEN_ARRAY_START)) json_ereport_error(result_first_token, lex_first_token); - + /* convert json expression to jsonb */ return DirectFunctionCall1(jsonb_in, CStringGetDatum(text_to_cstring(json_text))); } @@ -104,24 +104,24 @@ tsql_jsonb_in(text *json_text) * tsql_json_value() * * Extracts a scalar value from a json expression string - * + * * 'json_text' - target document for jsonpath evaluation * 'jsonpath_text' - jsonpath to be executed */ Datum tsql_json_value(PG_FUNCTION_ARGS) { - - text *json_text, - *jsonpath_text; - char *result_cstring; - Datum result, - jsonb, - jsonpath; - Jsonb *result_jsonb; - VarChar *result_varchar; - bool islax; - int prev_sql_dialect; + + text *json_text, + *jsonpath_text; + char *result_cstring; + Datum result , + jsonb, + jsonpath; + Jsonb *result_jsonb; + VarChar *result_varchar; + bool islax; + int prev_sql_dialect; if (PG_ARGISNULL(0)) PG_RETURN_NULL(); @@ -133,8 +133,11 @@ tsql_json_value(PG_FUNCTION_ARGS) jsonb = tsql_jsonb_in(json_text); jsonpath_text = PG_GETARG_TEXT_PP(1); jsonpath = DirectFunctionCall1(jsonpath_in, CStringGetDatum(text_to_cstring(jsonpath_text))); - - /* set sql_dialect to tsql, which is needed for jsonb parsing and processing */ + + /* + * set sql_dialect to tsql, which is needed for jsonb parsing and + * processing + */ prev_sql_dialect = sql_dialect; sql_dialect = SQL_DIALECT_TSQL; @@ -153,26 +156,30 @@ tsql_json_value(PG_FUNCTION_ARGS) /* check value is scalar */ if (result_jsonb && JB_ROOT_IS_SCALAR(result_jsonb)) { - /* handle cases where value is greater than 4000 characters */ - result_cstring = JsonbToCString(NULL, &result_jsonb->root, -1); - if (strlen(result_cstring) > 4000) - { - if (islax) - PG_RETURN_NULL(); - else - elog(ERROR, "The JSON_VALUE function requires 2 arguments"); - } - /* trim double quotes on json string values which are added by JsonbToCString() */ - if (strlen(result_cstring) > 1 && result_cstring[0] == '\"') - result_varchar = (VarChar *) cstring_to_text_with_len(result_cstring+1, strlen(result_cstring)-2); - else - result_varchar = (VarChar *) cstring_to_text(result_cstring); - PG_RETURN_VARCHAR_P(result_varchar); - } + /* handle cases where value is greater than 4000 characters */ + result_cstring = JsonbToCString(NULL, &result_jsonb->root, -1); + if (strlen(result_cstring) > 4000) + { + if (islax) + PG_RETURN_NULL(); + else + elog(ERROR, "The JSON_VALUE function requires 2 arguments"); + } + + /* + * trim double quotes on json string values which are added by + * JsonbToCString() + */ + if (strlen(result_cstring) > 1 && result_cstring[0] == '\"') + result_varchar = (VarChar *) cstring_to_text_with_len(result_cstring + 1, strlen(result_cstring) - 2); + else + result_varchar = (VarChar *) cstring_to_text(result_cstring); + PG_RETURN_VARCHAR_P(result_varchar); + } /* result is not a scalar value */ - else if (!islax) + else if (!islax) elog(ERROR, "Scalar value cannot be found in the specified JSON path."); - + PG_RETURN_NULL(); } @@ -180,27 +187,30 @@ tsql_json_value(PG_FUNCTION_ARGS) * tsql_json_query() * * Extracts a json object or array from a json expression string - * + * * 'json_text' - target document for jsonpath evaluation * 'jsonpath_text' - jsonpath to be executed */ Datum tsql_json_query(PG_FUNCTION_ARGS) { - text *json_text, - *jsonpath_text; - Datum result, - jsonb, - jsonpath; - Jsonb *result_jsonb; - VarChar *result_varchar; - bool islax; - int prev_sql_dialect; + text *json_text, + *jsonpath_text; + Datum result , + jsonb, + jsonpath; + Jsonb *result_jsonb; + VarChar *result_varchar; + bool islax; + int prev_sql_dialect; if (PG_ARGISNULL(0)) PG_RETURN_NULL(); - /* set sql_dialect to tsql, which is needed for jsonb parsing and processing */ + /* + * set sql_dialect to tsql, which is needed for jsonb parsing and + * processing + */ prev_sql_dialect = sql_dialect; sql_dialect = SQL_DIALECT_TSQL; @@ -216,33 +226,33 @@ tsql_json_query(PG_FUNCTION_ARGS) /* reset sql_dialect */ sql_dialect = prev_sql_dialect; - /* Check for null result*/ + /* Check for null result */ if (!result) PG_RETURN_NULL(); islax = (DatumGetJsonPathP(jsonpath)->header & JSONPATH_LAX) != 0; result_jsonb = DatumGetJsonbP(result); - /* check if value is json object or array */ - if (result_jsonb - && !JB_ROOT_IS_SCALAR(result_jsonb) - && (JB_ROOT_IS_OBJECT(result_jsonb) || JB_ROOT_IS_ARRAY(result_jsonb))) - { - result_varchar = (VarChar *) cstring_to_text(JsonbToCString(NULL, &result_jsonb->root, -1)); - PG_RETURN_VARCHAR_P(result_varchar); - } + /* check if value is json object or array */ + if (result_jsonb + && !JB_ROOT_IS_SCALAR(result_jsonb) + && (JB_ROOT_IS_OBJECT(result_jsonb) || JB_ROOT_IS_ARRAY(result_jsonb))) + { + result_varchar = (VarChar *) cstring_to_text(JsonbToCString(NULL, &result_jsonb->root, -1)); + PG_RETURN_VARCHAR_P(result_varchar); + } /* result is not an array or object */ else if (!islax) elog(ERROR, "Object or array cannot be found in the specified JSON path."); - PG_RETURN_NULL(); + PG_RETURN_NULL(); } Datum tsql_jsonb_path_query_first(Datum jsonb_datum, Datum jsonpath_datum) { LOCAL_FCINFO(fcinfo, 4); - Datum result, - vars; + Datum result , + vars; vars = DirectFunctionCall1(jsonb_in, CStringGetDatum("{}")); @@ -277,37 +287,47 @@ tsql_openjson_with(PG_FUNCTION_ARGS) static Datum tsql_openjson_with_internal(PG_FUNCTION_ARGS) { - FuncCallContext *funcctx; - int call_cntr; - int max_calls; - TupleDesc tupdesc; - AttInMetadata *attinmeta; - /* column_list is a list of lists - each contained list corresponds to a column in the return set */ - List *column_list; + FuncCallContext *funcctx; + int call_cntr; + int max_calls; + TupleDesc tupdesc; + AttInMetadata *attinmeta; + + /* + * column_list is a list of lists - each contained list corresponds to a + * column in the return set + */ + List *column_list; if (SRF_IS_FIRSTCALL()) { - int prev_sql_dialect; - MemoryContext oldcontext; + int prev_sql_dialect; + MemoryContext oldcontext; funcctx = SRF_FIRSTCALL_INIT(); prev_sql_dialect = sql_dialect; PG_TRY(); { - Jsonb *sub_jb; - ArrayType *arr; - int ndim; - - /* set sql_dialect to tsql, which is needed for jsonb parsing and processing */ + Jsonb *sub_jb; + ArrayType *arr; + int ndim; + + /* + * set sql_dialect to tsql, which is needed for jsonb parsing and + * processing + */ sql_dialect = SQL_DIALECT_TSQL; oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - /* Get information about return type. Used to build return message later. */ + /* + * Get information about return type. Used to build return message + * later. + */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("function returning record called in context " - "that cannot accept type record"))); + errmsg("function returning record called in context " + "that cannot accept type record"))); sub_jb = tsql_openjson_with_get_subjsonb(fcinfo); @@ -319,29 +339,29 @@ tsql_openjson_with_internal(PG_FUNCTION_ARGS) if (ndim > 1) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("array must be one-dimensional"))); + errmsg("array must be one-dimensional"))); else if (array_contains_nulls(arr)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("array must not contain nulls"))); + errmsg("array must not contain nulls"))); else if (ndim == 1) { /* generate rowsets for each column path */ - Datum *datum_opts; - int nelems; + Datum *datum_opts; + int nelems; Assert(ARR_ELEMTYPE(arr) == TEXTOID); deconstruct_array(arr, TEXTOID, -1, false, TYPALIGN_INT, - &datum_opts, NULL, &nelems); + &datum_opts, NULL, &nelems); max_calls = 0; column_list = NIL; for (int i = 0; i < nelems; i++) { - char *col_info = TextDatumGetCString(datum_opts[i]); - List *list = tsql_openjson_with_columnize(sub_jb, col_info); + char *col_info = TextDatumGetCString(datum_opts[i]); + List *list = tsql_openjson_with_columnize(sub_jb, col_info); column_list = lappend(column_list, list); @@ -366,26 +386,34 @@ tsql_openjson_with_internal(PG_FUNCTION_ARGS) column_list = funcctx->user_fctx; call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; - attinmeta = funcctx->attinmeta; + attinmeta = funcctx->attinmeta; if (call_cntr < max_calls && column_list != NULL) { - char **values; - ListCell *lc; + char **values; + ListCell *lc; HeapTuple tuple; - Datum result; + Datum result; values = palloc0(sizeof(char *) * column_list->length); - /* go through each column list and add its result to the current tuple to be returned */ + + /* + * go through each column list and add its result to the current tuple + * to be returned + */ foreach(lc, column_list) { - int i = foreach_current_index(lc); - List *column = lfirst(lc); + int i = foreach_current_index(lc); + List *column = lfirst(lc); + if (column) values[i] = linitial(column); - lc->ptr_value = list_delete_first(column); /* update each column to the next result for the next iteration */ + lc->ptr_value = list_delete_first(column); /* update each column to + * the next result for + * the next iteration */ } tuple = BuildTupleFromCStrings(attinmeta, values); result = HeapTupleGetDatum(tuple); + SRF_RETURN_NEXT(funcctx, result); } else diff --git a/contrib/babelfishpg_tsql/src/linked_servers.c b/contrib/babelfishpg_tsql/src/linked_servers.c index 8c90d93136..ef26faa735 100644 --- a/contrib/babelfishpg_tsql/src/linked_servers.c +++ b/contrib/babelfishpg_tsql/src/linked_servers.c @@ -26,23 +26,23 @@ PG_FUNCTION_INFO_V1(openquery_internal); #define TDS_NUMERIC_MAX_PRECISION 38 -/* +/* * number of bytes a numeric/decimal value takes in * TDS (according to implementation of client library), * where the array index is the numeric precision */ -const int tds_numeric_bytes_per_prec[TDS_NUMERIC_MAX_PRECISION + 1] = { - 1, - 2, 2, 3, 3, 4, 4, 4, 5, 5, - 6, 6, 6, 7, 7, 8, 8, 9, 9, 9, +const int tds_numeric_bytes_per_prec[TDS_NUMERIC_MAX_PRECISION + 1] = { + 1, + 2, 2, 3, 3, 4, 4, 4, 5, 5, + 6, 6, 6, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12, 12, 13, 13, 14, 14, 14, 15, 15, 16, 16, 16, 17, 17 }; -int tdsTypeStrToTypeId(char* datatype); -Oid tdsTypeToOid(int datatype); -int tdsTypeTypmod(int datatype, int datalen, bool is_metadata, int precision, int scale); -Datum getDatumFromBytePtr(LinkedServerProcess lsproc, void *val, int datatype, int len); +int tdsTypeStrToTypeId(char *datatype); +Oid tdsTypeToOid(int datatype); +int tdsTypeTypmod(int datatype, int datalen, bool is_metadata, int precision, int scale); +Datum getDatumFromBytePtr(LinkedServerProcess lsproc, void *val, int datatype, int len); static int linked_server_msg_handler(LinkedServerProcess lsproc, int error_code, int state, int severity, char *error_msg, char *svr_name, char *proc_name, int line) @@ -50,15 +50,18 @@ linked_server_msg_handler(LinkedServerProcess lsproc, int error_code, int state, StringInfoData buf; initStringInfo(&buf); - - /* If error severity is greater than 10, we interpret it as a T-SQL error; otheriwse, a T-SQL info */ + + /* + * If error severity is greater than 10, we interpret it as a T-SQL error; + * otheriwse, a T-SQL info + */ appendStringInfo( - &buf, - "TDS client library %s: Msg #: %i, Msg state: %i, ", - severity > 10 ? "error" : "info", - error_code, - state - ); + &buf, + "TDS client library %s: Msg #: %i, Msg state: %i, ", + severity > 10 ? "error" : "info", + error_code, + state + ); if (error_msg) appendStringInfo(&buf, "Msg: %s, ", error_msg); @@ -73,23 +76,23 @@ linked_server_msg_handler(LinkedServerProcess lsproc, int error_code, int state, if (severity > 10) ereport(ERROR, - (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), - errmsg("%s", buf.data))); + (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), + errmsg("%s", buf.data))); else { /* - * We delibrately don't call the TDS report warning/info function - * here because in doing so, it spews a lot of messages client side - * like for database change, language change for every single connection - * made to a remote server. Thus, we just log those events in the PG log - * files. It would be better to atleast send the warnings client side but - * currently there is no way the client libary is able to distinguish - * between a warning and an informational message. + * We delibrately don't call the TDS report warning/info function here + * because in doing so, it spews a lot of messages client side like + * for database change, language change for every single connection + * made to a remote server. Thus, we just log those events in the PG + * log files. It would be better to atleast send the warnings client + * side but currently there is no way the client libary is able to + * distinguish between a warning and an informational message. * * TODO: Distinguish between WARNING and INFO */ ereport(INFO, - (errmsg("%s", buf.data))); + (errmsg("%s", buf.data))); } return 0; @@ -102,8 +105,9 @@ linked_server_msg_handler(LinkedServerProcess lsproc, int error_code, int state, static char * remove_substr(char *src, const char *substr) { - char *start, *end; - size_t len; + char *start, + *end; + size_t len; if (!*substr) return src; @@ -131,8 +135,8 @@ linked_server_err_handler(LinkedServerProcess lsproc, int severity, int db_error { StringInfoData buf; - char* err_msg = NULL; - char* str = NULL; + char *err_msg = NULL; + char *str = NULL; initStringInfo(&buf); @@ -146,7 +150,7 @@ linked_server_err_handler(LinkedServerProcess lsproc, int severity, int db_error str = err_msg; /* We convert the 'S' in "Server" to lowercase */ - while((str = strstr(str, "Server")) != NULL) + while ((str = strstr(str, "Server")) != NULL) *str = 's'; } @@ -164,7 +168,7 @@ linked_server_err_handler(LinkedServerProcess lsproc, int severity, int db_error ereport(ERROR, (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), - errmsg("%s", buf.data))); + errmsg("%s", buf.data))); return LS_INT_CANCEL; } @@ -176,8 +180,8 @@ linked_server_err_handler(LinkedServerProcess lsproc, int severity, int db_error Datum getDatumFromBytePtr(LinkedServerProcess lsproc, void *val, int datatype, int len) { - bytea *bytes; - + bytea *bytes; + switch (datatype) { case TSQL_IMAGE: @@ -191,7 +195,7 @@ getDatumFromBytePtr(LinkedServerProcess lsproc, void *val, int datatype, int len return PointerGetDatum(bytes); case TSQL_BIT: case TSQL_BITN: - return BoolGetDatum(*(bool *)val); + return BoolGetDatum(*(bool *) val); case TSQL_VARCHAR: case TSQL_VARCHAR_X: case TSQL_CHAR: @@ -199,19 +203,23 @@ getDatumFromBytePtr(LinkedServerProcess lsproc, void *val, int datatype, int len case TSQL_XML: case TSQL_NVARCHAR_X: case TSQL_NCHAR_X: + /* - * All character data types are received from the client library in a format that can - * directly be stored in a PG tuple store so they need our TDS side receiver magic. + * All character data types are received from the client library + * in a format that can directly be stored in a PG tuple store so + * they need our TDS side receiver magic. */ - PG_RETURN_VARCHAR_P((VarChar *)cstring_to_text_with_len((char *)val, len)); + PG_RETURN_VARCHAR_P((VarChar *) cstring_to_text_with_len((char *) val, len)); break; case TSQL_TEXT: case TSQL_NTEXT: + /* - * All character data types are received from the client library in a format that can - * directly be stored in a PG tuple store, so they do not need our TDS side receiver magic. + * All character data types are received from the client library + * in a format that can directly be stored in a PG tuple store, so + * they do not need our TDS side receiver magic. */ - PG_RETURN_TEXT_P(cstring_to_text_with_len((char *)val, len)); + PG_RETURN_TEXT_P(cstring_to_text_with_len((char *) val, len)); break; case TSQL_UUID: if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->get_datum_from_byte_ptr) @@ -223,7 +231,7 @@ getDatumFromBytePtr(LinkedServerProcess lsproc, void *val, int datatype, int len * StringInfoData pointing to the correct portion of the TDS * message buffer. */ - pbuf.data = (char *)val; + pbuf.data = (char *) val; pbuf.maxlen = 16; pbuf.len = 16; pbuf.cursor = 0; @@ -242,7 +250,7 @@ getDatumFromBytePtr(LinkedServerProcess lsproc, void *val, int datatype, int len * StringInfoData pointing to the correct portion of the TDS * message buffer. */ - pbuf.data = (char *)val; + pbuf.data = (char *) val; pbuf.maxlen = 8; pbuf.len = 8; pbuf.cursor = 0; @@ -260,7 +268,7 @@ getDatumFromBytePtr(LinkedServerProcess lsproc, void *val, int datatype, int len * StringInfoData pointing to the correct portion of the TDS * message buffer. */ - pbuf.data = (char *)val; + pbuf.data = (char *) val; pbuf.maxlen = 4; pbuf.len = 4; pbuf.cursor = 0; @@ -296,16 +304,18 @@ getDatumFromBytePtr(LinkedServerProcess lsproc, void *val, int datatype, int len { LS_TDS_NUMERIC *numeric; StringInfoData pbuf; - int n, i = 0; + int n, + i = 0; - numeric = (LS_TDS_NUMERIC *)val; + numeric = (LS_TDS_NUMERIC *) val; n = tds_numeric_bytes_per_prec[numeric->precision] - 1; /* reverse 'n' bytes after 1st byte (sign byte) */ - for (i = 0; i < n/2; i++) + for (i = 0; i < n / 2; i++) { - char c = numeric->array[i + 1]; + char c = numeric->array[i + 1]; + numeric->array[i + 1] = numeric->array[n - i]; numeric->array[n - i] = c; } @@ -321,8 +331,8 @@ getDatumFromBytePtr(LinkedServerProcess lsproc, void *val, int datatype, int len * StringInfoData pointing to the correct portion of the TDS * message buffer. */ - pbuf.data = (char *)(numeric->array); - pbuf.maxlen = 17; /* sign byte + numeric bytes (1 + 16) */ + pbuf.data = (char *) (numeric->array); + pbuf.maxlen = 17; /* sign byte + numeric bytes (1 + 16) */ pbuf.len = 17; pbuf.cursor = 0; @@ -331,18 +341,18 @@ getDatumFromBytePtr(LinkedServerProcess lsproc, void *val, int datatype, int len break; case TSQL_FLOATN: case TSQL_FLOAT: - return Float8GetDatum(*(float8 *)val); + return Float8GetDatum(*(float8 *) val); case TSQL_REAL: - return Float4GetDatum(*(float4 *)val); + return Float4GetDatum(*(float4 *) val); case TSQL_TINYINT: - return UInt8GetDatum(*(int16_t *)val); + return UInt8GetDatum(*(int16_t *) val); case TSQL_SMALLINT: - return Int16GetDatum(*(int16_t *)val); + return Int16GetDatum(*(int16_t *) val); case TSQL_INT: case TSQL_INTN: - return Int32GetDatum(*(int32_t *)val); + return Int32GetDatum(*(int32_t *) val); case TSQL_BIGINT: - return Int64GetDatum(*(int64_t *)val); + return Int64GetDatum(*(int64_t *) val); case TSQL_MONEY: case TSQL_MONEYN: if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->get_datum_from_byte_ptr) @@ -354,7 +364,7 @@ getDatumFromBytePtr(LinkedServerProcess lsproc, void *val, int datatype, int len * StringInfoData pointing to the correct portion of the TDS * message buffer. */ - pbuf.data = (char *)val; + pbuf.data = (char *) val; pbuf.maxlen = 8; pbuf.len = 8; pbuf.cursor = 0; @@ -372,7 +382,7 @@ getDatumFromBytePtr(LinkedServerProcess lsproc, void *val, int datatype, int len * StringInfoData pointing to the correct portion of the TDS * message buffer. */ - pbuf.data = (char *)val; + pbuf.data = (char *) val; pbuf.maxlen = 4; pbuf.len = 4; pbuf.cursor = 0; @@ -393,7 +403,7 @@ getDatumFromBytePtr(LinkedServerProcess lsproc, void *val, int datatype, int len if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->get_datum_from_date_time_struct) { LS_TDS_DATETIMEALL *datetimeoffset = (LS_TDS_DATETIMEALL *) val; - + /* optional attribute here is time offset */ return (*pltsql_protocol_plugin_ptr)->get_datum_from_date_time_struct(datetimeoffset->time, datetimeoffset->date, TSQL_DATETIMEOFFSET, datetimeoffset->offset); } @@ -410,7 +420,7 @@ getDatumFromBytePtr(LinkedServerProcess lsproc, void *val, int datatype, int len * type. Used when preparing tuple descriptor for T-SQL OPENQUERY. */ int -tdsTypeStrToTypeId(char* datatype) +tdsTypeStrToTypeId(char *datatype) { datatype = lowerstr(datatype); @@ -471,8 +481,8 @@ tdsTypeStrToTypeId(char* datatype) else ereport(ERROR, (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), - errmsg("Unable to find type id for datatype %s", datatype) - )); + errmsg("Unable to find type id for datatype %s", datatype) + )); return 0; } @@ -489,85 +499,90 @@ tdsTypeToOid(int datatype) switch (datatype) { case TSQL_IMAGE: - return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid)("image"); + return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid) ("image"); case TSQL_VARBINARY: case TSQL_VARBINARY_X: - return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid)("varbinary"); + return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid) ("varbinary"); case TSQL_BINARY: case TSQL_BINARY_X: - return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid)("binary"); + return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid) ("binary"); case TSQL_BIT: case TSQL_BITN: - return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid)("bit"); + return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid) ("bit"); case TSQL_TEXT: return TEXTOID; case TSQL_NTEXT: - return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid)("ntext"); + return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid) ("ntext"); case TSQL_NVARCHAR_X: - return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid)("nvarchar"); + return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid) ("nvarchar"); case TSQL_VARCHAR: case TSQL_VARCHAR_X: case TSQL_CHAR: case TSQL_XML: return VARCHAROID; case TSQL_NCHAR_X: - return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid)("nchar"); + return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid) ("nchar"); case TSQL_CHAR_X: - return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid)("bpchar"); + return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid) ("bpchar"); case TSQL_DATETIME: case TSQL_DATETIMN: - return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid)("datetime"); + return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid) ("datetime"); case TSQL_SMALLDATETIME: - return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid)("smalldatetime"); + return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid) ("smalldatetime"); case TSQL_DATETIME2: - return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid)("datetime2"); + return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid) ("datetime2"); case TSQL_DATETIMEOFFSET: - return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid)("datetimeoffset"); + return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid) ("datetimeoffset"); case TSQL_DATE: return DATEOID; case TSQL_TIME: return TIMEOID; case TSQL_DECIMAL: case TSQL_NUMERIC: - /* - * Even though we have a domain for decimal, we will still use NUMERICOID + + /* + * Even though we have a domain for decimal, we will still use + * NUMERICOID * - * In babelfish, we send decimal as numeric so when the client library reads - * the column metadata token, it reads it as TSQL_NUMERIC but while computing - * the tuple descriptor using sp_describe_first_result_set, the system_type_name - * is decimal which causes a mismatch between actual and expected data type. - * - * To get around this, we store both decimal and numeric with NUMERICOID + * In babelfish, we send decimal as numeric so when the client + * library reads the column metadata token, it reads it as + * TSQL_NUMERIC but while computing the tuple descriptor using + * sp_describe_first_result_set, the system_type_name is + * decimal which causes a mismatch between actual and expected + * data type. + * + * To get around this, we store both decimal and numeric with + * NUMERICOID */ return NUMERICOID; case TSQL_FLOAT: - return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid)("float"); + return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid) ("float"); case TSQL_REAL: - return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid)("real"); + return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid) ("real"); case TSQL_TINYINT: - return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid)("tinyint"); + return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid) ("tinyint"); case TSQL_SMALLINT: return INT2OID; case TSQL_INT: case TSQL_INTN: - return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid)("int"); + return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid) ("int"); case TSQL_BIGINT: - return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid)("bigint"); + return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid) ("bigint"); case TSQL_MONEY: case TSQL_MONEYN: - return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid)("money"); + return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid) ("money"); case TSQL_SMALLMONEY: - return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid)("smallmoney"); + return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid) ("smallmoney"); case TSQL_UUID: - return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid)("uniqueidentifier"); + return (*common_utility_plugin_ptr->lookup_tsql_datatype_oid) ("uniqueidentifier"); default: ereport(ERROR, - (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), - errmsg("Unable to find OID for datatype %d", datatype) - )); + (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), + errmsg("Unable to find OID for datatype %d", datatype) + )); } } - + return InvalidOid; } @@ -596,16 +611,19 @@ tdsTypeTypmod(int datatype, int datalen, bool is_metadata, int precision, int sc if (datalen == -1) return -1; - /* - * When modfying the OPENQUERY result-set tuple descriptor, we use sp_describe_first_result_set, - * which gives us the correct data length of character data types. However, the col length that - * accompanies the actual result set column metadata from client library, is 4 * (max column - * len) and so we divide it by 4 to get appropriate typmod for character data types. + /* + * When modfying the OPENQUERY result-set tuple descriptor, we + * use sp_describe_first_result_set, which gives us the + * correct data length of character data types. However, the + * col length that accompanies the actual result set column + * metadata from client library, is 4 * (max column len) and + * so we divide it by 4 to get appropriate typmod for + * character data types. */ if (is_metadata) return datalen + VARHDRSZ; else - return (datalen/4) + VARHDRSZ; + return (datalen / 4) + VARHDRSZ; } case TSQL_NCHAR_X: case TSQL_NVARCHAR_X: @@ -613,16 +631,19 @@ tdsTypeTypmod(int datatype, int datalen, bool is_metadata, int precision, int sc if (datalen == -1) return -1; - /* - * When modfying the OPENQUERY result-set tuple descriptor, we use sp_describe_first_result_set, - * which gives us the correct data length of character data types. However, the col length that - * accompanies the actual result set column metadata from client library, is 4 * (max column - * len) and so we divide it by 4 to get appropriate typmod for character data types. + /* + * When modfying the OPENQUERY result-set tuple descriptor, we + * use sp_describe_first_result_set, which gives us the + * correct data length of character data types. However, the + * col length that accompanies the actual result set column + * metadata from client library, is 4 * (max column len) and + * so we divide it by 4 to get appropriate typmod for + * character data types. */ if (is_metadata) - return (datalen/2) + VARHDRSZ; + return (datalen / 2) + VARHDRSZ; else - return (datalen/4) + VARHDRSZ; + return (datalen / 4) + VARHDRSZ; } case TSQL_DECIMAL: case TSQL_NUMERIC: @@ -643,9 +664,9 @@ tdsTypeTypmod(int datatype, int datalen, bool is_metadata, int precision, int sc else return -1; } - case TSQL_BIT: + case TSQL_BIT: case TSQL_BITN: - case TSQL_TEXT: + case TSQL_TEXT: case TSQL_NTEXT: case TSQL_DATETIME: case TSQL_DATETIMN: @@ -665,47 +686,47 @@ tdsTypeTypmod(int datatype, int datalen, bool is_metadata, int precision, int sc return -1; default: ereport(ERROR, - (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), - errmsg("Unable to find typmod for datatype %d", datatype) - )); + (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), + errmsg("Unable to find typmod for datatype %d", datatype) + )); } return 0; } static void -ValidateLinkedServerDataSource(char* data_src) +ValidateLinkedServerDataSource(char *data_src) { - /* - * Only treat fully qualified DNS names (endpoints) or IP address - * as valid data sources. - * + /* + * Only treat fully qualified DNS names (endpoints) or IP address as valid + * data sources. + * * If data source is provided in the form of servername\\instancename, we - * throw an error to suggest use of fully qualified domain name or the IP address - * instead. + * throw an error to suggest use of fully qualified domain name or the IP + * address instead. */ if (strchr(data_src, '\\')) ereport(ERROR, - (errcode(ERRCODE_FDW_ERROR), - errmsg("Only fully qualified domain name or IP address are allowed as data source"))); + (errcode(ERRCODE_FDW_ERROR), + errmsg("Only fully qualified domain name or IP address are allowed as data source"))); } static void -linked_server_establish_connection(char* servername, LinkedServerProcess *lsproc) +linked_server_establish_connection(char *servername, LinkedServerProcess * lsproc) { /* Get the foreign server and user mapping */ ForeignServer *server = NULL; UserMapping *mapping = NULL; - + LinkedServerLogin login; - ListCell *option; - char *data_src = NULL; - char *database = NULL; + ListCell *option; + char *data_src = NULL; + char *database = NULL; - if(!pltsql_enable_linked_servers) + if (!pltsql_enable_linked_servers) ereport(ERROR, - (errcode(ERRCODE_FDW_ERROR), - errmsg("'openquery' is not currently supported in Babelfish"))); + (errcode(ERRCODE_FDW_ERROR), + errmsg("'openquery' is not currently supported in Babelfish"))); PG_TRY(); { @@ -715,22 +736,22 @@ linked_server_establish_connection(char* servername, LinkedServerProcess *lsproc if (server == NULL) ereport(ERROR, (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), - errmsg("Error fetching foreign server with servername '%s'", servername) - )); + errmsg("Error fetching foreign server with servername '%s'", servername) + )); mapping = GetUserMapping(GetUserId(), server->serverid); if (mapping == NULL) ereport(ERROR, (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), - errmsg("Error fetching user mapping with servername '%s'", servername) - )); + errmsg("Error fetching user mapping with servername '%s'", servername) + )); if (LINKED_SERVER_INIT() == FAIL) ereport(ERROR, (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), - errmsg("Failed to initialize TDS client library environment") - )); + errmsg("Failed to initialize TDS client library environment") + )); LINKED_SERVER_ERR_HANDLE(linked_server_err_handler); LINKED_SERVER_MSG_HANDLE(linked_server_msg_handler); @@ -754,9 +775,9 @@ linked_server_establish_connection(char* servername, LinkedServerProcess *lsproc } else ereport(ERROR, - (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), - errmsg("Unrecognized option \"%s\" for user mapping", element->defname) - )); + (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), + errmsg("Unrecognized option \"%s\" for user mapping", element->defname) + )); } LINKED_SERVER_SET_APP(login); @@ -770,12 +791,12 @@ linked_server_establish_connection(char* servername, LinkedServerProcess *lsproc if (strcmp(element->defname, "servername") == 0) data_src = defGetString(element); else if (strcmp(element->defname, "database") == 0) - database = defGetString(element); + database = defGetString(element); else ereport(ERROR, - (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), - errmsg("Unrecognized option \"%s\" for foreign server", element->defname) - )); + (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), + errmsg("Unrecognized option \"%s\" for foreign server", element->defname) + )); } ValidateLinkedServerDataSource(data_src); @@ -792,8 +813,8 @@ linked_server_establish_connection(char* servername, LinkedServerProcess *lsproc *lsproc = LINKED_SERVER_OPEN(login, data_src); if (!(*lsproc)) ereport(ERROR, - (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), - errmsg("Unable to connect to \"%s\"", data_src))); + (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), + errmsg("Unable to connect to \"%s\"", data_src))); LINKED_SERVER_FREELOGIN(login); @@ -809,11 +830,11 @@ linked_server_establish_connection(char* servername, LinkedServerProcess *lsproc } /* - * Fetch the column medata for the expected result set - * from remote server + * Fetch the column medata for the expected result set + * from remote server */ static void -getOpenqueryTupdescFromMetadata(char* linked_server, char* query, TupleDesc *tupdesc) +getOpenqueryTupdescFromMetadata(char *linked_server, char *query, TupleDesc *tupdesc) { LinkedServerProcess lsproc; @@ -822,11 +843,14 @@ getOpenqueryTupdescFromMetadata(char* linked_server, char* query, TupleDesc *tup LINKED_SERVER_RETCODE erc; StringInfoData buf; - int colcount; + int colcount; linked_server_establish_connection(linked_server, &lsproc); - /* prepare the query that will executed on remote server to get column medata of result set*/ + /* + * prepare the query that will executed on remote server to get column + * medata of result set + */ initStringInfo(&buf); appendStringInfoString(&buf, "EXEC sp_describe_first_result_set N'"); @@ -836,8 +860,8 @@ getOpenqueryTupdescFromMetadata(char* linked_server, char* query, TupleDesc *tup /* * If character is a single quote, we append another single quote - * because we want to escape it when we feed the query as a parameter - * to sp_describe_first_result_set stored procedure. + * because we want to escape it when we feed the query as a + * parameter to sp_describe_first_result_set stored procedure. */ if (query[i] == '\'') appendStringInfoChar(&buf, '\''); @@ -846,13 +870,13 @@ getOpenqueryTupdescFromMetadata(char* linked_server, char* query, TupleDesc *tup appendStringInfoString(&buf, "', NULL, 0"); LINKED_SERVER_DEBUG("LINKED SERVER: (Metadata) - Writing the following query to LinkedServerProcess struct: %s", buf.data); - + /* populate query in LinkedServerProcess structure */ if ((erc = LINKED_SERVER_PUT_CMD(lsproc, buf.data)) != SUCCEED) ereport(ERROR, (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), - errmsg("error writing query \"%s\" to LinkedServerProcess struct", buf.data) - )); + errmsg("error writing query \"%s\" to LinkedServerProcess struct", buf.data) + )); LINKED_SERVER_DEBUG("LINKED SERVER: (Metadata) - Executing query against remote server"); @@ -860,8 +884,8 @@ getOpenqueryTupdescFromMetadata(char* linked_server, char* query, TupleDesc *tup if (LINKED_SERVER_EXEC_QUERY(lsproc) == FAIL) ereport(ERROR, (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), - errmsg("error executing query \"%s\" against remote server", buf.data) - )); + errmsg("error executing query \"%s\" against remote server", buf.data) + )); LINKED_SERVER_DEBUG("LINKED SERVER: (Metadata) - Begin fetching results from remote server"); @@ -870,97 +894,108 @@ getOpenqueryTupdescFromMetadata(char* linked_server, char* query, TupleDesc *tup if (erc == FAIL) { ereport(ERROR, - (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), - errmsg("Failed to get results from query %s", buf.data) - )); + (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), + errmsg("Failed to get results from query %s", buf.data) + )); } /* We have some results to process */ colcount = LINKED_SERVER_NUM_COLS(lsproc); - if(colcount > 0) + if (colcount > 0) { - int numrows = 0; - int i = 0; + int numrows = 0; + int i = 0; - int collen[MAX_COLS_SELECT]; - char **colname = (char **) palloc0(MAX_COLS_SELECT * sizeof(char*)); - int tdsTypeId[MAX_COLS_SELECT]; - int tdsTypePrecision[MAX_COLS_SELECT]; - int tdsTypeScale[MAX_COLS_SELECT]; + int collen[MAX_COLS_SELECT]; + char **colname = (char **) palloc0(MAX_COLS_SELECT * sizeof(char *)); + int tdsTypeId[MAX_COLS_SELECT]; + int tdsTypePrecision[MAX_COLS_SELECT]; + int tdsTypeScale[MAX_COLS_SELECT]; /* bound variables */ - int bind_collen, bind_tdsTypeId, bind_precision, bind_scale; - char bind_colname[256] = {0x00}; - char bind_typename[256] = {0x00}; - char *column_dup; - int dup_collen; + int bind_collen, + bind_tdsTypeId, + bind_precision, + bind_scale; + char bind_colname[256] = {0x00}; + char bind_typename[256] = {0x00}; + char *column_dup; + int dup_collen; for (i = 0; i < MAX_COLS_SELECT; i++) colname[i] = (char *) palloc0(256 * sizeof(char)); - if (LINKED_SERVER_BIND_VAR(lsproc, 3, LS_NTBSTRINGBING, sizeof(bind_colname), (LS_BYTE *)bind_colname) != SUCCEED) + if (LINKED_SERVER_BIND_VAR(lsproc, 3, LS_NTBSTRINGBING, sizeof(bind_colname), (LS_BYTE *) bind_colname) != SUCCEED) ereport(ERROR, - (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), - errmsg("Failed to bind results for column \"name\" to a variable.") - )); + (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), + errmsg("Failed to bind results for column \"name\" to a variable.") + )); - if (LINKED_SERVER_BIND_VAR(lsproc, 5, LS_INTBIND, sizeof(int), (LS_BYTE *)&bind_tdsTypeId) != SUCCEED) + if (LINKED_SERVER_BIND_VAR(lsproc, 5, LS_INTBIND, sizeof(int), (LS_BYTE *) & bind_tdsTypeId) != SUCCEED) ereport(ERROR, - (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), - errmsg("Failed to bind results for column \"system_type_id\" to a variable.") - )); - - if (LINKED_SERVER_BIND_VAR(lsproc, 6, LS_NTBSTRINGBING, sizeof(bind_typename), (LS_BYTE *)&bind_typename) != SUCCEED) + (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), + errmsg("Failed to bind results for column \"system_type_id\" to a variable.") + )); + + if (LINKED_SERVER_BIND_VAR(lsproc, 6, LS_NTBSTRINGBING, sizeof(bind_typename), (LS_BYTE *) & bind_typename) != SUCCEED) ereport(ERROR, - (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), - errmsg("Failed to bind results for column \"system_type_name\" to a variable.") - )); + (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), + errmsg("Failed to bind results for column \"system_type_name\" to a variable.") + )); - if (LINKED_SERVER_BIND_VAR(lsproc, 7, INTBIND, sizeof(int), (LS_BYTE *)&bind_collen) != SUCCEED) + if (LINKED_SERVER_BIND_VAR(lsproc, 7, INTBIND, sizeof(int), (LS_BYTE *) & bind_collen) != SUCCEED) ereport(ERROR, - (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), - errmsg("Failed to bind results for column \"max_length\" to a variable.") - )); + (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), + errmsg("Failed to bind results for column \"max_length\" to a variable.") + )); - if (LINKED_SERVER_BIND_VAR(lsproc, 8, LS_INTBIND, sizeof(int), (LS_BYTE *)&bind_precision) != SUCCEED) + if (LINKED_SERVER_BIND_VAR(lsproc, 8, LS_INTBIND, sizeof(int), (LS_BYTE *) & bind_precision) != SUCCEED) ereport(ERROR, - (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), - errmsg("Failed to bind results for column \"precision\" to a variable.") - )); + (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), + errmsg("Failed to bind results for column \"precision\" to a variable.") + )); - if (LINKED_SERVER_BIND_VAR(lsproc, 9, LS_INTBIND, sizeof(int), (LS_BYTE *)&bind_scale) != SUCCEED) + if (LINKED_SERVER_BIND_VAR(lsproc, 9, LS_INTBIND, sizeof(int), (LS_BYTE *) & bind_scale) != SUCCEED) ereport(ERROR, - (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), - errmsg("Failed to bind results for column \"scale\" to a variable.") - )); + (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), + errmsg("Failed to bind results for column \"scale\" to a variable.") + )); LINKED_SERVER_DEBUG("LINKED SERVER: (Metadata) - Fetching result rows"); /* fetch the rows */ while (LINKED_SERVER_NEXT_ROW(lsproc) != NO_MORE_ROWS) { - char *typestr; - - /* We encountered an error, we shouldn't return any results */ - /* We return here, when we will again execute the query we will error out from there */ + char *typestr; + + /* + * We encountered an error, we shouldn't return any + * results + */ + + /* + * We return here, when we will again execute the query we + * will error out from there + */ if (bind_typename == NULL) ereport(ERROR, - (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), - errmsg("Failed to bind results for column \"system_type_name\" to a variable.") - )); + (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), + errmsg("Failed to bind results for column \"system_type_name\" to a variable.") + )); collen[numrows] = bind_collen; /* - * If column name is NULL or column name consists only of whitespace characters, - * we internally store it as ?column? (PG interpretation of NULL column name). + * If column name is NULL or column name consists only of + * whitespace characters, we internally store it as + * ?column? (PG interpretation of NULL column name). * - * This is needed so that later in the query plan, this column is not interpreted - * as a dropped column. + * This is needed so that later in the query plan, this + * column is not interpreted as a dropped column. * - * TODO: Solve for cases where column with only whitespace characters is a valid - * column name. + * TODO: Solve for cases where column with only whitespace + * characters is a valid column name. */ if ((bind_colname == NULL)) strncpy(bind_colname, "?column?", 256); @@ -971,7 +1006,7 @@ getOpenqueryTupdescFromMetadata(char* linked_server, char* query, TupleDesc *tup dup_collen = strlen(column_dup); /* remove trailing whitespaces */ - while(isspace(column_dup[dup_collen - 1])) + while (isspace(column_dup[dup_collen - 1])) column_dup[--dup_collen] = 0; /* column name only had whitespace characters */ @@ -1016,13 +1051,14 @@ getOpenqueryTupdescFromMetadata(char* linked_server, char* query, TupleDesc *tup else { /* - * Result set is empty, that means DML/DDL was passed as an argument to - * sp_describe_first_result_set. Since we only support SELECTs, we error out. + * Result set is empty, that means DML/DDL was passed as + * an argument to sp_describe_first_result_set. Since we + * only support SELECTs, we error out. */ ereport(ERROR, - (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), - errmsg("Query passed to OPENQUERY did not return a result set") - )); + (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), + errmsg("Query passed to OPENQUERY did not return a result set") + )); } if (colname) @@ -1053,13 +1089,13 @@ static Datum openquery_imp(PG_FUNCTION_ARGS) { LinkedServerProcess lsproc = NULL; - char* query; + char *query; LINKED_SERVER_RETCODE erc; - int colcount = 0; - int rowcount = 0; - + int colcount = 0; + int rowcount = 0; + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; TupleDesc tupdesc; Tuplestorestate *tupstore; @@ -1069,7 +1105,7 @@ openquery_imp(PG_FUNCTION_ARGS) PG_TRY(); { query = PG_ARGISNULL(1) ? NULL : text_to_cstring(PG_GETARG_TEXT_PP(1)); - + linked_server_establish_connection(PG_ARGISNULL(0) ? NULL : text_to_cstring(PG_GETARG_TEXT_PP(0)), &lsproc); LINKED_SERVER_DEBUG("LINKED SERVER: (OPENQUERY) - Writing the following query to LinkedServerProcess struct: %s", query); @@ -1078,8 +1114,8 @@ openquery_imp(PG_FUNCTION_ARGS) if (LINKED_SERVER_PUT_CMD(lsproc, query) == FAIL) ereport(ERROR, (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), - errmsg("error writing query to lsproc struct") - )); + errmsg("error writing query to lsproc struct") + )); LINKED_SERVER_DEBUG("LINKED SERVER: (OPENQUERY) - Executing query against remote server"); @@ -1087,24 +1123,27 @@ openquery_imp(PG_FUNCTION_ARGS) if (LINKED_SERVER_EXEC_QUERY(lsproc) == FAIL) ereport(ERROR, (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), - errmsg("error executing query \"%s\" against remote server", query) - )); + errmsg("error executing query \"%s\" against remote server", query) + )); LINKED_SERVER_DEBUG("LINKED SERVER: (OPENQUERY) - Begin fetching results from remote server"); - /* This is not a while loop because we should only return the first result set */ + /* + * This is not a while loop because we should only return the first + * result set + */ if ((erc = LINKED_SERVER_RESULTS(lsproc)) != NO_MORE_RESULTS) { - int i; + int i; - void *val[MAX_COLS_SELECT]; + void *val[MAX_COLS_SELECT]; if (erc == FAIL) { ereport(ERROR, - (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), - errmsg("Failed to get results from query %s", query) - )); + (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), + errmsg("Failed to get results from query %s", query) + )); } /* store the column count */ @@ -1112,44 +1151,46 @@ openquery_imp(PG_FUNCTION_ARGS) LINKED_SERVER_DEBUG_FINER("LINKED SERVER: (OPENQUERY) - Number of columns in result set: %d", colcount); - if(colcount > 0) + if (colcount > 0) { /* check to see if caller supports us returning a tuplestore */ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("set-valued function called in context that cannot accept a set"))); + errmsg("set-valued function called in context that cannot accept a set"))); if (!(rsinfo->allowedModes & SFRM_Materialize)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("materialize mode required, but it is not allowed in this context"))); + errmsg("materialize mode required, but it is not allowed in this context"))); /* Build tupdesc for result tuples. */ tupdesc = CreateTemplateTupleDesc(colcount); /* Let us process column metadata first */ - for(i = 0; i < colcount; i++) + for (i = 0; i < colcount; i++) { - Oid tdsTypeOid; - int coltype = LINKED_SERVER_COL_TYPE(lsproc, i + 1); - char *colname = LINKED_SERVER_COL_NAME(lsproc, i + 1); - int collen = LINKED_SERVER_COL_LEN(lsproc, i + 1); + Oid tdsTypeOid; + int coltype = LINKED_SERVER_COL_TYPE(lsproc, i + 1); + char *colname = LINKED_SERVER_COL_NAME(lsproc, i + 1); + int collen = LINKED_SERVER_COL_LEN(lsproc, i + 1); LS_TYPEINFO *typinfo = LINKED_SERVER_COL_TYPEINFO(lsproc, i + 1); - + tdsTypeOid = tdsTypeToOid(coltype); LINKED_SERVER_DEBUG_FINER("LINKED SERVER: (OPENQUERY) - Colinfo - index: %d, name: %s, type: %d, len: %d", i + 1, colname, coltype, collen); - /* - * Current TDS client library has a limitation where it can send - * column types like nvarchar as varchar in column metadata, so - * check with out previously computed tuple descriptor to see what - * should be the actual data type. At the moment there is no other way. + /* + * Current TDS client library has a limitation where it + * can send column types like nvarchar as varchar in + * column metadata, so check with out previously computed + * tuple descriptor to see what should be the actual data + * type. At the moment there is no other way. */ - if ((tdsTypeOid == VARCHAROID) || (tdsTypeOid == TEXTOID) || (common_utility_plugin_ptr && ((*common_utility_plugin_ptr->lookup_tsql_datatype_oid)("binary")))) + if ((tdsTypeOid == VARCHAROID) || (tdsTypeOid == TEXTOID) || (common_utility_plugin_ptr && ((*common_utility_plugin_ptr->lookup_tsql_datatype_oid) ("binary")))) { Form_pg_attribute att = TupleDescAttr(rsinfo->expectedDesc, (AttrNumber) i); + tdsTypeOid = att->atttypid; } @@ -1173,13 +1214,14 @@ openquery_imp(PG_FUNCTION_ARGS) while (LINKED_SERVER_NEXT_ROW(lsproc) != NO_MORE_ROWS) { /* for each row */ - Datum *values = palloc0(sizeof(Datum) * colcount); - bool *nulls = palloc0(sizeof(bool) * colcount); + Datum *values = palloc0(sizeof(Datum) * colcount); + bool *nulls = palloc0(sizeof(bool) * colcount); for (i = 0; i < colcount; i++) { - int coltype = LINKED_SERVER_COL_TYPE(lsproc, i + 1); - int datalen = LINKED_SERVER_DATA_LEN(lsproc, i + 1); + int coltype = LINKED_SERVER_COL_TYPE(lsproc, i + 1); + int datalen = LINKED_SERVER_DATA_LEN(lsproc, i + 1); + val[i] = LINKED_SERVER_DATA(lsproc, i + 1); if (val[i] == NULL) @@ -1209,13 +1251,13 @@ openquery_imp(PG_FUNCTION_ARGS) } PG_END_TRY(); - return (Datum)0; + return (Datum) 0; } #endif void -GetOpenqueryTupdescFromMetadata(char* linked_server, char* query, TupleDesc *tupdesc) +GetOpenqueryTupdescFromMetadata(char *linked_server, char *query, TupleDesc *tupdesc) { #ifdef ENABLE_TDS_LIB getOpenqueryTupdescFromMetadata(linked_server, query, tupdesc); @@ -1232,5 +1274,5 @@ openquery_internal(PG_FUNCTION_ARGS) #else NO_CLIENT_LIB_ERROR(); #endif - return (Datum)0; + return (Datum) 0; } diff --git a/contrib/babelfishpg_tsql/src/linked_servers.h b/contrib/babelfishpg_tsql/src/linked_servers.h index 2e56678171..9d1e46c323 100644 --- a/contrib/babelfishpg_tsql/src/linked_servers.h +++ b/contrib/babelfishpg_tsql/src/linked_servers.h @@ -5,14 +5,14 @@ #define MAX_COLS_SELECT 4096 -#define XSYBCHAR 175 /* 0xAF */ -#define XSYBVARCHAR 167 /* 0xA7 */ -#define XSYBNVARCHAR 231 /* 0xE7 */ -#define XSYBNCHAR 239 /* 0xEF */ -#define XSYBVARBINARY 165 /* 0xA5 */ -#define XSYBBINARY 173 /* 0xAD */ -#define SYBMSXML 241 /* 0xF1 */ -#define SYBUNIQUE 36 /* 0x24 */ +#define XSYBCHAR 175 /* 0xAF */ +#define XSYBVARCHAR 167 /* 0xA7 */ +#define XSYBNVARCHAR 231 /* 0xE7 */ +#define XSYBNCHAR 239 /* 0xEF */ +#define XSYBVARBINARY 165 /* 0xA5 */ +#define XSYBBINARY 173 /* 0xAD */ +#define SYBMSXML 241 /* 0xF1 */ +#define SYBUNIQUE 36 /* 0x24 */ #define TSQL_IMAGE SYBIMAGE #define TSQL_VARBINARY SYBVARBINARY @@ -56,23 +56,23 @@ typedef struct { - uint64_t time; /**< time, 7 digit precision */ - int32_t date; /**< date, 0 = 1900-01-01 */ - int16_t offset; /**< time offset */ - uint16_t time_prec3; - uint16_t _tds_reserved10; - uint16_t has_time1; - uint16_t has_date1; - uint16_t has_offset1; -} LS_TDS_DATETIMEALL; + uint64_t time; /**< time, 7 digit precision */ + int32_t date; /**< date, 0 = 1900-01-01 */ + int16_t offset; /**< time offset */ + uint16_t time_prec3; + uint16_t _tds_reserved10; + uint16_t has_time1; + uint16_t has_date1; + uint16_t has_offset1; +} LS_TDS_DATETIMEALL; #define LS_TDS_NUMERIC DBNUMERIC #define LS_INT_CANCEL INT_CANCEL typedef int LINKED_SERVER_RETCODE; -typedef LOGINREC *LinkedServerLogin; -typedef DBPROCESS *LinkedServerProcess; +typedef LOGINREC * LinkedServerLogin; +typedef DBPROCESS * LinkedServerProcess; #define LINKED_SERVER_INIT(void) dbinit(void) #define LINKED_SERVER_ERR_HANDLE(h) dberrhandle(h) diff --git a/contrib/babelfishpg_tsql/src/multidb.c b/contrib/babelfishpg_tsql/src/multidb.c index a4fce7d05d..bd509f82e2 100644 --- a/contrib/babelfishpg_tsql/src/multidb.c +++ b/contrib/babelfishpg_tsql/src/multidb.c @@ -19,15 +19,16 @@ /* rewrite function for data structures */ static void rewrite_rangevar(RangeVar *rv); static void rewrite_objectwithargs(ObjectWithArgs *obj); -void rewrite_plain_name(List *name); /* Value Strings */ +void rewrite_plain_name(List *name); /* Value Strings */ static void rewrite_schema_name(String *schema); static void rewrite_role_name(RoleSpec *role); -static void rewrite_rangevar_list(List *rvs); /* list of RangeVars */ -static void rewrite_objectwithargs_list(List *objs); /* list of ObjectWithArgs */ -static void rewrite_plain_name_list(List *names); /* list of plan names */ -static void rewrite_schema_name_list(List *schemas); /* list of schema names */ -static void rewrite_type_name_list(List *typenames); /* list of type names */ +static void rewrite_rangevar_list(List *rvs); /* list of RangeVars */ +static void rewrite_objectwithargs_list(List *objs); /* list of + * ObjectWithArgs */ +static void rewrite_plain_name_list(List *names); /* list of plan names */ +static void rewrite_schema_name_list(List *schemas); /* list of schema names */ +static void rewrite_type_name_list(List *typenames); /* list of type names */ static void rewrite_role_list(List *rolespecs); /* list of RoleSpecs */ static bool rewrite_relation_walker(Node *node, void *context); @@ -35,7 +36,7 @@ static bool rewrite_relation_walker(Node *node, void *context); static bool is_select_for_json(SelectStmt *stmt); static void select_json_modify(SelectStmt *stmt); static bool is_for_json(FuncCall *fc); -static bool get_array_wrapper(List* for_json_args); +static bool get_array_wrapper(List *for_json_args); @@ -46,7 +47,8 @@ static bool get_array_wrapper(List* for_json_args); bool enable_schema_mapping(void) { - if (!DbidIsValid(get_cur_db_id())) /* TODO: remove it after cur_db_oid() is enforeced */ + if (!DbidIsValid(get_cur_db_id())) /* TODO: remove it after cur_db_oid() + * is enforeced */ return false; if (!get_cur_db_name()) @@ -64,7 +66,7 @@ void rewrite_object_refs(Node *stmt) { /* - * TODO: Add check for mutlidb mode + * TODO: Add check for mutlidb mode */ if (sql_dialect != SQL_DIALECT_TSQL) @@ -73,574 +75,608 @@ rewrite_object_refs(Node *stmt) switch (stmt->type) { case T_SelectStmt: - { - SelectStmt* selectStmt = (SelectStmt*) stmt; - select_json_modify(selectStmt); - /* walker supported stmts */ - raw_expression_tree_walker(stmt, - rewrite_relation_walker, - (void *) NULL); - break; - } + { + SelectStmt *selectStmt = (SelectStmt *) stmt; + + select_json_modify(selectStmt); + /* walker supported stmts */ + raw_expression_tree_walker(stmt, + rewrite_relation_walker, + (void *) NULL); + break; + } case T_UpdateStmt: case T_DeleteStmt: case T_InsertStmt: - { - /* walker supported stmts */ - raw_expression_tree_walker(stmt, - rewrite_relation_walker, - (void *) NULL); - break; - } + { + /* walker supported stmts */ + raw_expression_tree_walker(stmt, + rewrite_relation_walker, + (void *) NULL); + break; + } case T_AlterTableStmt: - { - AlterTableStmt *alter_table = (AlterTableStmt *) stmt; - ListCell *c; - - rewrite_rangevar(alter_table->relation); - - foreach(c, alter_table->cmds) { - AlterTableCmd *cmd = lfirst(c); - - switch(cmd->subtype) - { - case AT_ColumnDefault: - { - ColumnDef *def = (ColumnDef *) cmd->def; + AlterTableStmt *alter_table = (AlterTableStmt *) stmt; + ListCell *c; - rewrite_relation_walker((Node *) def, (void *) NULL); - break; - } - case AT_AddColumn: - case AT_AlterColumnType: + rewrite_rangevar(alter_table->relation); + + foreach(c, alter_table->cmds) { - ColumnDef *def = (ColumnDef *) cmd->def; - ListCell *clist; + AlterTableCmd *cmd = lfirst(c); - foreach(clist, def->constraints) + switch (cmd->subtype) { - Constraint *constraint = lfirst_node(Constraint, clist); + case AT_ColumnDefault: + { + ColumnDef *def = (ColumnDef *) cmd->def; - rewrite_relation_walker(constraint->raw_expr, (void *) NULL); + rewrite_relation_walker((Node *) def, (void *) NULL); + break; + } + case AT_AddColumn: + case AT_AlterColumnType: + { + ColumnDef *def = (ColumnDef *) cmd->def; + ListCell *clist; - if (constraint->contype == CONSTR_FOREIGN) - rewrite_rangevar(constraint->pktable); - } - if (def->typeName) - { - TypeName *typename = (TypeName *) def->typeName; - rewrite_plain_name(typename->names); - } + foreach(clist, def->constraints) + { + Constraint *constraint = lfirst_node(Constraint, clist); - break; - } - case AT_AddConstraint: - { - Constraint *constraint = (Constraint *) cmd->def; + rewrite_relation_walker(constraint->raw_expr, (void *) NULL); - rewrite_relation_walker(constraint->raw_expr, (void *) NULL); + if (constraint->contype == CONSTR_FOREIGN) + rewrite_rangevar(constraint->pktable); + } + if (def->typeName) + { + TypeName *typename = (TypeName *) def->typeName; - if (constraint->contype == CONSTR_FOREIGN) - rewrite_rangevar(constraint->pktable); + rewrite_plain_name(typename->names); + } - break; - } - default: - break; + break; + } + case AT_AddConstraint: + { + Constraint *constraint = (Constraint *) cmd->def; + + rewrite_relation_walker(constraint->raw_expr, (void *) NULL); + + if (constraint->contype == CONSTR_FOREIGN) + rewrite_rangevar(constraint->pktable); + + break; + } + default: + break; + } } + break; } - break; - } case T_GrantStmt: - { - /* Grant / Revoke stmt share same structure */ - GrantStmt *grant = (GrantStmt *) stmt; - switch (grant->targtype) { - case ACL_TARGET_OBJECT: + /* Grant / Revoke stmt share same structure */ + GrantStmt *grant = (GrantStmt *) stmt; + + switch (grant->targtype) { - switch(grant->objtype) - { - case OBJECT_TABLE: - case OBJECT_SEQUENCE: - { - rewrite_rangevar_list(grant->objects); - break; - } - case OBJECT_FUNCTION: - case OBJECT_PROCEDURE: + case ACL_TARGET_OBJECT: { - rewrite_objectwithargs_list(grant->objects); + switch (grant->objtype) + { + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + { + rewrite_rangevar_list(grant->objects); + break; + } + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + { + rewrite_objectwithargs_list(grant->objects); + break; + } + case OBJECT_SCHEMA: + { + rewrite_schema_name_list(grant->objects); + break; + } + case OBJECT_TYPE: + { + rewrite_plain_name_list(grant->objects); + break; + } + default: + break; + } + rewrite_role_list(grant->grantees); break; } - case OBJECT_SCHEMA: + case ACL_TARGET_ALL_IN_SCHEMA: { rewrite_schema_name_list(grant->objects); break; } - case OBJECT_TYPE: - { - rewrite_plain_name_list(grant->objects); - break; - } - default: - break; - } - rewrite_role_list(grant->grantees); - break; - } - case ACL_TARGET_ALL_IN_SCHEMA: - { - rewrite_schema_name_list(grant->objects); - break; + default: + break; } - default: break; } - break; - } case T_GrantRoleStmt: - { - GrantRoleStmt *grant_role = (GrantRoleStmt *) stmt; - AccessPriv *granted; - RoleSpec *grantee; - char *role_name; - char *physical_role_name; - char *principal_name; - char *physical_principal_name; - char *db_name = get_cur_db_name(); - - /* Check if this is ALTER ROLE statement */ - if (list_length(grant_role->granted_roles) != 1 || - list_length(grant_role->grantee_roles) != 1) - break; - - granted = (AccessPriv *) linitial(grant_role->granted_roles); - role_name = granted->priv_name; - - /* Forbidden ALTER ROLE db_owner ADD/DROP MEMBER */ - if (strcmp(role_name, "db_owner") == 0) { - if (grant_role->is_grant) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Adding members to db_owner is not currently supported " - "in Babelfish"))); - else - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Dropping members to db_owner is not currently supported " - "in Babelfish"))); - } + GrantRoleStmt *grant_role = (GrantRoleStmt *) stmt; + AccessPriv *granted; + RoleSpec *grantee; + char *role_name; + char *physical_role_name; + char *principal_name; + char *physical_principal_name; + char *db_name = get_cur_db_name(); + + /* Check if this is ALTER ROLE statement */ + if (list_length(grant_role->granted_roles) != 1 || + list_length(grant_role->grantee_roles) != 1) + break; - /* Try to get physical granted role name, see if it's an existing db role */ - physical_role_name = get_physical_user_name(db_name, role_name); - if (get_role_oid(physical_role_name, true) == InvalidOid) - break; + granted = (AccessPriv *) linitial(grant_role->granted_roles); + role_name = granted->priv_name; - /* This is ALTER ROLE statement */ - grantee = (RoleSpec *) linitial(grant_role->grantee_roles); - principal_name = grantee->rolename; + /* Forbidden ALTER ROLE db_owner ADD/DROP MEMBER */ + if (strcmp(role_name, "db_owner") == 0) + { + if (grant_role->is_grant) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Adding members to db_owner is not currently supported " + "in Babelfish"))); + else + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Dropping members to db_owner is not currently supported " + "in Babelfish"))); + } - /* Forbidden the use of some special principals */ - if (strcmp(principal_name, "dbo") == 0 || - strcmp(principal_name, "db_owner") == 0) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Cannot use the special principal '%s'", principal_name))); + /* + * Try to get physical granted role name, see if it's an + * existing db role + */ + physical_role_name = get_physical_user_name(db_name, role_name); + if (get_role_oid(physical_role_name, true) == InvalidOid) + break; - /* Rewrite granted and grantee roles */ - pfree(granted->priv_name); - granted->priv_name = physical_role_name; + /* This is ALTER ROLE statement */ + grantee = (RoleSpec *) linitial(grant_role->grantee_roles); + principal_name = grantee->rolename; - physical_principal_name = get_physical_user_name(db_name, principal_name); - pfree(grantee->rolename); - grantee->rolename = physical_principal_name; + /* Forbidden the use of some special principals */ + if (strcmp(principal_name, "dbo") == 0 || + strcmp(principal_name, "db_owner") == 0) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Cannot use the special principal '%s'", principal_name))); - break; - } - case T_CreateStmt: - { - CreateStmt *create = (CreateStmt *) stmt; - ListCell *elements; + /* Rewrite granted and grantee roles */ + pfree(granted->priv_name); + granted->priv_name = physical_role_name; - rewrite_rangevar(create->relation); + physical_principal_name = get_physical_user_name(db_name, principal_name); + pfree(grantee->rolename); + grantee->rolename = physical_principal_name; - foreach(elements, create->tableElts) + break; + } + case T_CreateStmt: { - Node *element = lfirst(elements); + CreateStmt *create = (CreateStmt *) stmt; + ListCell *elements; - switch (nodeTag(element)) + rewrite_rangevar(create->relation); + + foreach(elements, create->tableElts) { - case T_ColumnDef: + Node *element = lfirst(elements); + + switch (nodeTag(element)) { - ColumnDef *def = (ColumnDef *) element; - ListCell *clist; - - foreach(clist, def->constraints) - { - Constraint *constraint = lfirst_node(Constraint, clist); + case T_ColumnDef: + { + ColumnDef *def = (ColumnDef *) element; + ListCell *clist; - rewrite_relation_walker(constraint->raw_expr, (void *) NULL); + foreach(clist, def->constraints) + { + Constraint *constraint = lfirst_node(Constraint, clist); - if (constraint->contype == CONSTR_FOREIGN) - rewrite_rangevar(constraint->pktable); - } - if (def->typeName) - { - TypeName *typename = (TypeName *) def->typeName; - rewrite_plain_name(typename->names); - } - break; - } - case T_Constraint: - { - Constraint *constraint = (Constraint*) element; - if (constraint->contype == CONSTR_FOREIGN) - rewrite_rangevar(constraint->pktable); - break; + rewrite_relation_walker(constraint->raw_expr, (void *) NULL); + + if (constraint->contype == CONSTR_FOREIGN) + rewrite_rangevar(constraint->pktable); + } + if (def->typeName) + { + TypeName *typename = (TypeName *) def->typeName; + + rewrite_plain_name(typename->names); + } + break; + } + case T_Constraint: + { + Constraint *constraint = (Constraint *) element; + + if (constraint->contype == CONSTR_FOREIGN) + rewrite_rangevar(constraint->pktable); + break; + } + default: + break; } - default: - break; } + break; } - break; - } case T_CreateRoleStmt: - { - CreateRoleStmt *create_role = (CreateRoleStmt *) stmt; - - if (create_role->options != NIL) { - DefElem *headel = (DefElem *) linitial(create_role->options); + CreateRoleStmt *create_role = (CreateRoleStmt *) stmt; - if (strcmp(headel->defname, "isuser") == 0 || - strcmp(headel->defname, "isrole") == 0) + if (create_role->options != NIL) { - ListCell *option; - char *user_name; - char *db_name = get_cur_db_name(); - - user_name = get_physical_user_name(db_name, create_role->role); - pfree(create_role->role); - create_role->role = user_name; + DefElem *headel = (DefElem *) linitial(create_role->options); - foreach (option, create_role->options) + if (strcmp(headel->defname, "isuser") == 0 || + strcmp(headel->defname, "isrole") == 0) { - DefElem *defel = (DefElem *) lfirst(option); + ListCell *option; + char *user_name; + char *db_name = get_cur_db_name(); - if (strcmp(defel->defname, "rolemembers") == 0) - { - RoleSpec *spec; + user_name = get_physical_user_name(db_name, create_role->role); + pfree(create_role->role); + create_role->role = user_name; - spec = makeNode(RoleSpec); - spec->roletype = ROLESPEC_CSTRING; - spec->location = -1; - spec->rolename = pstrdup(get_db_owner_name(db_name)); + foreach(option, create_role->options) + { + DefElem *defel = (DefElem *) lfirst(option); - if (defel->arg == NULL) - defel->arg = (Node *) list_make1(spec); - else + if (strcmp(defel->defname, "rolemembers") == 0) { - List *rolemembers = NIL; - rolemembers = (List *) defel->arg; - rolemembers = lappend(rolemembers, spec); + RoleSpec *spec; + + spec = makeNode(RoleSpec); + spec->roletype = ROLESPEC_CSTRING; + spec->location = -1; + spec->rolename = pstrdup(get_db_owner_name(db_name)); + + if (defel->arg == NULL) + defel->arg = (Node *) list_make1(spec); + else + { + List *rolemembers = NIL; + + rolemembers = (List *) defel->arg; + rolemembers = lappend(rolemembers, spec); + } } } } } + break; } - break; - } case T_AlterRoleStmt: - { - AlterRoleStmt *alter_role = (AlterRoleStmt *) stmt; - - if (alter_role->options != NIL) { - DefElem *headel = (DefElem *) linitial(alter_role->options); + AlterRoleStmt *alter_role = (AlterRoleStmt *) stmt; - if (strcmp(headel->defname, "isuser") == 0 || - strcmp(headel->defname, "isrole") == 0) + if (alter_role->options != NIL) { - char *user_name; - char *physical_user_name; - char *db_name = get_cur_db_name(); - - user_name = alter_role->role->rolename; - /* TODO: allow ALTER ROLE db_owner */ - if (strcmp(user_name, "dbo") == 0 || - strcmp(user_name, "db_owner") == 0 || - strcmp(user_name, "guest") == 0) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Cannot alter the user %s", user_name))); + DefElem *headel = (DefElem *) linitial(alter_role->options); - physical_user_name = get_physical_user_name(db_name, user_name); - pfree(alter_role->role->rolename); - alter_role->role->rolename = physical_user_name; + if (strcmp(headel->defname, "isuser") == 0 || + strcmp(headel->defname, "isrole") == 0) + { + char *user_name; + char *physical_user_name; + char *db_name = get_cur_db_name(); + + user_name = alter_role->role->rolename; + /* TODO: allow ALTER ROLE db_owner */ + if (strcmp(user_name, "dbo") == 0 || + strcmp(user_name, "db_owner") == 0 || + strcmp(user_name, "guest") == 0) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Cannot alter the user %s", user_name))); + + physical_user_name = get_physical_user_name(db_name, user_name); + pfree(alter_role->role->rolename); + alter_role->role->rolename = physical_user_name; + } } + break; } - break; - } case T_DropStmt: - { - DropStmt *drop = (DropStmt *) stmt; - switch(drop->removeType) { - case OBJECT_TABLE: - case OBJECT_SEQUENCE: - case OBJECT_VIEW: - case OBJECT_MATVIEW: - case OBJECT_INDEX: - { - rewrite_plain_name_list(drop->objects); - break; - } - case OBJECT_TYPE: - { - rewrite_type_name_list(drop->objects); - break; - } - case OBJECT_SCHEMA: - { - rewrite_schema_name_list(drop->objects); - break; - } - case OBJECT_TRIGGER: - { - rewrite_plain_name((List *) lfirst(list_head(drop->objects))); - break; - } - case OBJECT_FUNCTION: - case OBJECT_PROCEDURE: + DropStmt *drop = (DropStmt *) stmt; + + switch (drop->removeType) { - rewrite_objectwithargs_list(drop->objects); - break; + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_INDEX: + { + rewrite_plain_name_list(drop->objects); + break; + } + case OBJECT_TYPE: + { + rewrite_type_name_list(drop->objects); + break; + } + case OBJECT_SCHEMA: + { + rewrite_schema_name_list(drop->objects); + break; + } + case OBJECT_TRIGGER: + { + rewrite_plain_name((List *) lfirst(list_head(drop->objects))); + break; + } + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + { + rewrite_objectwithargs_list(drop->objects); + break; + } + default: + break; } - default: - break; + break; } - break; - } case T_TruncateStmt: - { - TruncateStmt *truncate = (TruncateStmt *) stmt; - rewrite_rangevar_list(truncate->relations); - break; - } - case T_IndexStmt: - { - IndexStmt *index = (IndexStmt *) stmt; - rewrite_rangevar(index->relation); - break; - } - case T_CreateFunctionStmt: - { - CreateFunctionStmt *create_func = (CreateFunctionStmt *) stmt; - ListCell *cell; - - /* handle arguments */ - foreach(cell, create_func->parameters) { - FunctionParameter *p = (FunctionParameter *) lfirst(cell); - TypeName *typename = p->argType; + TruncateStmt *truncate = (TruncateStmt *) stmt; - /* handle type */ - rewrite_plain_name(typename->names); - - /* default value */ - rewrite_relation_walker(p->defexpr, (void *) NULL); + rewrite_rangevar_list(truncate->relations); + break; } + case T_IndexStmt: + { + IndexStmt *index = (IndexStmt *) stmt; - rewrite_plain_name(create_func->funcname); - if (list_length(create_func->options) >= 3) + rewrite_rangevar(index->relation); + break; + } + case T_CreateFunctionStmt: { - DefElem *defElem = (DefElem *) lthird(create_func->options); - if (strncmp(defElem->defname, "trigStmt", 8) == 0) + CreateFunctionStmt *create_func = (CreateFunctionStmt *) stmt; + ListCell *cell; + + /* handle arguments */ + foreach(cell, create_func->parameters) { - CreateTrigStmt *create_trigger = (CreateTrigStmt *) defElem->arg; - rewrite_rangevar(create_trigger->relation); + FunctionParameter *p = (FunctionParameter *) lfirst(cell); + TypeName *typename = p->argType; + + /* handle type */ + rewrite_plain_name(typename->names); + + /* default value */ + rewrite_relation_walker(p->defexpr, (void *) NULL); } - else if (strncmp(defElem->defname, "tbltypStmt", 10) == 0) + + rewrite_plain_name(create_func->funcname); + if (list_length(create_func->options) >= 3) { - CreateStmt *tbltypStmt = (CreateStmt *) defElem->arg; - rewrite_rangevar(tbltypStmt->relation); + DefElem *defElem = (DefElem *) lthird(create_func->options); + + if (strncmp(defElem->defname, "trigStmt", 8) == 0) + { + CreateTrigStmt *create_trigger = (CreateTrigStmt *) defElem->arg; + + rewrite_rangevar(create_trigger->relation); + } + else if (strncmp(defElem->defname, "tbltypStmt", 10) == 0) + { + CreateStmt *tbltypStmt = (CreateStmt *) defElem->arg; + + rewrite_rangevar(tbltypStmt->relation); + } } + break; } - break; - } case T_AlterFunctionStmt: - { - AlterFunctionStmt *alter_func = (AlterFunctionStmt *) stmt; - rewrite_objectwithargs(alter_func->func); - break; - } + { + AlterFunctionStmt *alter_func = (AlterFunctionStmt *) stmt; + + rewrite_objectwithargs(alter_func->func); + break; + } case T_RenameStmt: - { - RenameStmt *rename = (RenameStmt *) stmt; - switch (rename->renameType) { - case OBJECT_FUNCTION: - case OBJECT_PROCEDURE: - case OBJECT_TYPE: - { - rewrite_objectwithargs((ObjectWithArgs *) rename->object); - break; - } - case OBJECT_SCHEMA: + RenameStmt *rename = (RenameStmt *) stmt; + + switch (rename->renameType) { - char *cur_db = get_cur_db_name(); - rename->subname = get_physical_schema_name(cur_db, rename->subname); - rename->newname = get_physical_schema_name(cur_db, rename->newname); - break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_TYPE: + { + rewrite_objectwithargs((ObjectWithArgs *) rename->object); + break; + } + case OBJECT_SCHEMA: + { + char *cur_db = get_cur_db_name(); + + rename->subname = get_physical_schema_name(cur_db, rename->subname); + rename->newname = get_physical_schema_name(cur_db, rename->newname); + break; + } + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_INDEX: + case OBJECT_COLUMN: + case OBJECT_TABCONSTRAINT: + case OBJECT_TRIGGER: + rewrite_rangevar(rename->relation); + break; + default: + break; } - case OBJECT_TABLE: - case OBJECT_SEQUENCE: - case OBJECT_VIEW: - case OBJECT_MATVIEW: - case OBJECT_INDEX: - case OBJECT_COLUMN: - case OBJECT_TABCONSTRAINT: - case OBJECT_TRIGGER: - rewrite_rangevar(rename->relation); - break; - default: - break; + break; } - break; - } case T_ViewStmt: - { - ViewStmt *view = (ViewStmt *) stmt; - rewrite_rangevar(view->view); - break; - } + { + ViewStmt *view = (ViewStmt *) stmt; + + rewrite_rangevar(view->view); + break; + } case T_CreateTableAsStmt: - { - CreateTableAsStmt *ctas = (CreateTableAsStmt *) stmt; - rewrite_rangevar(ctas->into->rel); - break; - } + { + CreateTableAsStmt *ctas = (CreateTableAsStmt *) stmt; + + rewrite_rangevar(ctas->into->rel); + break; + } case T_CreateSeqStmt: - { - CreateSeqStmt *create_seq = (CreateSeqStmt *) stmt; - rewrite_rangevar(create_seq->sequence); - break; - } + { + CreateSeqStmt *create_seq = (CreateSeqStmt *) stmt; + + rewrite_rangevar(create_seq->sequence); + break; + } case T_AlterSeqStmt: - { - AlterSeqStmt *alter_seq = (AlterSeqStmt *) stmt; - rewrite_rangevar(alter_seq->sequence); - break; - } + { + AlterSeqStmt *alter_seq = (AlterSeqStmt *) stmt; + + rewrite_rangevar(alter_seq->sequence); + break; + } case T_CreateTrigStmt: - { - CreateTrigStmt *create_trig = (CreateTrigStmt *) stmt; - rewrite_rangevar(create_trig->relation); - rewrite_plain_name(create_trig->funcname); - break; - } + { + CreateTrigStmt *create_trig = (CreateTrigStmt *) stmt; + + rewrite_rangevar(create_trig->relation); + rewrite_plain_name(create_trig->funcname); + break; + } case T_CreateSchemaStmt: - { - CreateSchemaStmt *create_schema = (CreateSchemaStmt *) stmt; - char *cur_db = get_cur_db_name(); - create_schema->schemaname = get_physical_schema_name(cur_db, create_schema->schemaname); - if (create_schema->authrole) - rewrite_role_name(create_schema->authrole); - break; - } + { + CreateSchemaStmt *create_schema = (CreateSchemaStmt *) stmt; + char *cur_db = get_cur_db_name(); + + create_schema->schemaname = get_physical_schema_name(cur_db, create_schema->schemaname); + if (create_schema->authrole) + rewrite_role_name(create_schema->authrole); + break; + } case T_AlterOwnerStmt: - { - AlterOwnerStmt *alter_owner = (AlterOwnerStmt *) stmt; - switch (alter_owner->objectType) { - case OBJECT_AGGREGATE: - case OBJECT_FUNCTION: - case OBJECT_PROCEDURE: - rewrite_objectwithargs((ObjectWithArgs *) alter_owner->object); - break; - case OBJECT_TABLE: - case OBJECT_SEQUENCE: - case OBJECT_VIEW: - case OBJECT_MATVIEW: - case OBJECT_INDEX: - case OBJECT_COLUMN: - case OBJECT_TABCONSTRAINT: - case OBJECT_TRIGGER: - rewrite_rangevar((RangeVar *) alter_owner->object); - break; - case OBJECT_SCHEMA: - { - rewrite_schema_name((String *) alter_owner->object); - break; - } - case OBJECT_TYPE: + AlterOwnerStmt *alter_owner = (AlterOwnerStmt *) stmt; + + switch (alter_owner->objectType) { - rewrite_plain_name((List *) alter_owner->object); - break; + case OBJECT_AGGREGATE: + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + rewrite_objectwithargs((ObjectWithArgs *) alter_owner->object); + break; + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_INDEX: + case OBJECT_COLUMN: + case OBJECT_TABCONSTRAINT: + case OBJECT_TRIGGER: + rewrite_rangevar((RangeVar *) alter_owner->object); + break; + case OBJECT_SCHEMA: + { + rewrite_schema_name((String *) alter_owner->object); + break; + } + case OBJECT_TYPE: + { + rewrite_plain_name((List *) alter_owner->object); + break; + } + default: + break; } - default: - break; + break; } - break; - } case T_CreateStatsStmt: - { - CreateStatsStmt *create_stats = (CreateStatsStmt *) stmt; - rewrite_rangevar_list(create_stats->relations); - break; - } + { + CreateStatsStmt *create_stats = (CreateStatsStmt *) stmt; + + rewrite_rangevar_list(create_stats->relations); + break; + } case T_CallStmt: - { - CallStmt *call = (CallStmt *) stmt; - rewrite_plain_name(call->funccall->funcname); - break; - } + { + CallStmt *call = (CallStmt *) stmt; + + rewrite_plain_name(call->funccall->funcname); + break; + } case T_DefineStmt: - { - DefineStmt *define_stmt = (DefineStmt *) stmt; - rewrite_plain_name(define_stmt->defnames); - break; - } + { + DefineStmt *define_stmt = (DefineStmt *) stmt; + + rewrite_plain_name(define_stmt->defnames); + break; + } case T_CompositeTypeStmt: - { - CompositeTypeStmt *comp_type_stmt = (CompositeTypeStmt *) stmt; - rewrite_rangevar(comp_type_stmt->typevar); - break; - } + { + CompositeTypeStmt *comp_type_stmt = (CompositeTypeStmt *) stmt; + + rewrite_rangevar(comp_type_stmt->typevar); + break; + } case T_CreateEnumStmt: - { - CreateEnumStmt *enum_stmt = (CreateEnumStmt *) stmt; - rewrite_plain_name(enum_stmt->typeName); - break; - } + { + CreateEnumStmt *enum_stmt = (CreateEnumStmt *) stmt; + + rewrite_plain_name(enum_stmt->typeName); + break; + } case T_CreateRangeStmt: - { - CreateRangeStmt *create_range = (CreateRangeStmt *) stmt; - rewrite_plain_name(create_range->typeName); - break; - } + { + CreateRangeStmt *create_range = (CreateRangeStmt *) stmt; + + rewrite_plain_name(create_range->typeName); + break; + } case T_AlterEnumStmt: - { - AlterEnumStmt *alter_enum = (AlterEnumStmt *) stmt; - rewrite_plain_name(alter_enum->typeName); - break; - } + { + AlterEnumStmt *alter_enum = (AlterEnumStmt *) stmt; + + rewrite_plain_name(alter_enum->typeName); + break; + } case T_AlterTypeStmt: - { - AlterTypeStmt *alter_type = (AlterTypeStmt *) stmt; - rewrite_plain_name(alter_type->typeName); - break; - } + { + AlterTypeStmt *alter_type = (AlterTypeStmt *) stmt; + + rewrite_plain_name(alter_type->typeName); + break; + } case T_CreateDomainStmt: - { - CreateDomainStmt *create_domain = (CreateDomainStmt *) stmt; - rewrite_plain_name(create_domain->domainname); - rewrite_plain_name(create_domain->typeName->names); - break; - } + { + CreateDomainStmt *create_domain = (CreateDomainStmt *) stmt; + + rewrite_plain_name(create_domain->domainname); + rewrite_plain_name(create_domain->typeName->names); + break; + } default: break; } @@ -652,32 +688,36 @@ rewrite_relation_walker(Node *node, void *context) if (!node) return false; - if (IsA(node, RangeVar)) - { - RangeVar *rv = (RangeVar *) node; + if (IsA(node, RangeVar)) + { + RangeVar *rv = (RangeVar *) node; + rewrite_rangevar(rv); return false; } if (IsA(node, ColumnRef)) { - ColumnRef *ref = (ColumnRef *) node; + ColumnRef *ref = (ColumnRef *) node; + rewrite_column_refs(ref); return false; } if (IsA(node, FuncCall)) { - FuncCall *func = (FuncCall *) node; + FuncCall *func = (FuncCall *) node; + rewrite_plain_name(func->funcname); - return raw_expression_tree_walker(node, rewrite_relation_walker, context); + return raw_expression_tree_walker(node, rewrite_relation_walker, context); } if (IsA(node, TypeName)) { - TypeName *typename = (TypeName *) node; + TypeName *typename = (TypeName *) node; + rewrite_plain_name(typename->names); return false; } else - return raw_expression_tree_walker(node, rewrite_relation_walker, context); + return raw_expression_tree_walker(node, rewrite_relation_walker, context); } /* @@ -686,27 +726,33 @@ rewrite_relation_walker(Node *node, void *context) * parameter to true * Otherwise we set it to false */ -static void select_json_modify(SelectStmt* stmt) +static void +select_json_modify(SelectStmt *stmt) { - List* targList = stmt->targetList; - List* fromList = stmt->fromClause; - if(list_length(targList) != 0 && list_length(fromList) != 0) + List *targList = stmt->targetList; + List *fromList = stmt->fromClause; + + if (list_length(targList) != 0 && list_length(fromList) != 0) { - Node* n = linitial(targList); - Node* n_from = linitial(fromList); - if(IsA(n, ResTarget) && IsA(n_from, RangeSubselect)) + Node *n = linitial(targList); + Node *n_from = linitial(fromList); + + if (IsA(n, ResTarget) && IsA(n_from, RangeSubselect)) { - ResTarget* rt = (ResTarget*) n; - RangeSubselect* rs = (RangeSubselect*) n_from; - if(IsA(rt->val, FuncCall) && IsA(rs->subquery, SelectStmt)) + ResTarget *rt = (ResTarget *) n; + RangeSubselect *rs = (RangeSubselect *) n_from; + + if (IsA(rt->val, FuncCall) && IsA(rs->subquery, SelectStmt)) { - FuncCall* json_mod_fc = (FuncCall*) rt->val; - SelectStmt* from_sel_stmt = (SelectStmt*) rs->subquery; + FuncCall *json_mod_fc = (FuncCall *) rt->val; + SelectStmt *from_sel_stmt = (SelectStmt *) rs->subquery; + rewrite_plain_name(json_mod_fc->funcname); - if(is_json_modify(json_mod_fc->funcname) && is_select_for_json(from_sel_stmt)) + if (is_json_modify(json_mod_fc->funcname) && is_select_for_json(from_sel_stmt)) { - Node *n = lfourth(json_mod_fc->args); - A_Const *escape = (A_Const*) n; + Node *n = lfourth(json_mod_fc->args); + A_Const *escape = (A_Const *) n; + escape->val.boolval.boolval = true; } } @@ -722,27 +768,29 @@ static void select_json_modify(SelectStmt* stmt) bool is_json_modify(List *name) { - switch(list_length(name)) - { - case 1: - { - Node *func = (Node *) linitial(name); - if(strncmp("json_modify", strVal(func), 11) == 0) - return true; - return false; - } - case 2: - { - Node *schema = (Node *) linitial(name); - Node *func = (Node *) lsecond(name); - if(strncmp("sys", strVal(schema), 3) == 0 && - strncmp("json_modify", strVal(func), 11) == 0) - return true; - return false; - } - default: - return false; - } + switch (list_length(name)) + { + case 1: + { + Node *func = (Node *) linitial(name); + + if (strncmp("json_modify", strVal(func), 11) == 0) + return true; + return false; + } + case 2: + { + Node *schema = (Node *) linitial(name); + Node *func = (Node *) lsecond(name); + + if (strncmp("sys", strVal(schema), 3) == 0 && + strncmp("json_modify", strVal(func), 11) == 0) + return true; + return false; + } + default: + return false; + } } /* @@ -750,21 +798,25 @@ is_json_modify(List *name) * returns true if the target function call is for json and array_wrapper is false * returns false otherwise */ -static bool is_select_for_json(SelectStmt *stmt) +static bool +is_select_for_json(SelectStmt *stmt) { - List* targetList = stmt->targetList; - ListCell* lc = (ListCell*) targetList->elements; - Node* n = lfirst(lc); - if(IsA(n, ResTarget)) - { - ResTarget* rt = (ResTarget*) n; - if(IsA(rt->val, FuncCall)) - { - FuncCall* fc = (FuncCall*) rt->val; - return is_for_json(fc); - } - } - return false; + List *targetList = stmt->targetList; + ListCell *lc = (ListCell *) targetList->elements; + Node *n = lfirst(lc); + + if (IsA(n, ResTarget)) + { + ResTarget *rt = (ResTarget *) n; + + if (IsA(rt->val, FuncCall)) + { + FuncCall *fc = (FuncCall *) rt->val; + + return is_for_json(fc); + } + } + return false; } /* @@ -775,27 +827,34 @@ static bool is_select_for_json(SelectStmt *stmt) static bool is_for_json(FuncCall *fc) { - // In this case, we need to check that the function name is correct, and also that the without_array_wrapper param is not true - List* funcname = fc->funcname; - List* fc_args = fc->args; - - switch(list_length(funcname)) - { - case 2: - { - Node *schema = (Node *) linitial(funcname); - Node *func = (Node *) lsecond(funcname); - if(strncmp("sys", strVal(schema), 3) == 0 && - strncmp("tsql_select_for_json_result", strVal(func), 27) == 0) - { - // If without array wrapper is true, we want to keep the escape characters so we return false - return !get_array_wrapper(fc_args); - } - return false; - } - default: - return false; - } + /* + * In this case, we need to check that the function name is correct, and + * also that the without_array_wrapper param is not true + */ + List *funcname = fc->funcname; + List *fc_args = fc->args; + + switch (list_length(funcname)) + { + case 2: + { + Node *schema = (Node *) linitial(funcname); + Node *func = (Node *) lsecond(funcname); + + if (strncmp("sys", strVal(schema), 3) == 0 && + strncmp("tsql_select_for_json_result", strVal(func), 27) == 0) + { + /* + * If without array wrapper is true, we want to keep the + * escape characters so we return false + */ + return !get_array_wrapper(fc_args); + } + return false; + } + default: + return false; + } } /* @@ -803,12 +862,15 @@ is_for_json(FuncCall *fc) * and returns the value of the array_wrapper parameter. It is the caller's responsibility * to ensure they are passing the correct input */ -static bool get_array_wrapper(List* for_json_args) { - FuncCall* agg_fc = (FuncCall *) linitial(for_json_args); - List* agg_fc_args = agg_fc->args; +static bool +get_array_wrapper(List *for_json_args) +{ + FuncCall *agg_fc = (FuncCall *) linitial(for_json_args); + List *agg_fc_args = agg_fc->args; + + Node *arr_wrap = lfourth(agg_fc_args); - Node* arr_wrap = lfourth(agg_fc_args); - return ((A_Const*) arr_wrap)->val.boolval.boolval; + return ((A_Const *) arr_wrap)->val.boolval.boolval; } /************************************************************* @@ -817,42 +879,43 @@ static bool get_array_wrapper(List* for_json_args) { void rewrite_column_refs(ColumnRef *cref) -{ +{ switch (list_length(cref->fields)) { case 3: - { - Node *schema = (Node *) linitial(cref->fields); - char *cur_db = get_cur_db_name(); - String *new_schema; - - if (is_shared_schema(strVal(schema))) - break; /* do not thing for shared schemas */ - else { - new_schema = makeString(get_physical_schema_name(cur_db, strVal(schema))); - cref->fields = list_delete_first(cref->fields); - cref->fields = lcons(new_schema, cref->fields); + Node *schema = (Node *) linitial(cref->fields); + char *cur_db = get_cur_db_name(); + String *new_schema; + + if (is_shared_schema(strVal(schema))) + break; /* do not thing for shared schemas */ + else + { + new_schema = makeString(get_physical_schema_name(cur_db, strVal(schema))); + cref->fields = list_delete_first(cref->fields); + cref->fields = lcons(new_schema, cref->fields); + } + break; } - break; - } case 4: - { - Node *db = (Node *) linitial(cref->fields); - Node *schema = (Node *) lsecond(cref->fields); - String *new_schema; - - if (is_shared_schema(strVal(schema))) - cref->fields = list_delete_first(cref->fields); /* redirect to shared schema */ - else { - new_schema = makeString(get_physical_schema_name(strVal(db), strVal(schema))); - cref->fields = list_delete_first(cref->fields); - cref->fields = list_delete_first(cref->fields); - cref->fields = lcons(new_schema, cref->fields); + Node *db = (Node *) linitial(cref->fields); + Node *schema = (Node *) lsecond(cref->fields); + String *new_schema; + + if (is_shared_schema(strVal(schema))) + cref->fields = list_delete_first(cref->fields); /* redirect to shared + * schema */ + else + { + new_schema = makeString(get_physical_schema_name(strVal(db), strVal(schema))); + cref->fields = list_delete_first(cref->fields); + cref->fields = list_delete_first(cref->fields); + cref->fields = lcons(new_schema, cref->fields); + } + break; } - break; - } default: break; } @@ -864,7 +927,7 @@ rewrite_rangevar(RangeVar *rv) if (rv->catalogname) { if (is_shared_schema(rv->schemaname)) - rv->catalogname = NULL; /* redirect to shared schema */ + rv->catalogname = NULL; /* redirect to shared schema */ else { rv->schemaname = get_physical_schema_name(rv->catalogname, rv->schemaname); @@ -874,10 +937,11 @@ rewrite_rangevar(RangeVar *rv) else if (rv->schemaname) { if (is_shared_schema(rv->schemaname)) - return; /* do not thing for shared schemas */ + return; /* do not thing for shared schemas */ else { - char *cur_db = get_cur_db_name(); + char *cur_db = get_cur_db_name(); + rv->schemaname = get_physical_schema_name(cur_db, rv->schemaname); } } @@ -895,40 +959,49 @@ rewrite_plain_name(List *name) switch (list_length(name)) { case 2: - { - Node *schema = (Node *) linitial(name); - char *cur_db = get_cur_db_name(); - String *new_schema; - - if (is_shared_schema(strVal(schema))) - break; /* do not thing for shared schemas */ + { + Node *schema = (Node *) linitial(name); + char *cur_db = get_cur_db_name(); + String *new_schema; - new_schema = makeString(get_physical_schema_name(cur_db, strVal(schema))); - /* ignoring the return value sinece list is valid and cannot be empty */ - name = list_delete_first(name); - name = lcons(new_schema, name); - break; - } - case 3: - { - Node *db = (Node *) linitial(name); - Node *schema = (Node *) lsecond(name); - String *new_schema; + if (is_shared_schema(strVal(schema))) + break; /* do not thing for shared schemas */ + new_schema = makeString(get_physical_schema_name(cur_db, strVal(schema))); - /* do nothing for shared schemas */ - if (is_shared_schema(strVal(schema))) - name = list_delete_first(name); /* redirect to shared SYS schema */ - else - { - new_schema = makeString(get_physical_schema_name(strVal(db), strVal(schema))); - /* ignoring the return value sinece list is valid and cannot be empty */ - name = list_delete_first(name); + /* + * ignoring the return value sinece list is valid and cannot + * be empty + */ name = list_delete_first(name); name = lcons(new_schema, name); + break; + } + case 3: + { + Node *db = (Node *) linitial(name); + Node *schema = (Node *) lsecond(name); + String *new_schema; + + + /* do nothing for shared schemas */ + if (is_shared_schema(strVal(schema))) + name = list_delete_first(name); /* redirect to shared SYS + * schema */ + else + { + new_schema = makeString(get_physical_schema_name(strVal(db), strVal(schema))); + + /* + * ignoring the return value sinece list is valid and + * cannot be empty + */ + name = list_delete_first(name); + name = list_delete_first(name); + name = lcons(new_schema, name); + } + break; } - break; - } default: break; } @@ -937,7 +1010,7 @@ rewrite_plain_name(List *name) static void rewrite_schema_name(String *schema) { - char *cur_db = get_cur_db_name(); + char *cur_db = get_cur_db_name(); /* do nothing for shared schemas */ if (is_shared_schema(strVal(schema))) @@ -948,26 +1021,27 @@ rewrite_schema_name(String *schema) static void rewrite_role_name(RoleSpec *role) { - char *cur_db = get_cur_db_name(); + char *cur_db = get_cur_db_name(); + role->rolename = get_physical_user_name(cur_db, role->rolename); } bool is_shared_schema(const char *name) { - if ((strcmp("sys", name ) == 0) - || (strcmp("information_schema_tsql", name) == 0)) - return true; /* babelfish shared schema */ + if ((strcmp("sys", name) == 0) + || (strcmp("information_schema_tsql", name) == 0)) + return true; /* babelfish shared schema */ else if ((strcmp("public", name) == 0) - || (strcmp("pg_catalog", name) == 0) - || (strcmp("pg_toast", name) == 0) - || (strcmp("information_schema", name) == 0)) - return true; /* PG shared schemas */ + || (strcmp("pg_catalog", name) == 0) + || (strcmp("pg_toast", name) == 0) + || (strcmp("information_schema", name) == 0)) + return true; /* PG shared schemas */ else if ((strcmp("aws_commons", name) == 0) - || (strcmp("aws_s3", name) == 0) - || (strcmp("aws_lambda", name) == 0) - || (strcmp("pglogical", name) == 0)) - return true; /* extension schemas */ + || (strcmp("aws_s3", name) == 0) + || (strcmp("aws_lambda", name) == 0) + || (strcmp("pglogical", name) == 0)) + return true; /* extension schemas */ else return false; } @@ -976,8 +1050,8 @@ PG_FUNCTION_INFO_V1(is_shared_schema_wrapper); Datum is_shared_schema_wrapper(PG_FUNCTION_ARGS) { - char *schema_name; - bool shared_schema; + char *schema_name; + bool shared_schema; schema_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); shared_schema = is_shared_schema(schema_name); @@ -988,11 +1062,12 @@ is_shared_schema_wrapper(PG_FUNCTION_ARGS) static void rewrite_rangevar_list(List *rvs) { - ListCell *cell; + ListCell *cell; foreach(cell, rvs) { RangeVar *rv = (RangeVar *) lfirst(cell); + rewrite_rangevar(rv); } } @@ -1000,11 +1075,12 @@ rewrite_rangevar_list(List *rvs) static void rewrite_objectwithargs_list(List *objs) { - ListCell *cell; + ListCell *cell; foreach(cell, objs) { ObjectWithArgs *obj = (ObjectWithArgs *) lfirst(cell); + rewrite_objectwithargs(obj); } } @@ -1012,7 +1088,7 @@ rewrite_objectwithargs_list(List *objs) static void rewrite_plain_name_list(List *names) { - ListCell *cell; + ListCell *cell; foreach(cell, names) { @@ -1023,11 +1099,12 @@ rewrite_plain_name_list(List *names) static void rewrite_schema_name_list(List *schemas) { - ListCell *cell; + ListCell *cell; foreach(cell, schemas) { - String *schema = (String *) lfirst(cell); + String *schema = (String *) lfirst(cell); + rewrite_schema_name(schema); } } @@ -1035,23 +1112,25 @@ rewrite_schema_name_list(List *schemas) static void rewrite_type_name_list(List *typenames) { - ListCell *cell; + ListCell *cell; foreach(cell, typenames) { - TypeName *typename = (TypeName *) lfirst(cell); + TypeName *typename = (TypeName *) lfirst(cell); + rewrite_plain_name(typename->names); } } -static void +static void rewrite_role_list(List *rolespecs) { - ListCell *cell; + ListCell *cell; foreach(cell, rolespecs) { - RoleSpec *role = (RoleSpec *) lfirst(cell); + RoleSpec *role = (RoleSpec *) lfirst(cell); + /* skip current user, session user, public */ if (role->roletype == ROLESPEC_CSTRING) rewrite_role_name(role); @@ -1066,9 +1145,9 @@ PG_FUNCTION_INFO_V1(get_current_physical_schema_name); Datum get_current_physical_schema_name(PG_FUNCTION_ARGS) { - char *schema_name; - char *cur_db_name; - char *ret; + char *schema_name; + char *cur_db_name; + char *ret; schema_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); cur_db_name = get_cur_db_name(); @@ -1091,9 +1170,9 @@ get_current_physical_schema_name(PG_FUNCTION_ARGS) char * get_physical_schema_name_by_mode(char *db_name, const char *schema_name, MigrationMode mode) { - char *name; - char *result; - int len; + char *name; + char *result; + int len; if (!schema_name) return NULL; @@ -1108,11 +1187,15 @@ get_physical_schema_name_by_mode(char *db_name, const char *schema_name, Migrati strncpy(name, schema_name, len); if (is_shared_schema(name)) - { - /* in case of "information_schema" it will return "information_schema_tsql" */ + { + /* + * in case of "information_schema" it will return + * "information_schema_tsql" + */ if (strcmp(schema_name, "information_schema") == 0) { result = palloc0(MAX_BBF_NAMEDATALEND); + snprintf(result, (MAX_BBF_NAMEDATALEND), "%s_%s", name, "tsql"); pfree(name); return result; @@ -1121,9 +1204,10 @@ get_physical_schema_name_by_mode(char *db_name, const char *schema_name, Migrati return name; } - /* Parser guarantees identifier will alsways be truncated to 64B. - * Schema name that comes from other source (e.g scheam_id function) - * needs one more truncate function call + /* + * Parser guarantees identifier will alsways be truncated to 64B. Schema + * name that comes from other source (e.g scheam_id function) needs one + * more truncate function call */ truncate_tsql_identifier(name); @@ -1134,15 +1218,16 @@ get_physical_schema_name_by_mode(char *db_name, const char *schema_name, Migrati (strlen(db_name) == 4 && (strncmp(db_name, "msdb", 4) == 0))) { result = palloc0(MAX_BBF_NAMEDATALEND); + snprintf(result, (MAX_BBF_NAMEDATALEND), "%s_%s", db_name, name); } else if (!DbidIsValid(get_db_id(db_name))) { ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_DATABASE), - errmsg("database \"%s\" does not exist. Make sure that the name is entered correctly.", db_name))); + (errcode(ERRCODE_UNDEFINED_DATABASE), + errmsg("database \"%s\" does not exist. Make sure that the name is entered correctly.", db_name))); } - else + else { /* all schema names are not prepended with db name on single-db */ return name; @@ -1151,6 +1236,7 @@ get_physical_schema_name_by_mode(char *db_name, const char *schema_name, Migrati else { result = palloc0(MAX_BBF_NAMEDATALEND); + snprintf(result, (MAX_BBF_NAMEDATALEND), "%s_%s", db_name, name); } @@ -1175,9 +1261,9 @@ get_physical_schema_name(char *db_name, const char *schema_name) char * get_physical_user_name(char *db_name, char *user_name) { - char *new_user_name; - char *result; - int len; + char *new_user_name; + char *result; + int len; if (!user_name) return NULL; @@ -1199,13 +1285,14 @@ get_physical_user_name(char *db_name, char *user_name) /* Truncate to 64 bytes */ truncate_tsql_identifier(new_user_name); - /* All the role and user names are prefixed. - * Historically, dbo and db_owner in single-db mode were unprefixed - * These are two exceptions to the naming convention + /* + * All the role and user names are prefixed. Historically, dbo and + * db_owner in single-db mode were unprefixed These are two exceptions to + * the naming convention */ if (SINGLE_DB == get_migration_mode()) { - // check that db_name is not "master", "tempdb", or "msdb" + /* check that db_name is not "master", "tempdb", or "msdb" */ if ((strlen(db_name) != 6 || (strncmp(db_name, "master", 6) != 0)) && (strlen(db_name) != 6 || (strncmp(db_name, "tempdb", 6) != 0)) && (strlen(db_name) != 4 || (strncmp(db_name, "msdb", 4) != 0))) @@ -1219,6 +1306,7 @@ get_physical_user_name(char *db_name, char *user_name) } result = palloc0(MAX_BBF_NAMEDATALEND); + snprintf(result, (MAX_BBF_NAMEDATALEND), "%s_%s", db_name, new_user_name); /* Truncate final result to 64 bytes */ @@ -1230,19 +1318,20 @@ get_physical_user_name(char *db_name, char *user_name) const char * get_dbo_schema_name(const char *dbname) { - if (0 == strcmp(dbname , "master")) + if (0 == strcmp(dbname, "master")) return "master_dbo"; - if (0 == strcmp(dbname , "tempdb")) + if (0 == strcmp(dbname, "tempdb")) return "tempdb_dbo"; - if (0 == strcmp(dbname , "msdb")) + if (0 == strcmp(dbname, "msdb")) return "msdb_dbo"; if (SINGLE_DB == get_migration_mode()) return "dbo"; else { - char *name = palloc0(MAX_BBF_NAMEDATALEND); + char *name = palloc0(MAX_BBF_NAMEDATALEND); + snprintf(name, MAX_BBF_NAMEDATALEND, "%s_dbo", dbname); - truncate_identifier(name, strlen(name), false); + truncate_identifier(name, strlen(name), false); return name; } } @@ -1250,19 +1339,20 @@ get_dbo_schema_name(const char *dbname) const char * get_dbo_role_name(const char *dbname) { - if (0 == strcmp(dbname , "master")) + if (0 == strcmp(dbname, "master")) return "master_dbo"; - if (0 == strcmp(dbname , "tempdb")) + if (0 == strcmp(dbname, "tempdb")) return "tempdb_dbo"; - if (0 == strcmp(dbname , "msdb")) + if (0 == strcmp(dbname, "msdb")) return "msdb_dbo"; if (SINGLE_DB == get_migration_mode()) return "dbo"; else { - char *name = palloc0(MAX_BBF_NAMEDATALEND); + char *name = palloc0(MAX_BBF_NAMEDATALEND); + snprintf(name, MAX_BBF_NAMEDATALEND, "%s_dbo", dbname); - truncate_identifier(name, strlen(name), false); + truncate_identifier(name, strlen(name), false); return name; } } @@ -1270,73 +1360,80 @@ get_dbo_role_name(const char *dbname) const char * get_db_owner_name(const char *dbname) { - if (0 == strcmp(dbname , "master")) + if (0 == strcmp(dbname, "master")) return "master_db_owner"; - if (0 == strcmp(dbname , "tempdb")) + if (0 == strcmp(dbname, "tempdb")) return "tempdb_db_owner"; - if (0 == strcmp(dbname , "msdb")) + if (0 == strcmp(dbname, "msdb")) return "msdb_db_owner"; if (SINGLE_DB == get_migration_mode()) return "db_owner"; else { - char *name = palloc0(MAX_BBF_NAMEDATALEND); + char *name = palloc0(MAX_BBF_NAMEDATALEND); + snprintf(name, MAX_BBF_NAMEDATALEND, "%s_db_owner", dbname); - truncate_identifier(name, strlen(name), false); + truncate_identifier(name, strlen(name), false); return name; } } -const char *get_guest_role_name(const char *dbname) +const char * +get_guest_role_name(const char *dbname) { - if (0 == strcmp(dbname , "master")) + if (0 == strcmp(dbname, "master")) return "master_guest"; - if (0 == strcmp(dbname , "tempdb")) + if (0 == strcmp(dbname, "tempdb")) return "tempdb_guest"; - if (0 == strcmp(dbname , "msdb")) + if (0 == strcmp(dbname, "msdb")) return "msdb_guest"; /* - * Always prefix with dbname regardless if single or multidb. - * Note that dbo is an exception. - */ + * Always prefix with dbname regardless if single or multidb. Note that + * dbo is an exception. + */ else { - char *name = palloc0(MAX_BBF_NAMEDATALEND); + char *name = palloc0(MAX_BBF_NAMEDATALEND); + snprintf(name, MAX_BBF_NAMEDATALEND, "%s_guest", dbname); truncate_identifier(name, strlen(name), false); return name; } } -const char *get_guest_schema_name(const char *dbname) +const char * +get_guest_schema_name(const char *dbname) { - if (0 == strcmp(dbname , "master")) + if (0 == strcmp(dbname, "master")) return "master_guest"; - if (0 == strcmp(dbname , "tempdb")) + if (0 == strcmp(dbname, "tempdb")) return "tempdb_guest"; - if (0 == strcmp(dbname , "msdb")) + if (0 == strcmp(dbname, "msdb")) return "msdb_guest"; if (SINGLE_DB == get_migration_mode()) return "guest"; else { - char *name = palloc0(MAX_BBF_NAMEDATALEND); + char *name = palloc0(MAX_BBF_NAMEDATALEND); + snprintf(name, MAX_BBF_NAMEDATALEND, "%s_guest", dbname); truncate_identifier(name, strlen(name), false); return name; } } -bool is_builtin_database(const char *dbname) +bool +is_builtin_database(const char *dbname) { return ((strlen(dbname) == 6 && (strncmp(dbname, "master", 6) == 0)) || - (strlen(dbname) == 6 && (strncmp(dbname, "tempdb", 6) == 0)) || - (strlen(dbname) == 4 && (strncmp(dbname, "msdb", 4) == 0))); + (strlen(dbname) == 6 && (strncmp(dbname, "tempdb", 6) == 0)) || + (strlen(dbname) == 4 && (strncmp(dbname, "msdb", 4) == 0))); } -bool physical_schema_name_exists(char *phys_schema_name) +bool +physical_schema_name_exists(char *phys_schema_name) { return SearchSysCacheExists1(NAMESPACENAME, PointerGetDatum(phys_schema_name)); } @@ -1344,7 +1441,8 @@ bool physical_schema_name_exists(char *phys_schema_name) /* * Assume the database already exists and it is not a built in database */ -bool is_user_database_singledb(const char *dbname) +bool +is_user_database_singledb(const char *dbname) { Assert(DbidIsValid(get_db_id(dbname))); return !is_builtin_database(dbname) && physical_schema_name_exists("dbo"); @@ -1352,7 +1450,7 @@ bool is_user_database_singledb(const char *dbname) /************************************************************* - * Helper Functions + * Helper Functions *************************************************************/ /* in-place truncate identifiers if needded */ @@ -1370,21 +1468,20 @@ truncate_tsql_identifier(char *ident) { /* this is BBF help function. use BBF truncation logic */ set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); truncate_identifier(ident, strlen(ident), false); } PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RE_THROW(); } PG_END_TRY(); set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); } - diff --git a/contrib/babelfishpg_tsql/src/multidb.h b/contrib/babelfishpg_tsql/src/multidb.h index 55f78f3f66..4be3241ff9 100644 --- a/contrib/babelfishpg_tsql/src/multidb.h +++ b/contrib/babelfishpg_tsql/src/multidb.h @@ -5,7 +5,8 @@ #include "guc.h" #include "nodes/parsenodes.h" -#define MAX_BBF_NAMEDATALEND (2*NAMEDATALEN + 2) /* two identifiers + 1 '_' + 1 terminator */ +#define MAX_BBF_NAMEDATALEND (2*NAMEDATALEN + 2) /* two identifiers + 1 '_' + * + 1 terminator */ /* condition for schema remapping */ extern bool enable_schema_mapping(void); @@ -13,7 +14,7 @@ extern bool enable_schema_mapping(void); /* rewriting column/object references accoring schema mapping */ extern void rewrite_column_refs(ColumnRef *cref); extern void rewrite_object_refs(Node *stmt); -extern void rewrite_plain_name(List *name); /* Value Strings */ +extern void rewrite_plain_name(List *name); /* Value Strings */ /* helper functions */ extern char *get_physical_user_name(char *db_name, char *user_name); diff --git a/contrib/babelfishpg_tsql/src/pl_comp-2.c b/contrib/babelfishpg_tsql/src/pl_comp-2.c index 29d7b93943..e6be6afb3e 100644 --- a/contrib/babelfishpg_tsql/src/pl_comp-2.c +++ b/contrib/babelfishpg_tsql/src/pl_comp-2.c @@ -21,18 +21,22 @@ * Both pltsql_curr_compile_body_lineno and pltsql_curr_compile_body_posistion will be set * when batch level statment is compiled and it will be reset when new SQL batch comes in. */ -int pltsql_curr_compile_body_position; /* cursor position of function/procedure body in CREATE */ -int pltsql_curr_compile_body_lineno; /* lineno of function/procedure body in CREATE */ +int pltsql_curr_compile_body_position; /* cursor position of + * function/procedure body in + * CREATE */ +int pltsql_curr_compile_body_lineno; /* lineno of + * function/procedure body in + * CREATE */ /* * Used in pltsql_compile_error_callback. Copied from pg_proc.c * Almost same as original one but not trying to find exact cursor position from original input query. (see the comment above) */ -bool pltsql_function_parse_error_transpose(const char *prosrc); +bool pltsql_function_parse_error_transpose(const char *prosrc); -void apply_post_compile_actions(PLtsql_function *func, InlineCodeBlockArgs *args); +void apply_post_compile_actions(PLtsql_function *func, InlineCodeBlockArgs *args); -extern int cache_compiled_batch(PLtsql_function *func); +extern int cache_compiled_batch(PLtsql_function *func); extern void cache_inline_args(PLtsql_function *func, InlineCodeBlockArgs *args); extern SPIPlanPtr prepare_exec_codes(PLtsql_function *func, ExecCodes *exec_codes); extern void cleanup_temporal_plan(ExecCodes *exec_codes); @@ -48,7 +52,8 @@ extern void cleanup_temporal_plan(ExecCodes *exec_codes); * * Returns true if a syntax error was processed, false if not. */ -bool pltsql_function_parse_error_transpose(const char *prosrc) +bool +pltsql_function_parse_error_transpose(const char *prosrc) { int origerrposition; @@ -68,15 +73,16 @@ bool pltsql_function_parse_error_transpose(const char *prosrc) } /* - * NOTE: In batch mode, we can't access ActivePortal to queryText. - * Skip finding exact cursor position from original query block. - * This behavior just affects the cursor position of error message and even sqlcmd doesn't care of it. + * NOTE: In batch mode, we can't access ActivePortal to queryText. Skip + * finding exact cursor position from original query block. This behavior + * just affects the cursor position of error message and even sqlcmd + * doesn't care of it. */ /* - * If unsuccessful, convert the position to an internal position - * marker and give the function text as the internal query. + * If unsuccessful, convert the position to an internal position marker + * and give the function text as the internal query. */ errposition(0); internalerrposition(origerrposition); @@ -85,29 +91,35 @@ bool pltsql_function_parse_error_transpose(const char *prosrc) return true; } -void apply_post_compile_actions(PLtsql_function *func, InlineCodeBlockArgs *args) +void +apply_post_compile_actions(PLtsql_function *func, InlineCodeBlockArgs *args) { if (OPTION_ENABLED(args, PREPARE_PLAN)) { - SPIPlanPtr plan; + SPIPlanPtr plan; + Assert(func->exec_codes); plan = prepare_exec_codes(func, func->exec_codes); - if(plan) + if (plan) { if (OPTION_ENABLED(args, SEND_METADATA)) { if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->send_column_metadata) { List *plansources; + plansources = SPI_plan_get_plan_sources(plan); if (list_length(plansources) == 1) { CachedPlanSource *plansource = (CachedPlanSource *) linitial(plansources); - List *targetlist = CachedPlanGetTargetList(plansource, NULL); + List *targetlist = CachedPlanGetTargetList(plansource, NULL); - /* Only SELECT command type should send column metadata */ + /* + * Only SELECT command type should send column + * metadata + */ if (plansource->commandTag == CMDTAG_SELECT) - (*(*pltsql_protocol_plugin_ptr)->send_column_metadata)(plansource->resultDesc, targetlist, NULL); + (*(*pltsql_protocol_plugin_ptr)->send_column_metadata) (plansource->resultDesc, targetlist, NULL); } } diff --git a/contrib/babelfishpg_tsql/src/pl_comp.c b/contrib/babelfishpg_tsql/src/pl_comp.c index e84918363e..c72b321681 100644 --- a/contrib/babelfishpg_tsql/src/pl_comp.c +++ b/contrib/babelfishpg_tsql/src/pl_comp.c @@ -16,8 +16,10 @@ #include "postgres.h" #include "miscadmin.h" #include -#include /* FIXME: for debugging only - feel free to remove */ -#include /* FIXME: for debugging only - feel free to remove */ +#include /* FIXME: for debugging only - feel free to + * remove */ +#include /* FIXME: for debugging only - feel free to + * remove */ #include "access/htup_details.h" #include "catalog/namespace.h" @@ -59,7 +61,9 @@ bool pltsql_DumpExecTree = false; bool pltsql_check_syntax = false; PLtsql_function *pltsql_curr_compile; -int pltsql_curr_compile_body_lineno; /* lineno of function/procedure body in CREATE */ +int pltsql_curr_compile_body_lineno; /* lineno of + * function/procedure body in + * CREATE */ /* A context appropriate for short-term allocs during compilation */ MemoryContext pltsql_compile_tmp_cxt; @@ -94,21 +98,21 @@ static const ExceptionLabelMap exception_label_map[] = { }; /* ---------- - * Current session's handler + * Current session's handler * ---------- */ -static int cur_handle_id = 1; +static int cur_handle_id = 1; /* ---------- * static prototypes * ---------- */ static PLtsql_function *do_compile(FunctionCallInfo fcinfo, - HeapTuple procTup, - PLtsql_function *function, - PLtsql_func_hashkey *hashkey, - bool forValidator); + HeapTuple procTup, + PLtsql_function *function, + PLtsql_func_hashkey *hashkey, + bool forValidator); static void pltsql_compile_error_callback(void *arg); static void add_parameter_name(PLtsql_nsitem_type itemtype, int itemno, const char *name); static void add_dummy_return(PLtsql_function *function); @@ -118,29 +122,29 @@ static Node *pltsql_post_column_ref(ParseState *pstate, ColumnRef *cref, Node *v static void pltsql_post_expand_star(ParseState *pstate, ColumnRef *cref, List *l); static Node *pltsql_param_ref(ParseState *pstate, ParamRef *pref); static Node *resolve_column_ref(ParseState *pstate, PLtsql_expr *expr, - ColumnRef *cref, bool error_if_no_field); + ColumnRef *cref, bool error_if_no_field); static Node *make_datum_param(PLtsql_expr *expr, int dno, int location); static PLtsql_row *build_row_from_vars(PLtsql_variable **vars, int numvars); static PLtsql_type *build_datatype(HeapTuple typeTup, int32 typmod, - Oid collation, TypeName *origtypname); + Oid collation, TypeName *origtypname); static void pltsql_start_datums(void); static void pltsql_finish_datums(PLtsql_function *function); static void compute_function_hashkey(FunctionCallInfo fcinfo, - Form_pg_proc procStruct, - PLtsql_func_hashkey *hashkey, - bool forValidator); + Form_pg_proc procStruct, + PLtsql_func_hashkey *hashkey, + bool forValidator); static void pltsql_resolve_polymorphic_argtypes(int numargs, - Oid *argtypes, char *argmodes, - Node *call_expr, bool forValidator, - const char *proname); + Oid *argtypes, char *argmodes, + Node *call_expr, bool forValidator, + const char *proname); static PLtsql_function *pltsql_HashTableLookup(PLtsql_func_hashkey *func_key); static void pltsql_HashTableInsert(PLtsql_function *function, - PLtsql_func_hashkey *func_key); + PLtsql_func_hashkey *func_key); static void pltsql_HashTableDelete(PLtsql_function *function); static void delete_function(PLtsql_function *func); extern Portal ActivePortal; -extern bool pltsql_function_parse_error_transpose(const char* prosrc); +extern bool pltsql_function_parse_error_transpose(const char *prosrc); /* ---------- * pltsql_compile Make an execution tree for a PL/tsql function. @@ -193,7 +197,7 @@ pltsql_compile(FunctionCallInfo fcinfo, bool forValidator) /* We have a compiled function, but is it still valid? */ if (function->fn_xmin == HeapTupleHeaderGetRawXmin(procTup->t_data) && ItemPointerEquals(&function->fn_tid, &procTup->t_self) && - function->exec_codes_valid) + function->exec_codes_valid) function_valid = true; else { @@ -311,10 +315,11 @@ do_compile(FunctionCallInfo fcinfo, int *in_arg_varnos = NULL; PLtsql_variable **out_arg_variables; MemoryContext func_cxt; + /* Special handling is needed for Multi-Statement Table-Valued Functions. */ - int tbl_dno = -1; /* dno of the output table variable */ - char *tbl_typ = NULL; /* Name of the output table variable's type */ - int *typmods = NULL; /* typmod of each argument if available */ + int tbl_dno = -1; /* dno of the output table variable */ + char *tbl_typ = NULL; /* Name of the output table variable's type */ + int *typmods = NULL; /* typmod of each argument if available */ CompileContext *cmpl_ctx = create_compile_context(); /* @@ -357,7 +362,7 @@ do_compile(FunctionCallInfo fcinfo, } else { - free_exec_codes(function->exec_codes); + free_exec_codes(function->exec_codes); /* re-using a previously existing struct, so clear it out */ memset(function, 0, sizeof(PLtsql_function)); } @@ -420,21 +425,25 @@ do_compile(FunctionCallInfo fcinfo, &argtypes, &argnames, &argmodes); pltsql_resolve_polymorphic_argtypes(numargs, argtypes, argmodes, - fcinfo->flinfo->fn_expr, - forValidator, - pltsql_error_funcname); + fcinfo->flinfo->fn_expr, + forValidator, + pltsql_error_funcname); in_arg_varnos = (int *) palloc(numargs * sizeof(int)); out_arg_variables = (PLtsql_variable **) palloc(numargs * sizeof(PLtsql_variable *)); MemoryContextSwitchTo(func_cxt); - /* use pronargs and proargtypes here instead of numargs and argtypes. it matches function signature and typmods array stored in probin */ + /* + * use pronargs and proargtypes here instead of numargs and + * argtypes. it matches function signature and typmods array + * stored in probin + */ probin_read_args_typmods(procTup, procStruct->pronargs, procStruct->proargtypes.values, &typmods); /* Function return type should not be rowversion. */ if (procStruct->prokind == PROKIND_FUNCTION && - (*common_utility_plugin_ptr->is_tsql_rowversion_or_timestamp_datatype)(procStruct->prorettype)) + (*common_utility_plugin_ptr->is_tsql_rowversion_or_timestamp_datatype) (procStruct->prorettype)) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("The timestamp data type is invalid for return values."))); @@ -456,18 +465,18 @@ do_compile(FunctionCallInfo fcinfo, /* rowversion is not a valid type for function parameter. */ if (procStruct->prokind == PROKIND_FUNCTION && - (*common_utility_plugin_ptr->is_tsql_rowversion_or_timestamp_datatype)(argtypeid) && + (*common_utility_plugin_ptr->is_tsql_rowversion_or_timestamp_datatype) (argtypeid) && argmode != PROARGMODE_TABLE) ereport(ERROR, - (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), - errmsg("Parameter or variable \"%s\" has an invalid data type.", argnames[i]))); + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("Parameter or variable \"%s\" has an invalid data type.", argnames[i]))); /* - * Function is a Multi-Statement Table-Valued function if there - * is a table arg, and the return type is a composite type. - * An inline Table-Valued function can also have table args, but - * its return type is either RECORD (multi-column) or a base - * type (single-column). + * Function is a Multi-Statement Table-Valued function if + * there is a table arg, and the return type is a composite + * type. An inline Table-Valued function can also have table + * args, but its return type is either RECORD (multi-column) + * or a base type (single-column). */ if (argmode == PROARGMODE_TABLE && get_typtype(procStruct->prorettype) == TYPTYPE_COMPOSITE) @@ -483,9 +492,9 @@ do_compile(FunctionCallInfo fcinfo, /* Create datatype info */ argdtype = pltsql_build_datatype(argtypeid, - (typmods ? typmods[i] : -1), - function->fn_input_collation, - NULL); + (typmods ? typmods[i] : -1), + function->fn_input_collation, + NULL); /* Disallow pseudotype argument */ /* (note we already replaced polymorphic types) */ @@ -501,18 +510,21 @@ do_compile(FunctionCallInfo fcinfo, * for the argument, use that as refname, else use $n name. */ argvariable = pltsql_build_variable((argnames && - argnames[i][0] != '\0') ? - argnames[i] : buf, - 0, argdtype, false); + argnames[i][0] != '\0') ? + argnames[i] : buf, + 0, argdtype, false); - /* Multi-Statement Table-Valued Function - save dno and typname */ + /* + * Multi-Statement Table-Valued Function - save dno and + * typname + */ if (function->is_mstvf) { tbl_dno = argvariable->dno; tbl_typ = psprintf("%s.%s", - get_namespace_name( - get_rel_namespace(get_typ_typrelid(argtypeid))), - argdtype->typname); + get_namespace_name( + get_rel_namespace(get_typ_typrelid(argtypeid))), + argdtype->typname); } if (argvariable->dtype == PLTSQL_DTYPE_VAR) @@ -545,10 +557,10 @@ do_compile(FunctionCallInfo fcinfo, /* * If there's a name for the argument, make an alias * - * Inline Table-Valued Function has one argument for each column - * of the rows to be returned, and we don't add them to the - * namespace to avoid error when query contain the same column - * reference name. + * Inline Table-Valued Function has one argument for each + * column of the rows to be returned, and we don't add them to + * the namespace to avoid error when query contain the same + * column reference name. * * For Multi-Statement Table-Valued Function we don't need to * skip this because it only has one argument for the result @@ -571,7 +583,7 @@ do_compile(FunctionCallInfo fcinfo, (num_out_args == 1 && function->fn_prokind == PROKIND_PROCEDURE)) { PLtsql_row *row = build_row_from_vars(out_arg_variables, - num_out_args); + num_out_args); pltsql_adddatum((PLtsql_datum *) row); function->out_param_varno = row->dno; @@ -652,8 +664,8 @@ do_compile(FunctionCallInfo fcinfo, function->fn_rettyplen = typeStruct->typlen; /* Special handling is needed for Inline Table-Valued Functions. */ function->is_itvf = procStruct->prokind == PROKIND_FUNCTION && - procStruct->proretset && - get_typtype(procStruct->prorettype) != TYPTYPE_COMPOSITE; + procStruct->proretset && + get_typtype(procStruct->prorettype) != TYPTYPE_COMPOSITE; /* * install $0 reference, but only for polymorphic return types, @@ -664,11 +676,11 @@ do_compile(FunctionCallInfo fcinfo, num_out_args == 0) { (void) pltsql_build_variable("$0", 0, - build_datatype(typeTup, - -1, - function->fn_input_collation, - NULL), - true); + build_datatype(typeTup, + -1, + function->fn_input_collation, + NULL), + true); } ReleaseSysCache(typeTup); @@ -699,110 +711,110 @@ do_compile(FunctionCallInfo fcinfo, /* Add the variable tg_name */ var = pltsql_build_variable("tg_name", 0, - pltsql_build_datatype(NAMEOID, - -1, - InvalidOid, - NULL), - true); + pltsql_build_datatype(NAMEOID, + -1, + InvalidOid, + NULL), + true); Assert(var->dtype == PLTSQL_DTYPE_VAR); var->dtype = PLTSQL_DTYPE_PROMISE; ((PLtsql_var *) var)->promise = PLTSQL_PROMISE_TG_NAME; /* Add the variable tg_when */ var = pltsql_build_variable("tg_when", 0, - pltsql_build_datatype(TEXTOID, - -1, - function->fn_input_collation, - NULL), - true); + pltsql_build_datatype(TEXTOID, + -1, + function->fn_input_collation, + NULL), + true); Assert(var->dtype == PLTSQL_DTYPE_VAR); var->dtype = PLTSQL_DTYPE_PROMISE; ((PLtsql_var *) var)->promise = PLTSQL_PROMISE_TG_WHEN; /* Add the variable tg_level */ var = pltsql_build_variable("tg_level", 0, - pltsql_build_datatype(TEXTOID, - -1, - function->fn_input_collation, - NULL), - true); + pltsql_build_datatype(TEXTOID, + -1, + function->fn_input_collation, + NULL), + true); Assert(var->dtype == PLTSQL_DTYPE_VAR); var->dtype = PLTSQL_DTYPE_PROMISE; ((PLtsql_var *) var)->promise = PLTSQL_PROMISE_TG_LEVEL; /* Add the variable tg_op */ var = pltsql_build_variable("tg_op", 0, - pltsql_build_datatype(TEXTOID, - -1, - function->fn_input_collation, - NULL), - true); + pltsql_build_datatype(TEXTOID, + -1, + function->fn_input_collation, + NULL), + true); Assert(var->dtype == PLTSQL_DTYPE_VAR); var->dtype = PLTSQL_DTYPE_PROMISE; ((PLtsql_var *) var)->promise = PLTSQL_PROMISE_TG_OP; /* Add the variable tg_relid */ var = pltsql_build_variable("tg_relid", 0, - pltsql_build_datatype(OIDOID, - -1, - InvalidOid, - NULL), - true); + pltsql_build_datatype(OIDOID, + -1, + InvalidOid, + NULL), + true); Assert(var->dtype == PLTSQL_DTYPE_VAR); var->dtype = PLTSQL_DTYPE_PROMISE; ((PLtsql_var *) var)->promise = PLTSQL_PROMISE_TG_RELID; /* Add the variable tg_relname */ var = pltsql_build_variable("tg_relname", 0, - pltsql_build_datatype(NAMEOID, - -1, - InvalidOid, - NULL), - true); + pltsql_build_datatype(NAMEOID, + -1, + InvalidOid, + NULL), + true); Assert(var->dtype == PLTSQL_DTYPE_VAR); var->dtype = PLTSQL_DTYPE_PROMISE; ((PLtsql_var *) var)->promise = PLTSQL_PROMISE_TG_TABLE_NAME; /* tg_table_name is now preferred to tg_relname */ var = pltsql_build_variable("tg_table_name", 0, - pltsql_build_datatype(NAMEOID, - -1, - InvalidOid, - NULL), - true); + pltsql_build_datatype(NAMEOID, + -1, + InvalidOid, + NULL), + true); Assert(var->dtype == PLTSQL_DTYPE_VAR); var->dtype = PLTSQL_DTYPE_PROMISE; ((PLtsql_var *) var)->promise = PLTSQL_PROMISE_TG_TABLE_NAME; /* add the variable tg_table_schema */ var = pltsql_build_variable("tg_table_schema", 0, - pltsql_build_datatype(NAMEOID, - -1, - InvalidOid, - NULL), - true); + pltsql_build_datatype(NAMEOID, + -1, + InvalidOid, + NULL), + true); Assert(var->dtype == PLTSQL_DTYPE_VAR); var->dtype = PLTSQL_DTYPE_PROMISE; ((PLtsql_var *) var)->promise = PLTSQL_PROMISE_TG_TABLE_SCHEMA; /* Add the variable tg_nargs */ var = pltsql_build_variable("tg_nargs", 0, - pltsql_build_datatype(INT4OID, - -1, - InvalidOid, - NULL), - true); + pltsql_build_datatype(INT4OID, + -1, + InvalidOid, + NULL), + true); Assert(var->dtype == PLTSQL_DTYPE_VAR); var->dtype = PLTSQL_DTYPE_PROMISE; ((PLtsql_var *) var)->promise = PLTSQL_PROMISE_TG_NARGS; /* Add the variable tg_argv */ var = pltsql_build_variable("tg_argv", 0, - pltsql_build_datatype(TEXTARRAYOID, - -1, - function->fn_input_collation, - NULL), - true); + pltsql_build_datatype(TEXTARRAYOID, + -1, + function->fn_input_collation, + NULL), + true); Assert(var->dtype == PLTSQL_DTYPE_VAR); var->dtype = PLTSQL_DTYPE_PROMISE; ((PLtsql_var *) var)->promise = PLTSQL_PROMISE_TG_ARGV; @@ -824,22 +836,22 @@ do_compile(FunctionCallInfo fcinfo, /* Add the variable tg_event */ var = pltsql_build_variable("tg_event", 0, - pltsql_build_datatype(TEXTOID, - -1, - function->fn_input_collation, - NULL), - true); + pltsql_build_datatype(TEXTOID, + -1, + function->fn_input_collation, + NULL), + true); Assert(var->dtype == PLTSQL_DTYPE_VAR); var->dtype = PLTSQL_DTYPE_PROMISE; ((PLtsql_var *) var)->promise = PLTSQL_PROMISE_TG_EVENT; /* Add the variable tg_tag */ var = pltsql_build_variable("tg_tag", 0, - pltsql_build_datatype(TEXTOID, - -1, - function->fn_input_collation, - NULL), - true); + pltsql_build_datatype(TEXTOID, + -1, + function->fn_input_collation, + NULL), + true); Assert(var->dtype == PLTSQL_DTYPE_VAR); var->dtype = PLTSQL_DTYPE_PROMISE; ((PLtsql_var *) var)->promise = PLTSQL_PROMISE_TG_TAG; @@ -859,19 +871,19 @@ do_compile(FunctionCallInfo fcinfo, * Create the magic FOUND variable. */ var = pltsql_build_variable("found", 0, - pltsql_build_datatype(BOOLOID, - -1, - InvalidOid, - NULL), - true); + pltsql_build_datatype(BOOLOID, + -1, + InvalidOid, + NULL), + true); function->found_varno = var->dno; var = pltsql_build_variable("@@fetch_status", 0, - pltsql_build_datatype(INT4OID, - -1, - InvalidOid, - NULL), - true); + pltsql_build_datatype(INT4OID, + -1, + InvalidOid, + NULL), + true); function->fetch_status_varno = var->dno; @@ -888,7 +900,7 @@ do_compile(FunctionCallInfo fcinfo, else { report_antlr_error(result); - parse_rc = 1; /* invalid input */ + parse_rc = 1; /* invalid input */ } } @@ -900,16 +912,15 @@ do_compile(FunctionCallInfo fcinfo, pfree(proc_source); /* - * Multi-Statement Table-Valued Function: - * 1) Add a declare table statement to the beginning - * 2) Add a return table statement to the end + * Multi-Statement Table-Valued Function: 1) Add a declare table statement + * to the beginning 2) Add a return table statement to the end */ if (function->is_mstvf) { - /* - * ANTLR parser would return a stmt list like INIT->BLOCK, - * where BLOCK is a wrapper for the statements. - * For MSTVF parsing we don't want the wrapper. + /* + * ANTLR parser would return a stmt list like INIT->BLOCK, where BLOCK + * is a wrapper for the statements. For MSTVF parsing we don't want + * the wrapper. */ Assert(list_length(pltsql_parse_result->body) >= 2); function->action = (PLtsql_stmt_block *) lsecond(pltsql_parse_result->body); @@ -955,7 +966,7 @@ do_compile(FunctionCallInfo fcinfo, MemoryContextSwitchTo(pltsql_compile_tmp_cxt); pltsql_compile_tmp_cxt = NULL; - /* Generate execution code for new executor */ + /* Generate execution code for new executor */ PG_TRY(); { analyze(function, cmpl_ctx); @@ -992,20 +1003,20 @@ pltsql_compile_inline(char *proc_source, InlineCodeBlockArgs *args) int parse_rc; MemoryContext func_cxt; - Datum *allTypes; - Datum *paramModes; - Datum *paramNames; - bool have_names = false; - int *in_arg_varnos = NULL; - int num_in_args = 0; - int num_out_args = 0; + Datum *allTypes; + Datum *paramModes; + Datum *paramNames; + bool have_names = false; + int *in_arg_varnos = NULL; + int num_in_args = 0; + int num_out_args = 0; PLtsql_variable **out_arg_variables; - int i; + int i; - int numargs = args ? args->numargs : 0; - Oid *argtypes = args ? args->argtypes : NULL; - char **argnames = args ? args->argnames : NULL; - char *argmodes = args ? args->argmodes : NULL; + int numargs = args ? args->numargs : 0; + Oid *argtypes = args ? args->argtypes : NULL; + char **argnames = args ? args->argnames : NULL; + char *argmodes = args ? args->argmodes : NULL; CompileContext *cmpl_ctx = create_compile_context(); /* @@ -1096,43 +1107,42 @@ pltsql_compile_inline(char *proc_source, InlineCodeBlockArgs *args) for (i = 0; i < numargs; i++) { - char buf[32]; - Oid argtypeid = argtypes[i]; - char argmode = argmodes[i]; - PLtsql_type *argdtype; - PLtsql_variable *argvariable; - PLtsql_nsitem_type argitemtype; + char buf[32]; + Oid argtypeid = argtypes[i]; + char argmode = argmodes[i]; + PLtsql_type *argdtype; + PLtsql_variable *argvariable; + PLtsql_nsitem_type argitemtype; /* Create $n name for variable */ snprintf(buf, sizeof(buf), "$%d", i + 1); /* Create datatype info */ argdtype = pltsql_build_datatype(argtypeid, - -1, - function->fn_input_collation, - NULL); - - /* - * Disallow pseudotype argument - * (note we already replaced polymorphic types - * build_variable would do this, but wrong message) + -1, + function->fn_input_collation, + NULL); + + /* + * Disallow pseudotype argument (note we already replaced polymorphic + * types build_variable would do this, but wrong message) */ if (argdtype->ttype == PLTSQL_TTYPE_PSEUDO) ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("PL/tsql functions cannot accept type %s", - format_type_be(argtypeid)))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("PL/tsql functions cannot accept type %s", + format_type_be(argtypeid)))); - /* - * Build variable and add to datum list. If there's a name - * for the argument, use that as refname, else use $n name. + /* + * Build variable and add to datum list. If there's a name for the + * argument, use that as refname, else use $n name. */ - argvariable = pltsql_build_variable((argnames && - argnames[i][0] != '\0') ? - argnames[i] : buf, - 0, - argdtype, - false); + argvariable = pltsql_build_variable((argnames && + argnames[i][0] != '\0') ? + argnames[i] : buf, + 0, + argdtype, + false); if (argvariable->dtype == PLTSQL_DTYPE_VAR) argitemtype = PLTSQL_NSTYPE_VAR; @@ -1146,12 +1156,12 @@ pltsql_compile_inline(char *proc_source, InlineCodeBlockArgs *args) /* Remember arguments in appropriate arrays */ if (argmode == FUNC_PARAM_IN || - argmode == FUNC_PARAM_INOUT || - argmode == FUNC_PARAM_VARIADIC) + argmode == FUNC_PARAM_INOUT || + argmode == FUNC_PARAM_VARIADIC) in_arg_varnos[num_in_args++] = argvariable->dno; if (argmode == FUNC_PARAM_OUT || - argmode == FUNC_PARAM_INOUT || - argmode == FUNC_PARAM_TABLE) + argmode == FUNC_PARAM_INOUT || + argmode == FUNC_PARAM_TABLE) out_arg_variables[num_out_args++] = argvariable; /* Add to namespace under the $n name */ @@ -1160,8 +1170,8 @@ pltsql_compile_inline(char *proc_source, InlineCodeBlockArgs *args) /* If there's a name for the argument, make an alias */ if (argnames && argnames[i][0] != '\0') { - add_parameter_name(argitemtype, argvariable->dno, - argnames[i]); + add_parameter_name(argitemtype, argvariable->dno, + argnames[i]); paramNames[i] = CStringGetTextDatum(argnames[i]); have_names = true; } @@ -1171,16 +1181,16 @@ pltsql_compile_inline(char *proc_source, InlineCodeBlockArgs *args) } /* - * When there are more than one output argument, the return type should - * be RECORD and there should be a tuple descriptor for all argument - * types, i.e. this is a sp_executesql case. + * When there are more than one output argument, the return type should be + * RECORD and there should be a tuple descriptor for all argument types, + * i.e. this is a sp_executesql case. */ if (num_out_args >= 1) { - ArrayType *allParameterTypes; - ArrayType *parameterModes; - ArrayType *parameterNames; - PLtsql_row *row; + ArrayType *allParameterTypes; + ArrayType *parameterModes; + ArrayType *parameterNames; + PLtsql_row *row; function->fn_prokind = PROKIND_PROCEDURE; function->fn_rettype = RECORDOID; @@ -1189,9 +1199,9 @@ pltsql_compile_inline(char *proc_source, InlineCodeBlockArgs *args) function->fn_rettyplen = -1; allParameterTypes = construct_array(allTypes, numargs, OIDOID, - sizeof(Oid), true, 'i'); + sizeof(Oid), true, 'i'); parameterModes = construct_array(paramModes, numargs, CHAROID, - 1, true, 'c'); + 1, true, 'c'); if (have_names) { for (i = 0; i < numargs; i++) @@ -1200,21 +1210,20 @@ pltsql_compile_inline(char *proc_source, InlineCodeBlockArgs *args) paramNames[i] = CStringGetTextDatum(""); } parameterNames = construct_array(paramNames, numargs, TEXTOID, - -1, false, 'i'); + -1, false, 'i'); } else parameterNames = NULL; - /* Build a tuple descriptor for the result rowtype */ + /* Build a tuple descriptor for the result rowtype */ function->fn_tupdesc = build_function_result_tupdesc_d(function->fn_prokind, - PointerGetDatum(allParameterTypes), - PointerGetDatum(parameterModes), - PointerGetDatum(parameterNames)); + PointerGetDatum(allParameterTypes), + PointerGetDatum(parameterModes), + PointerGetDatum(parameterNames)); /* - * For a procedure that has one or more OUT parameters - * (sp_executesql at the moment), build a row that holds all of - * them. + * For a procedure that has one or more OUT parameters (sp_executesql + * at the moment), build a row that holds all of them. */ row = build_row_from_vars(out_arg_variables, num_out_args); pltsql_adddatum((PLtsql_datum *) row); @@ -1225,18 +1234,18 @@ pltsql_compile_inline(char *proc_source, InlineCodeBlockArgs *args) * Create the magic FOUND variable. */ var = pltsql_build_variable("found", 0, - pltsql_build_datatype(BOOLOID, - -1, - InvalidOid, - NULL), - true); + pltsql_build_datatype(BOOLOID, + -1, + InvalidOid, + NULL), + true); function->found_varno = var->dno; - var = pltsql_build_variable("@@fetch_status", 0, + var = pltsql_build_variable("@@fetch_status", 0, pltsql_build_datatype(INT4OID, - -1, - InvalidOid, - NULL), + -1, + InvalidOid, + NULL), true); function->fetch_status_varno = var->dno; @@ -1253,7 +1262,7 @@ pltsql_compile_inline(char *proc_source, InlineCodeBlockArgs *args) else { report_antlr_error(result); - parse_rc = 1; /* invalid input */ + parse_rc = 1; /* invalid input */ } } @@ -1267,12 +1276,12 @@ pltsql_compile_inline(char *proc_source, InlineCodeBlockArgs *args) toDotTSql((PLtsql_stmt *) pltsql_parse_result, proc_source, "/tmp/sql.dot"); } - + pltsql_scanner_finish(); /* - * If it returns VOID or has OUT parameters (always true at the moment), - * we allow control to fall off the end without an explicit RETURN + * If it returns VOID or has OUT parameters (always true at the moment), + * we allow control to fall off the end without an explicit RETURN * statement. */ if (num_out_args > 0 || function->fn_rettype == VOIDOID) @@ -1315,7 +1324,7 @@ pltsql_compile_inline(char *proc_source, InlineCodeBlockArgs *args) } PG_END_TRY(); destroy_compile_context(cmpl_ctx); - + return function; } @@ -1337,11 +1346,14 @@ pltsql_compile_error_callback(void *arg) if (!ActivePortal || !ActivePortal->sourceText) { /* - * ActivePortal can be NULL when tsql batch mode is on. - * But function_parse_error_transpose() can assume ActivePortal is not NULL and try to access it to get full original query text. - * Also, we may have created a dummy ActivePortal which does not contain query text. - * To avoid crash, use pltsql function which is the similar as original one but not trying to get full original query text. - * The side effect will be errposition is set to 0 in some cases. + * ActivePortal can be NULL when tsql batch mode is on. But + * function_parse_error_transpose() can assume ActivePortal is not + * NULL and try to access it to get full original query text. + * Also, we may have created a dummy ActivePortal which does not + * contain query text. To avoid crash, use pltsql function which + * is the similar as original one but not trying to get full + * original query text. The side effect will be errposition is set + * to 0 in some cases. */ if (pltsql_function_parse_error_transpose((const char *) arg)) return; @@ -1378,8 +1390,8 @@ add_parameter_name(PLtsql_nsitem_type itemtype, int itemno, const char *name) * disambiguate. */ if (pltsql_ns_lookup(pltsql_ns_top(), true, - name, NULL, NULL, - NULL) != NULL) + name, NULL, NULL, + NULL) != NULL) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("parameter name \"%s\" used more than once", @@ -1527,32 +1539,37 @@ pltsql_post_column_ref(ParseState *pstate, ColumnRef *cref, Node *var) static void pltsql_post_expand_star(ParseState *pstate, ColumnRef *cref, List *l) { - ListCell *li; - Datum attopts; - ArrayType *arr; - Datum *optiondatums; - int noptions, i; - char *optstr, *bbf_original_name; + ListCell *li; + Datum attopts; + ArrayType *arr; + Datum *optiondatums; + int noptions, + i; + char *optstr, + *bbf_original_name; foreach(li, l) { /* - * Each item in the List here should be a TargetEntry (see ExpandAllTables/expandNSItemAttrs) + * Each item in the List here should be a TargetEntry (see + * ExpandAllTables/expandNSItemAttrs) */ TargetEntry *te = (TargetEntry *) lfirst(li); - Var *varnode = (Var *) te->expr; + Var *varnode = (Var *) te->expr; RangeTblEntry *rte = GetRTEByRangeTablePosn(pstate, varnode->varno, varnode->varlevelsup); - Oid relid = rte->relid; - int16 attnum = varnode->varattno; + Oid relid = rte->relid; + int16 attnum = varnode->varattno; if (rte->rtekind != RTE_RELATION || relid == InvalidOid) { return; } + /* - * Get the list of names in pg_attribute. get_attoptions returns a Datum of - * the text[] field pgattribute.attoptions. We don't want to throw a full - * error if cache lookup fails to preserve functionality, so just log it. + * Get the list of names in pg_attribute. get_attoptions returns a + * Datum of the text[] field pgattribute.attoptions. We don't want to + * throw a full error if cache lookup fails to preserve functionality, + * so just log it. */ PG_TRY(); { @@ -1561,7 +1578,7 @@ pltsql_post_expand_star(ParseState *pstate, ColumnRef *cref, List *l) PG_CATCH(); { elog(LOG, "Cache lookup failed in pltsql_post_expand_star for attribute %d of relation %u", - attnum, relid); + attnum, relid); attopts = (Datum) 0; } PG_END_TRY(); @@ -1572,7 +1589,7 @@ pltsql_post_expand_star(ParseState *pstate, ColumnRef *cref, List *l) arr = DatumGetArrayTypeP(attopts); deconstruct_array(arr, TEXTOID, -1, false, TYPALIGN_INT, - &optiondatums, NULL, &noptions); + &optiondatums, NULL, &noptions); for (i = 0; i < noptions; i++) { @@ -1604,8 +1621,8 @@ pltsql_param_ref(ParseState *pstate, ParamRef *pref) snprintf(pname, sizeof(pname), "$%d", pref->number); nse = pltsql_ns_lookup(expr->ns, false, - pname, NULL, NULL, - NULL); + pname, NULL, NULL, + NULL); if (nse == NULL) return NULL; /* name not known to pltsql */ @@ -1722,8 +1739,8 @@ resolve_column_ref(ParseState *pstate, PLtsql_expr *expr, } nse = pltsql_ns_lookup(expr->ns, false, - name1, name2, name3, - &nnames); + name1, name2, name3, + &nnames); if (nse == NULL) return NULL; /* name not known to pltsql */ @@ -1814,10 +1831,10 @@ make_datum_param(PLtsql_expr *expr, int dno, int location) param->paramkind = PARAM_EXTERN; param->paramid = dno + 1; pltsql_exec_get_datum_type_info(estate, - datum, - ¶m->paramtype, - ¶m->paramtypmod, - ¶m->paramcollid); + datum, + ¶m->paramtype, + ¶m->paramtypmod, + ¶m->paramcollid); param->location = location; return (Node *) param; @@ -1842,7 +1859,7 @@ make_datum_param(PLtsql_expr *expr, int dno, int location) */ bool pltsql_parse_word(char *word1, const char *yytxt, - PLwdatum *wdatum, PLword *word) + PLwdatum *wdatum, PLword *word) { PLtsql_nsitem *ns; @@ -1851,10 +1868,11 @@ pltsql_parse_word(char *word1, const char *yytxt, * no need to do anything either --- lookup will happen when the * expression is compiled. */ + /* * Update for table variables: because we need to replace the table - * variables by their underlying tables' names in the expression, we need to - * be able to lookup in IDENTIFIER_LOOKUP_EXPR as well. + * variables by their underlying tables' names in the expression, we need + * to be able to lookup in IDENTIFIER_LOOKUP_EXPR as well. */ if (pltsql_IdentifierLookup == IDENTIFIER_LOOKUP_NORMAL || pltsql_IdentifierLookup == IDENTIFIER_LOOKUP_EXPR) @@ -1863,8 +1881,8 @@ pltsql_parse_word(char *word1, const char *yytxt, * Do a lookup in the current namespace stack */ ns = pltsql_ns_lookup(pltsql_ns_top(), false, - word1, NULL, NULL, - NULL); + word1, NULL, NULL, + NULL); if (ns != NULL) { @@ -1904,7 +1922,7 @@ pltsql_parse_word(char *word1, const char *yytxt, */ bool pltsql_parse_dblword(char *word1, char *word2, - PLwdatum *wdatum, PLcword *cword) + PLwdatum *wdatum, PLcword *cword) { PLtsql_nsitem *ns; List *idents; @@ -1924,8 +1942,8 @@ pltsql_parse_dblword(char *word1, char *word2, * Do a lookup in the current namespace stack */ ns = pltsql_ns_lookup(pltsql_ns_top(), false, - word1, word2, NULL, - &nnames); + word1, word2, NULL, + &nnames); if (ns != NULL) { switch (ns->itemtype) @@ -1984,7 +2002,7 @@ pltsql_parse_dblword(char *word1, char *word2, */ bool pltsql_parse_tripword(char *word1, char *word2, char *word3, - PLwdatum *wdatum, PLcword *cword) + PLwdatum *wdatum, PLcword *cword) { PLtsql_nsitem *ns; List *idents; @@ -2006,8 +2024,8 @@ pltsql_parse_tripword(char *word1, char *word2, char *word3, * reference, else ignore. */ ns = pltsql_ns_lookup(pltsql_ns_top(), false, - word1, word2, word3, - &nnames); + word1, word2, word3, + &nnames); if (ns != NULL && nnames == 2) { switch (ns->itemtype) @@ -2062,8 +2080,8 @@ pltsql_parse_wordtype(char *ident) * Do a lookup in the current namespace stack */ nse = pltsql_ns_lookup(pltsql_ns_top(), false, - ident, NULL, NULL, - NULL); + ident, NULL, NULL, + NULL); if (nse != NULL) { @@ -2141,10 +2159,10 @@ pltsql_parse_cwordtype(List *idents) * variables. */ nse = pltsql_ns_lookup(pltsql_ns_top(), false, - strVal(linitial(idents)), - strVal(lsecond(idents)), - NULL, - NULL); + strVal(linitial(idents)), + strVal(lsecond(idents)), + NULL, + NULL); if (nse != NULL && nse->itemtype == PLTSQL_NSTYPE_VAR) { @@ -2256,7 +2274,7 @@ pltsql_parse_wordrowtype(char *ident) /* Build and return the row type struct */ return pltsql_build_datatype(get_rel_type_id(classOid), -1, InvalidOid, - makeTypeName(ident)); + makeTypeName(ident)); } /* ---------- @@ -2291,7 +2309,7 @@ pltsql_parse_cwordrowtype(List *idents) /* Build and return the row type struct */ return pltsql_build_datatype(get_rel_type_id(classOid), -1, InvalidOid, - makeTypeNameFromNameList(idents)); + makeTypeNameFromNameList(idents)); } /* @@ -2305,7 +2323,7 @@ pltsql_parse_cwordrowtype(List *idents) */ PLtsql_variable * pltsql_build_variable(const char *refname, int lineno, PLtsql_type *dtype, - bool add2namespace) + bool add2namespace) { PLtsql_variable *result; @@ -2331,9 +2349,10 @@ pltsql_build_variable(const char *refname, int lineno, PLtsql_type *dtype, pltsql_adddatum((PLtsql_datum *) var); if (add2namespace) pltsql_ns_additem(PLTSQL_NSTYPE_VAR, - var->dno, - refname); + var->dno, + refname); result = (PLtsql_variable *) var; + break; } case PLTSQL_TTYPE_REC: @@ -2342,9 +2361,10 @@ pltsql_build_variable(const char *refname, int lineno, PLtsql_type *dtype, PLtsql_rec *rec; rec = pltsql_build_record(refname, lineno, - dtype, dtype->typoid, - add2namespace); + dtype, dtype->typoid, + add2namespace); result = (PLtsql_variable *) rec; + break; } case PLTSQL_TTYPE_PSEUDO: @@ -2353,6 +2373,7 @@ pltsql_build_variable(const char *refname, int lineno, PLtsql_type *dtype, errmsg("variable \"%s\" has pseudo-type %s", refname, format_type_be(dtype->typoid)))); result = NULL; /* keep compiler quiet */ + break; case PLTSQL_TTYPE_TBL: { @@ -2360,14 +2381,16 @@ pltsql_build_variable(const char *refname, int lineno, PLtsql_type *dtype, PLtsql_tbl *tbl; tbl = pltsql_build_table(refname, lineno, - dtype, dtype->typoid, - add2namespace); + dtype, dtype->typoid, + add2namespace); result = (PLtsql_variable *) tbl; + break; } default: elog(ERROR, "unrecognized ttype: %d", dtype->ttype); result = NULL; /* keep compiler quiet */ + break; } @@ -2379,8 +2402,8 @@ pltsql_build_variable(const char *refname, int lineno, PLtsql_type *dtype, */ PLtsql_rec * pltsql_build_record(const char *refname, int lineno, - PLtsql_type *dtype, Oid rectypeid, - bool add2namespace) + PLtsql_type *dtype, Oid rectypeid, + bool add2namespace) { PLtsql_rec *rec; @@ -2546,7 +2569,7 @@ pltsql_build_recfield(PLtsql_rec *rec, const char *fldname) */ PLtsql_type * pltsql_build_datatype(Oid typeOid, int32 typmod, - Oid collation, TypeName *origtypname) + Oid collation, TypeName *origtypname) { HeapTuple typeTup; PLtsql_type *typ; @@ -2802,7 +2825,7 @@ pltsql_start_datums(void) pltsql_nDatums = 0; /* This is short-lived, so needn't allocate in function's cxt */ pltsql_Datums = MemoryContextAlloc(pltsql_compile_tmp_cxt, - sizeof(PLtsql_datum *) * datums_alloc); + sizeof(PLtsql_datum *) * datums_alloc); /* datums_last tracks what's been seen by pltsql_add_initdatums() */ datums_last = 0; } @@ -2981,11 +3004,11 @@ compute_function_hashkey(FunctionCallInfo fcinfo, /* resolve any polymorphic argument types */ pltsql_resolve_polymorphic_argtypes(procStruct->pronargs, - hashkey->argtypes, - NULL, - fcinfo->flinfo->fn_expr, - forValidator, - NameStr(procStruct->proname)); + hashkey->argtypes, + NULL, + fcinfo->flinfo->fn_expr, + forValidator, + NameStr(procStruct->proname)); } } @@ -2997,9 +3020,9 @@ compute_function_hashkey(FunctionCallInfo fcinfo, */ static void pltsql_resolve_polymorphic_argtypes(int numargs, - Oid *argtypes, char *argmodes, - Node *call_expr, bool forValidator, - const char *proname) + Oid *argtypes, char *argmodes, + Node *call_expr, bool forValidator, + const char *proname) { int i; @@ -3077,9 +3100,9 @@ pltsql_HashTableInit(void) ctl.keysize = sizeof(PLtsql_func_hashkey); ctl.entrysize = sizeof(pltsql_HashEnt); pltsql_HashTable = hash_create("PLtsql function hash", - FUNCS_PER_USER, - &ctl, - HASH_ELEM | HASH_BLOBS); + FUNCS_PER_USER, + &ctl, + HASH_ELEM | HASH_BLOBS); } static PLtsql_function * @@ -3088,9 +3111,9 @@ pltsql_HashTableLookup(PLtsql_func_hashkey *func_key) pltsql_HashEnt *hentry; hentry = (pltsql_HashEnt *) hash_search(pltsql_HashTable, - (void *) func_key, - HASH_FIND, - NULL); + (void *) func_key, + HASH_FIND, + NULL); if (hentry) return hentry->function; else @@ -3099,15 +3122,15 @@ pltsql_HashTableLookup(PLtsql_func_hashkey *func_key) static void pltsql_HashTableInsert(PLtsql_function *function, - PLtsql_func_hashkey *func_key) + PLtsql_func_hashkey *func_key) { pltsql_HashEnt *hentry; bool found; hentry = (pltsql_HashEnt *) hash_search(pltsql_HashTable, - (void *) func_key, - HASH_ENTER, - &found); + (void *) func_key, + HASH_ENTER, + &found); if (found) elog(WARNING, "trying to insert a function that already exists"); @@ -3126,9 +3149,9 @@ pltsql_HashTableDelete(PLtsql_function *function) return; hentry = (pltsql_HashEnt *) hash_search(pltsql_HashTable, - (void *) function->fn_hashkey, - HASH_REMOVE, - NULL); + (void *) function->fn_hashkey, + HASH_REMOVE, + NULL); if (hentry == NULL) elog(WARNING, "trying to delete function that does not exist"); @@ -3138,17 +3161,18 @@ pltsql_HashTableDelete(PLtsql_function *function) /* helper function for compiled batch */ -int cache_compiled_batch(PLtsql_function *func); -PLtsql_function *find_cached_batch(int handle); -void delete_cached_batch(int handle); +int cache_compiled_batch(PLtsql_function *func); +PLtsql_function *find_cached_batch(int handle); +void delete_cached_batch(int handle); /* helper function to reset cache incase reset connection takes place */ -void reset_cached_batch(void); +void reset_cached_batch(void); -PLtsql_function * find_cached_batch(int handle) +PLtsql_function * +find_cached_batch(int handle) { PLtsql_func_hashkey hashkey; - PLtsql_function *func; + PLtsql_function *func; MemSet(&hashkey, 0, sizeof(PLtsql_func_hashkey)); /* use upper 32bit for funcOid */ @@ -3162,30 +3186,32 @@ PLtsql_function * find_cached_batch(int handle) return func; } -int cache_compiled_batch(PLtsql_function *func) +int +cache_compiled_batch(PLtsql_function *func) { PLtsql_func_hashkey hashkey; - int handle = cur_handle_id; + int handle = cur_handle_id; MemSet(&hashkey, 0, sizeof(PLtsql_func_hashkey)); - hashkey.funcOid = ((long) handle) << 32; /* use upper 32bit for funcOid */ + hashkey.funcOid = ((long) handle) << 32; /* use upper 32bit for funcOid */ hashkey.isTrigger = false; hashkey.isEventTrigger = false; hashkey.inputCollation = -1; - /* avoid overflow when wraparound*/ + /* avoid overflow when wraparound */ cur_handle_id = (cur_handle_id % INT32_MAX) + 1; - pltsql_HashTableInsert(func, &hashkey); + pltsql_HashTableInsert(func, &hashkey); return handle; } -void delete_cached_batch(int handle) +void +delete_cached_batch(int handle) { - PLtsql_function *func; + PLtsql_function *func; func = find_cached_batch(handle); - + if (func) { pltsql_HashTableDelete(func); @@ -3193,7 +3219,8 @@ void delete_cached_batch(int handle) } } -void reset_cached_batch() +void +reset_cached_batch() { while (cur_handle_id > 0) delete_cached_batch(cur_handle_id--); diff --git a/contrib/babelfishpg_tsql/src/pl_exec-2.c b/contrib/babelfishpg_tsql/src/pl_exec-2.c index a49c20d0ef..0b0058fa05 100644 --- a/contrib/babelfishpg_tsql/src/pl_exec-2.c +++ b/contrib/babelfishpg_tsql/src/pl_exec-2.c @@ -30,51 +30,51 @@ PLtsql_execstate *get_outermost_tsql_estate(int *nestlevel); * A SELECT statement that returns zero rows will leave the target(s) unchanged */ -static int exec_tsql_stmt(PLtsql_execstate *estate, PLtsql_stmt *stmt, PLtsql_stmt *save_estmt); -static int exec_stmt_print(PLtsql_execstate *estate, PLtsql_stmt_print *stmt); -static int exec_stmt_query_set(PLtsql_execstate *estate, PLtsql_stmt_query_set *stmt); -static int exec_stmt_try_catch(PLtsql_execstate *estate, PLtsql_stmt_try_catch *stmt); -static int exec_stmt_push_result(PLtsql_execstate *estate, PLtsql_stmt_push_result *stmt); -static int exec_stmt_exec(PLtsql_execstate *estate, PLtsql_stmt_exec *stmt); -static int exec_stmt_decl_table(PLtsql_execstate *estate, PLtsql_stmt_decl_table *stmt); -static int exec_stmt_return_table(PLtsql_execstate *estate, PLtsql_stmt_return_query *stmt); -static int exec_stmt_exec_batch(PLtsql_execstate *estate, PLtsql_stmt_exec_batch *stmt); -static int exec_stmt_exec_sp(PLtsql_execstate *estate, PLtsql_stmt_exec_sp *stmt); -static int exec_stmt_deallocate(PLtsql_execstate *estate, PLtsql_stmt_deallocate *stmt); -static int exec_stmt_decl_cursor(PLtsql_execstate *estate, PLtsql_stmt_decl_cursor *stmt); -static int exec_run_dml_with_output(PLtsql_execstate *estate, PLtsql_stmt_push_result *stmt, - Portal portal, PLtsql_expr *expr, CmdType cmd, ParamListInfo paramLI); -static int exec_stmt_usedb(PLtsql_execstate *estate, PLtsql_stmt_usedb *stmt); -static int exec_stmt_usedb_explain(PLtsql_execstate *estate, PLtsql_stmt_usedb *stmt, bool shouldRestoreDb); -static int exec_stmt_grantdb(PLtsql_execstate *estate, PLtsql_stmt_grantdb *stmt); -static int exec_stmt_insert_execute_select(PLtsql_execstate *estate, PLtsql_expr *expr); -static int exec_stmt_insert_bulk(PLtsql_execstate *estate, PLtsql_stmt_insert_bulk *expr); +static int exec_tsql_stmt(PLtsql_execstate *estate, PLtsql_stmt *stmt, PLtsql_stmt *save_estmt); +static int exec_stmt_print(PLtsql_execstate *estate, PLtsql_stmt_print *stmt); +static int exec_stmt_query_set(PLtsql_execstate *estate, PLtsql_stmt_query_set *stmt); +static int exec_stmt_try_catch(PLtsql_execstate *estate, PLtsql_stmt_try_catch *stmt); +static int exec_stmt_push_result(PLtsql_execstate *estate, PLtsql_stmt_push_result *stmt); +static int exec_stmt_exec(PLtsql_execstate *estate, PLtsql_stmt_exec *stmt); +static int exec_stmt_decl_table(PLtsql_execstate *estate, PLtsql_stmt_decl_table *stmt); +static int exec_stmt_return_table(PLtsql_execstate *estate, PLtsql_stmt_return_query *stmt); +static int exec_stmt_exec_batch(PLtsql_execstate *estate, PLtsql_stmt_exec_batch *stmt); +static int exec_stmt_exec_sp(PLtsql_execstate *estate, PLtsql_stmt_exec_sp *stmt); +static int exec_stmt_deallocate(PLtsql_execstate *estate, PLtsql_stmt_deallocate *stmt); +static int exec_stmt_decl_cursor(PLtsql_execstate *estate, PLtsql_stmt_decl_cursor *stmt); +static int exec_run_dml_with_output(PLtsql_execstate *estate, PLtsql_stmt_push_result *stmt, + Portal portal, PLtsql_expr *expr, CmdType cmd, ParamListInfo paramLI); +static int exec_stmt_usedb(PLtsql_execstate *estate, PLtsql_stmt_usedb *stmt); +static int exec_stmt_usedb_explain(PLtsql_execstate *estate, PLtsql_stmt_usedb *stmt, bool shouldRestoreDb); +static int exec_stmt_grantdb(PLtsql_execstate *estate, PLtsql_stmt_grantdb *stmt); +static int exec_stmt_insert_execute_select(PLtsql_execstate *estate, PLtsql_expr *expr); +static int exec_stmt_insert_bulk(PLtsql_execstate *estate, PLtsql_stmt_insert_bulk *expr); extern Datum pltsql_inline_handler(PG_FUNCTION_ARGS); -static char *transform_tsql_temp_tables(char * dynstmt); +static char *transform_tsql_temp_tables(char *dynstmt); static char *next_word(char *dyntext); static bool is_next_temptbl(char *dyntext); static bool is_char_identstart(char c); static bool is_char_identpart(char c); -void read_param_def(InlineCodeBlockArgs * args, const char *paramdefstr); -void cache_inline_args(PLtsql_function *func, InlineCodeBlockArgs *args); +void read_param_def(InlineCodeBlockArgs *args, const char *paramdefstr); +void cache_inline_args(PLtsql_function *func, InlineCodeBlockArgs *args); InlineCodeBlockArgs *create_args(int numargs); InlineCodeBlockArgs *clone_inline_args(InlineCodeBlockArgs *args); static void read_param_val(PLtsql_execstate *estate, List *params, InlineCodeBlockArgs *args, - FunctionCallInfo fcinfo, PLtsql_row *row); + FunctionCallInfo fcinfo, PLtsql_row *row); static bool check_spexecutesql_param(char *defmode, tsql_exec_param *p); -static int exec_eval_int(PLtsql_execstate *estate, PLtsql_expr *expr, bool *isNull); +static int exec_eval_int(PLtsql_execstate *estate, PLtsql_expr *expr, bool *isNull); int -execute_plan_and_push_result(PLtsql_execstate *estate, PLtsql_expr *expr, ParamListInfo paramLI); + execute_plan_and_push_result(PLtsql_execstate *estate, PLtsql_expr *expr, ParamListInfo paramLI); static void get_param_mode(List *params, int paramno, char **modes); extern void pltsql_update_cursor_row_count(char *curname, int64 row_count); extern void pltsql_update_cursor_last_operation(char *curname, int last_operation); -extern bool pltsql_declare_cursor(PLtsql_execstate *estate, PLtsql_var *var, PLtsql_expr* explicit_expr, int cursor_options); +extern bool pltsql_declare_cursor(PLtsql_execstate *estate, PLtsql_var *var, PLtsql_expr *explicit_expr, int cursor_options); extern char *pltsql_demangle_curname(char *curname); extern void enable_sp_cursor_find_param_hook(void); @@ -84,24 +84,24 @@ extern void reset_sp_cursor_params(); extern void pltsql_commit_not_required_impl_txn(PLtsql_execstate *estate); -int execute_batch(PLtsql_execstate *estate, char *batch, InlineCodeBlockArgs *args, List *params); -Oid get_role_oid(const char *rolename, bool missing_ok); -bool is_member_of_role(Oid member, Oid role); +int execute_batch(PLtsql_execstate *estate, char *batch, InlineCodeBlockArgs *args, List *params); +Oid get_role_oid(const char *rolename, bool missing_ok); +bool is_member_of_role(Oid member, Oid role); -extern PLtsql_function *find_cached_batch(int handle); +extern PLtsql_function *find_cached_batch(int handle); -extern SPIPlanPtr prepare_stmt_exec(PLtsql_execstate *estate, PLtsql_function *func, PLtsql_stmt_exec *stmt, bool keepplan); +extern SPIPlanPtr prepare_stmt_exec(PLtsql_execstate *estate, PLtsql_function *func, PLtsql_stmt_exec *stmt, bool keepplan); -extern int sp_prepare_count; +extern int sp_prepare_count; BulkCopyStmt *cstmt = NULL; -int insert_bulk_rows_per_batch = DEFAULT_INSERT_BULK_ROWS_PER_BATCH; -int insert_bulk_kilobytes_per_batch = DEFAULT_INSERT_BULK_PACKET_SIZE; -bool insert_bulk_keep_nulls = false; +int insert_bulk_rows_per_batch = DEFAULT_INSERT_BULK_ROWS_PER_BATCH; +int insert_bulk_kilobytes_per_batch = DEFAULT_INSERT_BULK_PACKET_SIZE; +bool insert_bulk_keep_nulls = false; -static int prev_insert_bulk_rows_per_batch = DEFAULT_INSERT_BULK_ROWS_PER_BATCH; -static int prev_insert_bulk_kilobytes_per_batch = DEFAULT_INSERT_BULK_PACKET_SIZE; +static int prev_insert_bulk_rows_per_batch = DEFAULT_INSERT_BULK_ROWS_PER_BATCH; +static int prev_insert_bulk_kilobytes_per_batch = DEFAULT_INSERT_BULK_PACKET_SIZE; static bool prev_insert_bulk_keep_nulls = false; /* return a underlying node if n is implicit casting and underlying node is a certain type of node */ @@ -112,20 +112,22 @@ static Node *get_underlying_node_from_implicit_casting(Node *n, NodeTag underlyi * return code (RETURN 41 + 1) of the most recently completed procedure * * Although unsatisfying, we keep the return code here instead of in the - * tuple that holds the OUT parameter values because a procedure needs to + * tuple that holds the OUT parameter values because a procedure needs to * deliver a return code *and* OUT values. It would be possible to add an - * extra attribute to the OUT value tuple (the new attribute would hold + * extra attribute to the OUT value tuple (the new attribute would hold * the return code), but this mechanism seems less intrusive. * * pltsql_proc_return_code is set when a procedure executes a RETURN * statement and is read when we execute an EXEC statement. */ -int pltsql_proc_return_code; +int pltsql_proc_return_code; -PLtsql_execstate *get_current_tsql_estate() +PLtsql_execstate * +get_current_tsql_estate() { ErrorContextCallback *plerrcontext = error_context_stack; + while (plerrcontext != NULL) { /* Check plerrcontext was created in T-SQL */ @@ -140,10 +142,12 @@ PLtsql_execstate *get_current_tsql_estate() return NULL; } -PLtsql_execstate *get_outermost_tsql_estate(int *nestlevel) +PLtsql_execstate * +get_outermost_tsql_estate(int *nestlevel) { PLtsql_execstate *estate = NULL; ErrorContextCallback *plerrcontext = error_context_stack; + *nestlevel = 0; while (plerrcontext != NULL) { @@ -162,7 +166,7 @@ PLtsql_execstate *get_outermost_tsql_estate(int *nestlevel) static int exec_tsql_stmt(PLtsql_execstate *estate, PLtsql_stmt *stmt, PLtsql_stmt *save_estmt) { - int rc; + int rc; switch ((int) stmt->cmd_type) { @@ -171,10 +175,10 @@ exec_tsql_stmt(PLtsql_execstate *estate, PLtsql_stmt *stmt, PLtsql_stmt *save_es break; case PLTSQL_STMT_INIT: - /* + + /* * This stmt contains a (possibly nil) list of assignment - * statements, each of which initializes a particular - * variable. + * statements, each of which initializes a particular variable. */ rc = exec_stmts(estate, ((PLtsql_stmt_init *) stmt)->inits); break; @@ -198,7 +202,7 @@ exec_tsql_stmt(PLtsql_execstate *estate, PLtsql_stmt *stmt, PLtsql_stmt *save_es case PLTSQL_STMT_EXEC_BATCH: rc = exec_stmt_exec_batch(estate, (PLtsql_stmt_exec_batch *) stmt); break; - + case PLTSQL_STMT_EXEC_SP: rc = exec_stmt_exec_sp(estate, (PLtsql_stmt_exec_sp *) stmt); break; @@ -219,32 +223,33 @@ exec_tsql_stmt(PLtsql_execstate *estate, PLtsql_stmt *stmt, PLtsql_stmt *save_es rc = exec_stmt_return_table(estate, (PLtsql_stmt_return_query *) stmt); break; - case PLTSQL_STMT_INSERT_BULK: - rc = exec_stmt_insert_bulk(estate, (PLtsql_stmt_insert_bulk *) stmt); - break; + case PLTSQL_STMT_INSERT_BULK: + rc = exec_stmt_insert_bulk(estate, (PLtsql_stmt_insert_bulk *) stmt); + break; default: estate->err_stmt = save_estmt; elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type); } - + return rc; } static int exec_stmt_print(PLtsql_execstate *estate, PLtsql_stmt_print *stmt) { - Datum formatdatum; - bool formatisnull; - Oid formattypeid; - int32 formattypmod; - char *extval; + Datum formatdatum; + bool formatisnull; + Oid formattypeid; + int32 formattypmod; + char *extval; StringInfoData query; const char *print_text; if (pltsql_explain_only) { - PLtsql_expr *expr_temp = (PLtsql_expr *) linitial(stmt->exprs); + PLtsql_expr *expr_temp = (PLtsql_expr *) linitial(stmt->exprs); + initStringInfo(&query); appendStringInfo(&query, "PRINT "); print_text = strip_select_from_expr(expr_temp); @@ -267,7 +272,7 @@ exec_stmt_print(PLtsql_execstate *estate, PLtsql_stmt_print *stmt) ereport(INFO, errmsg_internal("%s", extval)); - exec_set_rowcount(0); + exec_set_rowcount(0); if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->send_info) ((*pltsql_protocol_plugin_ptr)->send_info) (0, @@ -281,7 +286,7 @@ exec_stmt_print(PLtsql_execstate *estate, PLtsql_stmt_print *stmt) /* ---------- * exec_stmt_query_set Evaluate a query and assign the results to * the target specified by the user. This stmt - * implements TSQL semantics - a query that + * implements TSQL semantics - a query that * returns no rows leaves the target(s) untouched; * a query that returns more than one row will * assign the values found in the *last* row @@ -290,9 +295,9 @@ exec_stmt_print(PLtsql_execstate *estate, PLtsql_stmt_print *stmt) static int exec_stmt_query_set(PLtsql_execstate *estate, - PLtsql_stmt_query_set *stmt) + PLtsql_stmt_query_set *stmt) { - int rc; + int rc; /* * On the first call for this statement generate the plan, and detect @@ -302,9 +307,9 @@ exec_stmt_query_set(PLtsql_execstate *estate, exec_prepare_plan(estate, stmt->sqlstmt, CURSOR_OPT_PARALLEL_OK, true); /* - * If we started an implicit_transaction for this statement but - * the statement has a simple expression associated with them, - * we no longer require an implicit transaction + * If we started an implicit_transaction for this statement but the + * statement has a simple expression associated with them, we no longer + * require an implicit transaction */ if (estate->impl_txn_type == PLTSQL_IMPL_TRAN_START) { @@ -327,12 +332,12 @@ exec_stmt_query_set(PLtsql_execstate *estate, exec_set_found(estate, (SPI_processed != 0)); exec_set_found(estate, (SPI_processed == 0 ? 1 : 0)); exec_set_rowcount(SPI_processed); - break; + break; case SPI_OK_UPDATE_RETURNING: exec_set_found(estate, (SPI_processed != 0)); exec_set_found(estate, (SPI_processed == 0 ? 1 : 0)); exec_set_rowcount(SPI_processed); - break; + break; case SPI_ERROR_TRANSACTION: ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), @@ -352,11 +357,11 @@ exec_stmt_query_set(PLtsql_execstate *estate, errmsg("SELECT used with a command that cannot return data"))); /* - * A SELECT statement that returns zero rows will leave the - * target(s) unchanged + * A SELECT statement that returns zero rows will leave the target(s) + * unchanged * - * A SELECT statement that returns more than one row will assign - * the values in the *last* row. + * A SELECT statement that returns more than one row will assign the + * values in the *last* row. */ if (SPI_processed > 0) @@ -364,7 +369,7 @@ exec_stmt_query_set(PLtsql_execstate *estate, PLtsql_variable *target = (PLtsql_variable *) estate->datums[stmt->target->dno]; /* Put the last result row into the target */ - exec_move_row(estate, target, SPI_tuptable->vals[SPI_processed-1], SPI_tuptable->tupdesc); + exec_move_row(estate, target, SPI_tuptable->vals[SPI_processed - 1], SPI_tuptable->tupdesc); } /* Clean up */ @@ -385,20 +390,20 @@ exec_stmt_try_catch(PLtsql_execstate *estate, PLtsql_stmt_try_catch *stmt) MemoryContext oldcontext = CurrentMemoryContext; ResourceOwner oldowner = CurrentResourceOwner; ExprContext *old_eval_econtext = estate->eval_econtext; - ErrorData *save_cur_error = estate->cur_error->error; + ErrorData *save_cur_error = estate->cur_error->error; MemoryContext stmt_mcontext; estate->err_text = gettext_noop("during statement block entry"); /* - * We will need a stmt_mcontext to hold the error data if an error - * occurs. It seems best to force it to exist before entering the - * subtransaction, so that we reduce the risk of out-of-memory during - * error recovery, and because this greatly simplifies restoring the - * stmt_mcontext stack to the correct state after an error. We can - * ameliorate the cost of this by allowing the called statements to - * use this mcontext too; so we don't push it down here. + * We will need a stmt_mcontext to hold the error data if an error occurs. + * It seems best to force it to exist before entering the subtransaction, + * so that we reduce the risk of out-of-memory during error recovery, and + * because this greatly simplifies restoring the stmt_mcontext stack to + * the correct state after an error. We can ameliorate the cost of this + * by allowing the called statements to use this mcontext too; so we don't + * push it down here. */ stmt_mcontext = get_stmt_mcontext(estate); @@ -409,10 +414,10 @@ exec_stmt_try_catch(PLtsql_execstate *estate, PLtsql_stmt_try_catch *stmt) PG_TRY(); { /* - * We need to run the block's statements with a new eval_econtext - * that belongs to the current subtransaction; if we try to use - * the outer econtext then ExprContext shutdown callbacks will be - * called at the wrong times. + * We need to run the block's statements with a new eval_econtext that + * belongs to the current subtransaction; if we try to use the outer + * econtext then ExprContext shutdown callbacks will be called at the + * wrong times. */ pltsql_create_econtext(estate); @@ -449,20 +454,20 @@ exec_stmt_try_catch(PLtsql_execstate *estate, PLtsql_stmt_try_catch *stmt) Assert(stmt_mcontext == estate->stmt_mcontext); /* - * Revert to outer eval_econtext. (The inner one was - * automatically cleaned up during subxact exit.) + * Revert to outer eval_econtext. (The inner one was automatically + * cleaned up during subxact exit.) */ estate->eval_econtext = old_eval_econtext; } PG_CATCH(); { -// ErrorData *edata; +/* ErrorData *edata; */ estate->err_text = gettext_noop("during exception cleanup"); /* Save error info in our stmt_mcontext */ MemoryContextSwitchTo(stmt_mcontext); -// edata = CopyErrorData(); +/* edata = CopyErrorData(); */ FlushErrorState(); /* Abort the inner transaction */ @@ -473,20 +478,20 @@ exec_stmt_try_catch(PLtsql_execstate *estate, PLtsql_stmt_try_catch *stmt) /* * Set up the stmt_mcontext stack as though we had restored our * previous state and then done push_stmt_mcontext(). The push is - * needed so that statements in the exception handler won't - * clobber the error data that's in our stmt_mcontext. + * needed so that statements in the exception handler won't clobber + * the error data that's in our stmt_mcontext. */ estate->stmt_mcontext_parent = stmt_mcontext; estate->stmt_mcontext = NULL; /* - * Now we can delete any nested stmt_mcontexts that might have - * been created as children of ours. (Note: we do not immediately - * release any statement-lifespan data that might have been left - * behind in stmt_mcontext itself. We could attempt that by doing - * a MemoryContextReset on it before collecting the error data - * above, but it seems too risky to do any significant amount of - * work before collecting the error.) + * Now we can delete any nested stmt_mcontexts that might have been + * created as children of ours. (Note: we do not immediately release + * any statement-lifespan data that might have been left behind in + * stmt_mcontext itself. We could attempt that by doing a + * MemoryContextReset on it before collecting the error data above, + * but it seems too risky to do any significant amount of work before + * collecting the error.) */ MemoryContextDeleteChildren(stmt_mcontext); @@ -494,10 +499,9 @@ exec_stmt_try_catch(PLtsql_execstate *estate, PLtsql_stmt_try_catch *stmt) estate->eval_econtext = old_eval_econtext; /* - * Must clean up the econtext too. However, any tuple table made - * in the subxact will have been thrown away by SPI during subxact - * abort, so we don't need to (and mustn't try to) free the - * eval_tuptable. + * Must clean up the econtext too. However, any tuple table made in + * the subxact will have been thrown away by SPI during subxact abort, + * so we don't need to (and mustn't try to) free the eval_tuptable. */ estate->eval_tuptable = NULL; exec_eval_cleanup(estate); @@ -505,9 +509,9 @@ exec_stmt_try_catch(PLtsql_execstate *estate, PLtsql_stmt_try_catch *stmt) rc = exec_stmt(estate, stmt->handler); /* - * Restore previous state of cur_error, whether or not we executed - * a handler. This is needed in case an error got thrown from - * some inner block's exception handler. + * Restore previous state of cur_error, whether or not we executed a + * handler. This is needed in case an error got thrown from some + * inner block's exception handler. */ estate->cur_error->error = save_cur_error; @@ -558,7 +562,7 @@ exec_stmt_push_result(PLtsql_execstate *estate, uint64 processed = 0; DestReceiver *receiver; QueryCompletion qc; - + Assert(stmt->query != NULL); /* Handle naked SELECT stmt differently for INSERT ... EXECUTE */ @@ -571,16 +575,16 @@ exec_stmt_push_result(PLtsql_execstate *estate, SetRemoteDestReceiverParams(receiver, portal); if (PortalRun(portal, - FETCH_ALL, - true, /* always top level */ - true, - receiver, - receiver, - &qc)) - processed = portal->portalPos; - + FETCH_ALL, + true, /* always top level */ + true, + receiver, + receiver, + &qc)) + processed = portal->portalPos; + receiver->rDestroy(receiver); - + SPI_freetuptable(SPI_tuptable); SPI_cursor_close(portal); @@ -588,19 +592,19 @@ exec_stmt_push_result(PLtsql_execstate *estate, estate->eval_processed = processed; exec_set_rowcount(processed); - exec_set_found(estate, processed != 0); + exec_set_found(estate, processed != 0); return PLTSQL_RC_OK; } static int exec_run_dml_with_output(PLtsql_execstate *estate, PLtsql_stmt_push_result *stmt, - Portal portal, PLtsql_expr *expr, CmdType cmd, ParamListInfo paramLI) + Portal portal, PLtsql_expr *expr, CmdType cmd, ParamListInfo paramLI) { uint64 processed = 0; DestReceiver *receiver; QueryCompletion qc; - bool success = false; + bool success = false; int rc = 0; Assert(stmt->query != NULL); @@ -609,22 +613,22 @@ exec_run_dml_with_output(PLtsql_execstate *estate, PLtsql_stmt_push_result *stmt * Put the query and paramlist into the portal */ portal = SPI_cursor_open_with_paramlist(NULL, expr->plan, - paramLI, - estate->readonly_func); + paramLI, + estate->readonly_func); if (portal == NULL) elog(ERROR, "could not open implicit cursor for query \"%s\": %s", - expr->query, SPI_result_code_string(SPI_result)); + expr->query, SPI_result_code_string(SPI_result)); receiver = CreateDestReceiver(DestRemote); SetRemoteDestReceiverParams(receiver, portal); success = PortalRun(portal, - FETCH_ALL, - true, - true, - receiver, - receiver, - &qc); + FETCH_ALL, + true, + true, + receiver, + receiver, + &qc); if (success) { processed = (portal)->portalPos; @@ -660,60 +664,62 @@ exec_stmt_exec(PLtsql_execstate *estate, PLtsql_stmt_exec *stmt) SPIExecuteOptions options; bool need_path_reset = false; - Oid current_user_id = GetUserId(); - char *cur_dbname = get_cur_db_name(); + Oid current_user_id = GetUserId(); + char *cur_dbname = get_cur_db_name(); /* fetch current search_path */ - char *old_search_path = NULL; - char *new_search_path; + char *old_search_path = NULL; + char *new_search_path; + estate->db_name = NULL; if (stmt->proc_name == NULL) stmt->proc_name = ""; if (stmt->is_cross_db) { - char *login = GetUserNameFromId(GetSessionUserId(), false); - char *user = get_user_for_database(stmt->db_name); + char *login = GetUserNameFromId(GetSessionUserId(), false); + char *user = get_user_for_database(stmt->db_name); - estate->db_name = stmt->db_name; - if(user) + estate->db_name = stmt->db_name; + if (user) SetCurrentRoleId(GetSessionUserId(), false); else ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_DATABASE), - errmsg("The server principal \"%s\" is not able to access " - "the database \"%s\" under the current security context", - login, stmt->db_name))); + (errcode(ERRCODE_UNDEFINED_DATABASE), + errmsg("The server principal \"%s\" is not able to access " + "the database \"%s\" under the current security context", + login, stmt->db_name))); } - /* - * "sp_describe_first_result_set" needs special handling. It is a - * sys function and satisfies the below condition and it appends "master_dbo" + /* + * "sp_describe_first_result_set" needs special handling. It is a sys + * function and satisfies the below condition and it appends "master_dbo" * to the search path which is not required for sys functions. */ if (strcmp(stmt->proc_name, "sp_describe_first_result_set") != 0) { if (strncmp(stmt->proc_name, "sp_", 3) == 0 && strcmp(cur_dbname, "master") != 0 - && ((stmt->schema_name == NULL || stmt->schema_name[0] == (char)'\0') || strcmp(stmt->schema_name, "dbo") == 0)) + && ((stmt->schema_name == NULL || stmt->schema_name[0] == (char) '\0') || strcmp(stmt->schema_name, "dbo") == 0)) + { + if (!old_search_path) { - if (!old_search_path) - { - List *path_oids = fetch_search_path(false); - old_search_path = flatten_search_path(path_oids); - list_free(path_oids); - } - new_search_path = psprintf("%s, master_dbo", old_search_path); - - /* Add master_dbo to the new search path */ - (void) set_config_option("search_path", new_search_path, - PGC_USERSET, PGC_S_SESSION, - GUC_ACTION_SAVE, true, 0, false); - SetCurrentRoleId(GetSessionUserId(), false); - need_path_reset = true; + List *path_oids = fetch_search_path(false); + + old_search_path = flatten_search_path(path_oids); + list_free(path_oids); } + new_search_path = psprintf("%s, master_dbo", old_search_path); + + /* Add master_dbo to the new search path */ + (void) set_config_option("search_path", new_search_path, + PGC_USERSET, PGC_S_SESSION, + GUC_ACTION_SAVE, true, 0, false); + SetCurrentRoleId(GetSessionUserId(), false); + need_path_reset = true; + } } - if (stmt->schema_name != NULL && stmt->schema_name[0] != (char)'\0') - estate->schema_name = stmt->schema_name; + if (stmt->schema_name != NULL && stmt->schema_name[0] != (char) '\0') + estate->schema_name = stmt->schema_name; else estate->schema_name = NULL; @@ -723,28 +729,30 @@ exec_stmt_exec(PLtsql_execstate *estate, PLtsql_stmt_exec *stmt) SPIPlanPtr plan = expr->plan; ParamListInfo paramLI; PLtsql_var *return_code; - Query* query; - TargetEntry *target; /* used for scalar function */ - Oid rettype; /* used for scalar function */ - int32 rettypmod; /* used for scalar function */ - bool is_scalar_func; + Query *query; + TargetEntry *target; /* used for scalar function */ + Oid rettype; /* used for scalar function */ + int32 rettypmod; /* used for scalar function */ + bool is_scalar_func; + /* for EXEC as part of inline code under INSERT ... EXECUTE */ Tuplestorestate *tss; DestReceiver *dest; - + if (plan == NULL) plan = prepare_stmt_exec(estate, estate->func, stmt, estate->atomic); /* - * If we will deal with scalar function, we need to know the correct return-type. + * If we will deal with scalar function, we need to know the correct + * return-type. */ query = linitial_node(Query, ((CachedPlanSource *) linitial(plan->plancache_list))->query_list); if (query->commandType == CMD_SELECT) { - Node* node; - FuncExpr *funcexpr; - HeapTuple func_tuple; + Node *node; + FuncExpr *funcexpr; + HeapTuple func_tuple; if (query->targetList == NULL || list_length(query->targetList) != 1) elog(ERROR, "scalar function on EXEC statement does not have exactly 1 target"); @@ -755,14 +763,14 @@ exec_stmt_exec(PLtsql_execstate *estate, PLtsql_stmt_exec *stmt) if (target->expr == NULL || !IsA(target->expr, FuncExpr)) elog(ERROR, "scalar function on EXEC statement does not have scalar function target"); - funcexpr = (FuncExpr*) target->expr; + funcexpr = (FuncExpr *) target->expr; func_tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcexpr->funcid)); if (!HeapTupleIsValid(func_tuple)) elog(ERROR, "cache lookup failed for function %u", funcexpr->funcid); - rettype = exprType((Node*) funcexpr); - rettypmod = exprTypmod((Node*) funcexpr); + rettype = exprType((Node *) funcexpr); + rettypmod = exprTypmod((Node *) funcexpr); ReleaseSysCache(func_tuple); @@ -776,8 +784,11 @@ exec_stmt_exec(PLtsql_execstate *estate, PLtsql_stmt_exec *stmt) stmt->is_scalar_func = is_scalar_func; /* T-SQL doens't allow call prcedure in function */ - if (estate->func && estate->func->fn_oid != InvalidOid && estate->func->fn_prokind == PROKIND_FUNCTION && estate->func->fn_is_trigger == PLTSQL_NOT_TRIGGER /* check EXEC is running in the body of function */ - && !is_scalar_func) /* in case of EXEC on scalar function, it is allowed in T-SQL. do not throw an error */ + if (estate->func && estate->func->fn_oid != InvalidOid && estate->func->fn_prokind == PROKIND_FUNCTION && estate->func->fn_is_trigger == PLTSQL_NOT_TRIGGER /* check EXEC is running + * in the body of + * function */ + && !is_scalar_func) /* in case of EXEC on scalar function, it is + * allowed in T-SQL. do not throw an error */ { ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), @@ -807,13 +818,13 @@ exec_stmt_exec(PLtsql_execstate *estate, PLtsql_stmt_exec *stmt) if (is_scalar_func) { - funcexpr = (FuncExpr*) target->expr; + funcexpr = (FuncExpr *) target->expr; } else { - /* - * Get the parsed CallStmt, and look up the called procedure - */ + /* + * Get the parsed CallStmt, and look up the called procedure + */ node = query->utilityStmt; if (node == NULL || !IsA(node, CallStmt)) elog(ERROR, "query for CALL statement is not a CallStmt"); @@ -875,9 +886,10 @@ exec_stmt_exec(PLtsql_execstate *estate, PLtsql_stmt_exec *stmt) parammodes[i] != PROARGMODE_INOUT && parammodes[i] != PROARGMODE_OUT) { - /* - * If an INOUT arg is called without OUTPUT, it should be treated like an - * IN param. Put -1 to param id. We can skip assigning actual value. + /* + * If an INOUT arg is called without OUTPUT, it should + * be treated like an IN param. Put -1 to param id. We + * can skip assigning actual value. */ row->varnos[nfields++] = -1; } @@ -891,16 +903,19 @@ exec_stmt_exec(PLtsql_execstate *estate, PLtsql_stmt_exec *stmt) else if (get_underlying_node_from_implicit_casting(n, T_Param) != NULL) { /* - * Other than PL/pgsql, T-SQL allows implicit casting in INOUT and OUT params. + * Other than PL/pgsql, T-SQL allows implicit casting + * in INOUT and OUT params. * - * In PG, if implcit casting is added (i.e. int->bigint), it throws an error - * "corresponding argument is not writable" (see the else-clause) + * In PG, if implcit casting is added (i.e. + * int->bigint), it throws an error "corresponding + * argument is not writable" (see the else-clause) * - * In T-SQL, if arg node is an implicit casting, we will strip the casting. - * Actual casting will be done at value assignement with validity check. + * In T-SQL, if arg node is an implicit casting, we + * will strip the casting. Actual casting will be done + * at value assignement with validity check. */ - Param *param = (Param *) get_underlying_node_from_implicit_casting(n, T_Param); + Param *param = (Param *) get_underlying_node_from_implicit_casting(n, T_Param); /* paramid is offset by 1 (see make_datum_param()) */ row->varnos[nfields++] = param->paramid - 1; @@ -908,14 +923,18 @@ exec_stmt_exec(PLtsql_execstate *estate, PLtsql_stmt_exec *stmt) else if (argmodes[i] == PROARGMODE_INOUT && IsA(n, Const)) { /* - * T-SQL allows to pass constant value as an output parameter. - * Put -1 to param id. We can skip assigning actual value. + * T-SQL allows to pass constant value as an output + * parameter. Put -1 to param id. We can skip + * assigning actual value. */ row->varnos[nfields++] = -1; } else if (argmodes[i] == PROARGMODE_INOUT && get_underlying_node_from_implicit_casting(n, T_Const) != NULL) { - /* mixture case of implicit casting + CONST. We can skip assigning actual value. */ + /* + * mixture case of implicit casting + CONST. We can + * skip assigning actual value. + */ row->varnos[nfields++] = -1; } else @@ -965,11 +984,11 @@ exec_stmt_exec(PLtsql_execstate *estate, PLtsql_stmt_exec *stmt) SetTuplestoreDestReceiverParams(dest, tss, CurrentMemoryContext, false, NULL, NULL); dest->rStartup(dest, -1, estate->rsi->expectedDesc); - callstmt = (CallStmt *)node; + callstmt = (CallStmt *) node; callstmt->relation = InvalidOid; callstmt->attrnos = NULL; - callstmt->retdesc = (void *)estate->rsi->expectedDesc; - callstmt->dest = (void *)dest; + callstmt->retdesc = (void *) estate->rsi->expectedDesc; + callstmt->dest = (void *) dest; } paramLI = setup_param_list(estate, expr); @@ -991,8 +1010,8 @@ exec_stmt_exec(PLtsql_execstate *estate, PLtsql_stmt_exec *stmt) topEntry != simple_econtext_stack) { /* - * If we are in a new transaction after the call, we need to build new - * simple-expression infrastructure. + * If we are in a new transaction after the call, we need to build + * new simple-expression infrastructure. */ if (estate->use_shared_simple_eval_state) estate->simple_eval_estate = NULL; @@ -1000,7 +1019,7 @@ exec_stmt_exec(PLtsql_execstate *estate, PLtsql_stmt_exec *stmt) } /* - * Copy the procedure's return code into the specified variable + * Copy the procedure's return code into the specified variable * * Note that the procedure stores its return code in the global * variable named pltsql_proc_return_code. @@ -1012,12 +1031,13 @@ exec_stmt_exec(PLtsql_execstate *estate, PLtsql_stmt_exec *stmt) if (is_scalar_func) { /* - * In case of scalar function, we should have 1-row/1-column result. - * Get the result data and assign into return_code. We should use exec_assign_value() - * to handle implicit casting correctly. + * In case of scalar function, we should have 1-row/1-column + * result. Get the result data and assign into return_code. We + * should use exec_assign_value() to handle implicit casting + * correctly. */ - Datum retval; - bool isnull; + Datum retval; + bool isnull; if (SPI_processed != 1) elog(ERROR, "scalar function result does not return exactly one row"); @@ -1034,19 +1054,21 @@ exec_stmt_exec(PLtsql_execstate *estate, PLtsql_stmt_exec *stmt) if (estate->insert_exec) { /* - * For EXEC under INSERT ... EXECUTE, get the rows sent back by the - * CallStmt, and store them into estate->tuple_store so that at the - * end of function execution they will be sent to the right place. + * For EXEC under INSERT ... EXECUTE, get the rows sent back by + * the CallStmt, and store them into estate->tuple_store so that + * at the end of function execution they will be sent to the right + * place. */ TupleTableSlot *slot = MakeSingleTupleTableSlot(estate->rsi->expectedDesc, &TTSOpsMinimalTuple); + if (estate->tuple_store == NULL) - exec_init_tuple_store(estate); + exec_init_tuple_store(estate); for (;;) { if (!tuplestore_gettupleslot(tss, true, false, slot)) - break; + break; tuplestore_puttupleslot(estate->tuple_store, slot); ExecClearTuple(slot); } @@ -1061,20 +1083,22 @@ exec_stmt_exec(PLtsql_execstate *estate, PLtsql_stmt_exec *stmt) if (need_path_reset) { (void) set_config_option("search_path", old_search_path, - PGC_USERSET, PGC_S_SESSION, - GUC_ACTION_SAVE, true, 0, false); + PGC_USERSET, PGC_S_SESSION, + GUC_ACTION_SAVE, true, 0, false); SetCurrentRoleId(current_user_id, false); } if (stmt->is_cross_db) SetCurrentRoleId(current_user_id, false); + /* * If we aren't saving the plan, unset the pointer. Note that it * could have been unset already, in case of a recursive call. */ if (expr->plan && !expr->plan->saved) { - SPIPlanPtr plan = expr->plan; + SPIPlanPtr plan = expr->plan; + expr->plan = NULL; SPI_freeplan(plan); } @@ -1088,14 +1112,15 @@ exec_stmt_exec(PLtsql_execstate *estate, PLtsql_stmt_exec *stmt) if (need_path_reset) { (void) set_config_option("search_path", old_search_path, - PGC_USERSET, PGC_S_SESSION, - GUC_ACTION_SAVE, true, 0, false); + PGC_USERSET, PGC_S_SESSION, + GUC_ACTION_SAVE, true, 0, false); SetCurrentRoleId(current_user_id, false); } if (expr->plan && !expr->plan->saved) { - SPIPlanPtr plan = expr->plan; + SPIPlanPtr plan = expr->plan; + expr->plan = NULL; SPI_freeplan(plan); } @@ -1137,15 +1162,16 @@ exec_stmt_exec(PLtsql_execstate *estate, PLtsql_stmt_exec *stmt) static int exec_stmt_decl_table(PLtsql_execstate *estate, PLtsql_stmt_decl_table *stmt) { - char *tblname; - char *query; + char *tblname; + char *query; PLtsql_tbl *var = (PLtsql_tbl *) (estate->datums[stmt->dno]); - int rc; - bool isnull; - int old_client_min_messages; - bool old_pltsql_explain_only = pltsql_explain_only; + int rc; + bool isnull; + int old_client_min_messages; + bool old_pltsql_explain_only = pltsql_explain_only; - pltsql_explain_only = false; /* Create temporary table even in EXPLAIN ONLY mode */ + pltsql_explain_only = false; /* Create temporary table even in EXPLAIN + * ONLY mode */ PG_TRY(); { @@ -1160,15 +1186,16 @@ exec_stmt_decl_table(PLtsql_execstate *estate, PLtsql_stmt_decl_table *stmt) tblname = psprintf("%s_%d", var->refname, estate->nestlevel); if (stmt->tbltypname) query = psprintf("CREATE TEMPORARY TABLE IF NOT EXISTS %s (like %s including all)", - tblname, stmt->tbltypname); + tblname, stmt->tbltypname); else query = psprintf("CREATE TEMPORARY TABLE IF NOT EXISTS %s%s", - tblname, stmt->coldef); + tblname, stmt->coldef); /* - * If a table with the same name already exists, we should just use that - * table, and ignore the NOTICE of "relation already exists, skipping". - */ + * If a table with the same name already exists, we should just use + * that table, and ignore the NOTICE of "relation already exists, + * skipping". + */ old_client_min_messages = client_min_messages; client_min_messages = WARNING; rc = SPI_execute(query, false, 0); @@ -1179,7 +1206,8 @@ exec_stmt_decl_table(PLtsql_execstate *estate, PLtsql_stmt_decl_table *stmt) if (old_pltsql_explain_only) { /* Restore EXPLAIN ONLY mode and append explain info */ - StringInfo strinfo = makeStringInfo(); + StringInfo strinfo = makeStringInfo(); + appendStringInfo(strinfo, "DECLARE TABLE %s", var->refname); pltsql_explain_only = true; @@ -1197,7 +1225,8 @@ exec_stmt_decl_table(PLtsql_execstate *estate, PLtsql_stmt_decl_table *stmt) } PG_CATCH(); { - pltsql_explain_only = old_pltsql_explain_only; /* Recover EXPLAIN ONLY mode */ + pltsql_explain_only = old_pltsql_explain_only; /* Recover EXPLAIN ONLY + * mode */ PG_RE_THROW(); } PG_END_TRY(); @@ -1216,7 +1245,7 @@ static int exec_stmt_return_table(PLtsql_execstate *estate, PLtsql_stmt_return_query *stmt) { PLtsql_expr *expr; - PLtsql_tbl *tbl; + PLtsql_tbl *tbl; MemoryContext oldcontext; tbl = (PLtsql_tbl *) (estate->datums[estate->func->out_param_varno]); @@ -1227,11 +1256,11 @@ exec_stmt_return_table(PLtsql_execstate *estate, PLtsql_stmt_return_query *stmt) oldcontext = MemoryContextSwitchTo(estate->func->fn_cxt); expr = palloc0(sizeof(PLtsql_expr)); - expr->query = psprintf("select * from %s", tbl->tblname); - expr->plan = NULL; - expr->paramnos = NULL; - expr->rwparam = -1; - expr->ns = pltsql_ns_top(); + expr->query = psprintf("select * from %s", tbl->tblname); + expr->plan = NULL; + expr->paramnos = NULL; + expr->rwparam = -1; + expr->ns = pltsql_ns_top(); MemoryContextSwitchTo(oldcontext); @@ -1246,29 +1275,31 @@ exec_stmt_return_table(PLtsql_execstate *estate, PLtsql_stmt_return_query *stmt) static int exec_stmt_exec_batch(PLtsql_execstate *estate, PLtsql_stmt_exec_batch *stmt) { - Datum query; - bool isnull; - Oid restype; - int32 restypmod; - char *querystr; + Datum query; + bool isnull; + Oid restype; + int32 restypmod; + char *querystr; InlineCodeBlock *codeblock; volatile LocalTransactionId before_lxid; LocalTransactionId after_lxid; SimpleEcontextStackEntry *topEntry; volatile int save_nestlevel; volatile int scope_level; - char *old_db_name = get_cur_db_name(); - char *cur_db_name = NULL; - LOCAL_FCINFO(fcinfo,1); + char *old_db_name = get_cur_db_name(); + char *cur_db_name = NULL; + + LOCAL_FCINFO(fcinfo, 1); PG_TRY(); { - /* - * First we evaluate the string expression. Its result is the - * querystring we have to execute. - */ + /* + * First we evaluate the string expression. Its result is the + * querystring we have to execute. + */ query = exec_eval_expr(estate, stmt->expr, &isnull, &restype, &restypmod); - if (isnull) { + if (isnull) + { /* No op in case of null */ return PLTSQL_RC_OK; } @@ -1300,7 +1331,7 @@ exec_stmt_exec_batch(PLtsql_execstate *estate, PLtsql_stmt_exec_batch *stmt) { /* Restore past settings */ cur_db_name = get_cur_db_name(); - if(strcmp(cur_db_name, old_db_name) != 0) + if (strcmp(cur_db_name, old_db_name) != 0) set_session_properties(old_db_name); pltsql_revert_guc(save_nestlevel); @@ -1312,8 +1343,8 @@ exec_stmt_exec_batch(PLtsql_execstate *estate, PLtsql_stmt_exec_batch *stmt) /* * This logic is similar to what we do in exec_stmt_exec_spexecutesql(). - * If we are in a different transaction here, we need to build - * new simple-expression infrastructure. + * If we are in a different transaction here, we need to build new + * simple-expression infrastructure. */ if (before_lxid != after_lxid || simple_econtext_stack == NULL || @@ -1330,25 +1361,25 @@ exec_stmt_exec_batch(PLtsql_execstate *estate, PLtsql_stmt_exec_batch *stmt) int execute_batch(PLtsql_execstate *estate, char *batch, InlineCodeBlockArgs *args, List *params) { - Datum retval; + Datum retval; volatile LocalTransactionId before_lxid; LocalTransactionId after_lxid; SimpleEcontextStackEntry *topEntry; - PLtsql_row * row = NULL; - FmgrInfo flinfo; - InlineCodeBlock *codeblock = makeNode(InlineCodeBlock); + PLtsql_row *row = NULL; + FmgrInfo flinfo; + InlineCodeBlock *codeblock = makeNode(InlineCodeBlock); /* - * In case of SP_PREPARE via RPC numargs will be 0 so we only - * need to allocate 2 indexes of memory. + * In case of SP_PREPARE via RPC numargs will be 0 so we only need to + * allocate 2 indexes of memory. */ FunctionCallInfo fcinfo = palloc0(SizeForFunctionCallInfo((args) ? args->numargs + 2 : 2)); - /* - * 1. Build code block to store SQL query + /* + * 1. Build code block to store SQL query */ codeblock->source_text = batch; - codeblock->atomic = false; /* sp_executesql could not be top level */ + codeblock->atomic = false; /* sp_executesql could not be top level */ /* * 2. Build fcinfo to pack all function info @@ -1364,8 +1395,8 @@ execute_batch(PLtsql_execstate *estate, char *batch, InlineCodeBlockArgs *args, if (args) { /* - * We have to assign the param declaration info at the last because we may - * need to change the param mode in the above process. + * We have to assign the param declaration info at the last because we + * may need to change the param mode in the above process. */ fcinfo->nargs += 1; fcinfo->args[1].value = PointerGetDatum(args); @@ -1375,9 +1406,10 @@ execute_batch(PLtsql_execstate *estate, char *batch, InlineCodeBlockArgs *args, { /* SP_PREPAR may pass NULL, but it could not have params */ Assert(estate); + /* - * 3. Read parameter values, insert OUT parameter info in - * the row Datum. + * 3. Read parameter values, insert OUT parameter info in the row + * Datum. */ row = (PLtsql_row *) palloc0(sizeof(PLtsql_row)); row->dtype = PLTSQL_DTYPE_ROW; @@ -1385,15 +1417,15 @@ execute_batch(PLtsql_execstate *estate, char *batch, InlineCodeBlockArgs *args, row->lineno = -1; row->varnos = (int *) palloc(sizeof(int) * args->numargs); - /* + /* * Load in the param definition */ /* Safety check */ if (fcinfo->nargs > list_length(params) + 2) ereport(ERROR, (errcode(ERRCODE_TOO_MANY_ARGUMENTS), - errmsg("cannot pass more than %d arguments to a procedure", - list_length(params)))); + errmsg("cannot pass more than %d arguments to a procedure", + list_length(params)))); read_param_val(estate, params, args, fcinfo, row); } @@ -1402,8 +1434,8 @@ execute_batch(PLtsql_execstate *estate, char *batch, InlineCodeBlockArgs *args, before_lxid = MyProc->lxid; topEntry = simple_econtext_stack; - /* - * 4. Call inline handler to execute the whole statement + /* + * 4. Call inline handler to execute the whole statement */ fcinfo->isnull = true; PG_TRY(); @@ -1450,7 +1482,7 @@ execute_batch(PLtsql_execstate *estate, char *batch, InlineCodeBlockArgs *args, /* * 5. Got return value, make assignment to target variables */ - if (row) + if (row) { if (retval) exec_move_row_from_datum(estate, (PLtsql_variable *) row, retval); @@ -1465,14 +1497,14 @@ execute_batch(PLtsql_execstate *estate, char *batch, InlineCodeBlockArgs *args, } static InlineCodeBlockArgs * -evaluate_sp_cursor_param_def(PLtsql_execstate *estate, PLtsql_expr *stmt_param_def, const char* proc_name) +evaluate_sp_cursor_param_def(PLtsql_execstate *estate, PLtsql_expr *stmt_param_def, const char *proc_name) { InlineCodeBlockArgs *args = NULL; - Datum paramdef; - char *paramdefstr; - bool isnull; - Oid restype; - int32 restypmod; + Datum paramdef; + char *paramdefstr; + bool isnull; + Oid restype; + int32 restypmod; args = create_args(0); @@ -1484,16 +1516,17 @@ evaluate_sp_cursor_param_def(PLtsql_execstate *estate, PLtsql_expr *stmt_param_d if (!isnull) { paramdefstr = convert_value_to_string(estate, paramdef, restype); - if (strlen(paramdefstr) > 0) /* empty string should be treated as same as NULL */ + if (strlen(paramdefstr) > 0) /* empty string should be treated as + * same as NULL */ { read_param_def(args, paramdefstr); reset_sp_cursor_params(); - for (int i=0; inumargs; ++i) + for (int i = 0; i < args->numargs; ++i) { if (args->argmodes[i] != FUNC_PARAM_IN) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("output argument is not supported in %s yet", proc_name))); + errmsg("output argument is not supported in %s yet", proc_name))); add_sp_cursor_param(args->argnames[i]); } @@ -1506,17 +1539,17 @@ evaluate_sp_cursor_param_def(PLtsql_execstate *estate, PLtsql_expr *stmt_param_d static void evaluate_sp_cursor_param_values(PLtsql_execstate *estate, int paramno, List *params, Datum **values, char **nulls) { - Oid rettype; - int32 rettypmod; - ListCell *lc; - int i = 0; - bool isnull; + Oid rettype; + int32 rettypmod; + ListCell *lc; + int i = 0; + bool isnull; if (paramno <= 0) return; - Assert(values); /* should be provided by caller */ - Assert(nulls); /* should be provided by caller */ + Assert(values); /* should be provided by caller */ + Assert(nulls); /* should be provided by caller */ (*values) = (Datum *) palloc0(sizeof(Datum) * paramno); (*nulls) = (char *) palloc0(sizeof(char) * paramno); @@ -1525,12 +1558,13 @@ evaluate_sp_cursor_param_values(PLtsql_execstate *estate, int paramno, List *par { tsql_exec_param *p = (tsql_exec_param *) lfirst(lc); PLtsql_expr *expr = p->expr; + if (p->name != NULL) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("named argument is not supported in sp_cursoropen yet"))); + errmsg("named argument is not supported in sp_cursoropen yet"))); if (p->mode != FUNC_PARAM_IN) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("output argument is not supported in sp_cursoropen yet"))); + errmsg("output argument is not supported in sp_cursoropen yet"))); (*values)[i] = exec_eval_expr(estate, expr, &isnull, &rettype, &rettypmod); if (isnull) @@ -1543,512 +1577,518 @@ evaluate_sp_cursor_param_values(PLtsql_execstate *estate, int paramno, List *par static int exec_stmt_exec_sp(PLtsql_execstate *estate, PLtsql_stmt_exec_sp *stmt) { - int cursor_handle; - int prepared_handle; - Datum val; - bool isnull; - Oid restype; - int32 restypmod; - char *querystr; - int ret = 0; - - switch(stmt->sp_type_code) + int cursor_handle; + int prepared_handle; + Datum val; + bool isnull; + Oid restype; + int32 restypmod; + char *querystr; + int ret = 0; + + switch (stmt->sp_type_code) { case PLTSQL_EXEC_SP_CURSOR: - { - int opttype; - int rownum; - char *tablename; + { + int opttype; + int rownum; + char *tablename; - cursor_handle = exec_eval_int(estate, stmt->handle, &isnull); - if (isnull) - ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("cursor argument of sp_cursor is null"))); + cursor_handle = exec_eval_int(estate, stmt->handle, &isnull); + if (isnull) + ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("cursor argument of sp_cursor is null"))); - opttype = exec_eval_int(estate, stmt->opt1, &isnull); - if (isnull) - ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("opttype argument of sp_cursor is null"))); + opttype = exec_eval_int(estate, stmt->opt1, &isnull); + if (isnull) + ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("opttype argument of sp_cursor is null"))); - rownum = exec_eval_int(estate, stmt->opt2, &isnull); - if (isnull) - ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("rownum argument of sp_cursor is null"))); + rownum = exec_eval_int(estate, stmt->opt2, &isnull); + if (isnull) + ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("rownum argument of sp_cursor is null"))); - val = exec_eval_expr(estate, stmt->opt3, &isnull, &restype, &restypmod); - if (isnull) - ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("table argument of sp_cursor is null"))); - tablename = convert_value_to_string(estate, val, restype); + val = exec_eval_expr(estate, stmt->opt3, &isnull, &restype, &restypmod); + if (isnull) + ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("table argument of sp_cursor is null"))); + tablename = convert_value_to_string(estate, val, restype); - ret = execute_sp_cursor(cursor_handle, opttype, rownum, tablename, stmt->stropt); - if (ret > 0) - ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("sp_cursor failed: %d", ret))); + ret = execute_sp_cursor(cursor_handle, opttype, rownum, tablename, stmt->stropt); + if (ret > 0) + ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("sp_cursor failed: %d", ret))); - break; - } + break; + } case PLTSQL_EXEC_SP_CURSOROPEN: - { - int scrollopt; - int ccopt; - int rowcount; - bool scrollopt_null = true; - bool ccopt_null = true; - bool rowcount_null = true; - InlineCodeBlockArgs *args = NULL; - int paramno = stmt->paramno; - Datum *values = NULL; - char *nulls = NULL; - - /* evaulate query string */ - val = exec_eval_expr(estate, stmt->query, &isnull, &restype, &restypmod); - if (isnull) - ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("stmt argument of sp_cursoropen is null"))); - querystr = convert_value_to_string(estate, val, restype); - - if (stmt->opt1 != NULL) - scrollopt = exec_eval_int(estate, stmt->opt1, &scrollopt_null); - if (stmt->opt2 != NULL) - ccopt = exec_eval_int(estate, stmt->opt2, &ccopt_null); - if (stmt->opt3 != NULL) - rowcount = exec_eval_int(estate, stmt->opt3, &rowcount_null); - - /* evalaute parameter definition */ - args = evaluate_sp_cursor_param_def(estate, stmt->param_def, "sp_cursoropen"); - if (args->numargs != stmt->paramno) - ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("param definition mismatches with inputs"))); + { + int scrollopt; + int ccopt; + int rowcount; + bool scrollopt_null = true; + bool ccopt_null = true; + bool rowcount_null = true; + InlineCodeBlockArgs *args = NULL; + int paramno = stmt->paramno; + Datum *values = NULL; + char *nulls = NULL; + + /* evaulate query string */ + val = exec_eval_expr(estate, stmt->query, &isnull, &restype, &restypmod); + if (isnull) + ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("stmt argument of sp_cursoropen is null"))); + querystr = convert_value_to_string(estate, val, restype); + + if (stmt->opt1 != NULL) + scrollopt = exec_eval_int(estate, stmt->opt1, &scrollopt_null); + if (stmt->opt2 != NULL) + ccopt = exec_eval_int(estate, stmt->opt2, &ccopt_null); + if (stmt->opt3 != NULL) + rowcount = exec_eval_int(estate, stmt->opt3, &rowcount_null); + + /* evalaute parameter definition */ + args = evaluate_sp_cursor_param_def(estate, stmt->param_def, "sp_cursoropen"); + if (args->numargs != stmt->paramno) + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("param definition mismatches with inputs"))); - /* evaluate parameter values */ - evaluate_sp_cursor_param_values(estate, paramno, stmt->params, &values, &nulls); + /* evaluate parameter values */ + evaluate_sp_cursor_param_values(estate, paramno, stmt->params, &values, &nulls); - enable_sp_cursor_find_param_hook(); - PG_TRY(); - { - ret = execute_sp_cursoropen(&cursor_handle, - querystr, - (scrollopt_null ? NULL : &scrollopt), - (ccopt_null ? NULL : &ccopt), - (rowcount_null ? NULL : &rowcount), - paramno, args->numargs, args->argtypes, - values, nulls); - } - PG_CATCH(); - { + enable_sp_cursor_find_param_hook(); + PG_TRY(); + { + ret = execute_sp_cursoropen(&cursor_handle, + querystr, + (scrollopt_null ? NULL : &scrollopt), + (ccopt_null ? NULL : &ccopt), + (rowcount_null ? NULL : &rowcount), + paramno, args->numargs, args->argtypes, + values, nulls); + } + PG_CATCH(); + { + disable_sp_cursor_find_param_hook(); + PG_RE_THROW(); + } + PG_END_TRY(); disable_sp_cursor_find_param_hook(); - PG_RE_THROW(); - } - PG_END_TRY(); - disable_sp_cursor_find_param_hook(); - if (ret > 0) - ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("sp_cursoropen failed: %d", ret))); + if (ret > 0) + ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("sp_cursoropen failed: %d", ret))); - assign_simple_var(estate, (PLtsql_var *) estate->datums[stmt->cursor_handleno], Int32GetDatum(cursor_handle), false, false); - break; - } + assign_simple_var(estate, (PLtsql_var *) estate->datums[stmt->cursor_handleno], Int32GetDatum(cursor_handle), false, false); + break; + } case PLTSQL_EXEC_SP_CURSORPREPARE: - { - int options; - int scrollopt; - int ccopt; - bool scrollopt_null = true; - bool ccopt_null = true; - InlineCodeBlockArgs *args = NULL; - - /* evaulate query string */ - val = exec_eval_expr(estate, stmt->query, &isnull, &restype, &restypmod); - if (isnull) - ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("query string argument of sp_cursorprepare is null"))); - querystr = convert_value_to_string(estate, val, restype); - - if (stmt->opt1 != NULL) - scrollopt = exec_eval_int(estate, stmt->opt1, &scrollopt_null); - if (stmt->opt2 != NULL) - ccopt = exec_eval_int(estate, stmt->opt2, &ccopt_null); - Assert(stmt->opt3); - options = exec_eval_int(estate, stmt->opt3, &isnull); - if (isnull) - ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("options argument of sp_cursorprepare is null"))); + { + int options; + int scrollopt; + int ccopt; + bool scrollopt_null = true; + bool ccopt_null = true; + InlineCodeBlockArgs *args = NULL; + + /* evaulate query string */ + val = exec_eval_expr(estate, stmt->query, &isnull, &restype, &restypmod); + if (isnull) + ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("query string argument of sp_cursorprepare is null"))); + querystr = convert_value_to_string(estate, val, restype); + + if (stmt->opt1 != NULL) + scrollopt = exec_eval_int(estate, stmt->opt1, &scrollopt_null); + if (stmt->opt2 != NULL) + ccopt = exec_eval_int(estate, stmt->opt2, &ccopt_null); + Assert(stmt->opt3); + options = exec_eval_int(estate, stmt->opt3, &isnull); + if (isnull) + ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("options argument of sp_cursorprepare is null"))); - /* evalaute parameter definition */ - args = evaluate_sp_cursor_param_def(estate, stmt->param_def, "sp_cursorprepare"); + /* evalaute parameter definition */ + args = evaluate_sp_cursor_param_def(estate, stmt->param_def, "sp_cursorprepare"); - enable_sp_cursor_find_param_hook(); - PG_TRY(); - { - ret = execute_sp_cursorprepare(&prepared_handle, - querystr, - options, - (scrollopt_null ? NULL : &scrollopt), - (ccopt_null ? NULL : &ccopt), - args->numargs, args->argtypes); - } - PG_CATCH(); - { + enable_sp_cursor_find_param_hook(); + PG_TRY(); + { + ret = execute_sp_cursorprepare(&prepared_handle, + querystr, + options, + (scrollopt_null ? NULL : &scrollopt), + (ccopt_null ? NULL : &ccopt), + args->numargs, args->argtypes); + } + PG_CATCH(); + { + disable_sp_cursor_find_param_hook(); + PG_RE_THROW(); + } + PG_END_TRY(); disable_sp_cursor_find_param_hook(); - PG_RE_THROW(); - } - PG_END_TRY(); - disable_sp_cursor_find_param_hook(); - if (ret > 0) - ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("sp_cursorprepare failed: %d", ret))); + if (ret > 0) + ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("sp_cursorprepare failed: %d", ret))); - assign_simple_var(estate, (PLtsql_var *) estate->datums[stmt->prepared_handleno], Int32GetDatum(prepared_handle), false, false); - break; - } + assign_simple_var(estate, (PLtsql_var *) estate->datums[stmt->prepared_handleno], Int32GetDatum(prepared_handle), false, false); + break; + } case PLTSQL_EXEC_SP_CURSOREXECUTE: - { - int scrollopt; - int ccopt; - int rowcount; - bool scrollopt_null = true; - bool ccopt_null = true; - bool rowcount_null = true; - int paramno = stmt->paramno; - Datum *values = NULL; - char *nulls = NULL; - - prepared_handle = exec_eval_int(estate, stmt->handle, &isnull); - if (isnull) - ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("prepared_handle argument of sp_cursorexecute is null"))); - - if (stmt->opt1 != NULL) - scrollopt = exec_eval_int(estate, stmt->opt1, &scrollopt_null); - if (stmt->opt2 != NULL) - ccopt = exec_eval_int(estate, stmt->opt2, &ccopt_null); - if (stmt->opt3 != NULL) - rowcount = exec_eval_int(estate, stmt->opt3, &rowcount_null); - - /* evaluate parameter values */ - evaluate_sp_cursor_param_values(estate, paramno, stmt->params, &values, &nulls); - - ret = execute_sp_cursorexecute(prepared_handle, - &cursor_handle, - (scrollopt_null ? NULL : &scrollopt), - (ccopt_null ? NULL : &ccopt), - (rowcount_null ? NULL : &rowcount), - paramno, values, nulls); - if (ret > 0) - ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("sp_cursorexecute failed: %d", ret))); - - assign_simple_var(estate, (PLtsql_var *) estate->datums[stmt->cursor_handleno], Int32GetDatum(cursor_handle), false, false); - break; - } - case PLTSQL_EXEC_SP_CURSORPREPEXEC: - { - int scrollopt; - int ccopt; - int rowcount; - bool scrollopt_null = true; - bool ccopt_null = true; - bool rowcount_null = true; - InlineCodeBlockArgs *args = NULL; - int paramno = stmt->paramno; - Datum *values = NULL; - char *nulls = NULL; - - /* evaulate query string */ - val = exec_eval_expr(estate, stmt->query, &isnull, &restype, &restypmod); - if (isnull) - ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("stmt argument of sp_cursorprepexec is null"))); - querystr = convert_value_to_string(estate, val, restype); - - if (stmt->opt1 != NULL) - scrollopt = exec_eval_int(estate, stmt->opt1, &scrollopt_null); - if (stmt->opt2 != NULL) - ccopt = exec_eval_int(estate, stmt->opt2, &ccopt_null); - if (stmt->opt3 != NULL) - rowcount = exec_eval_int(estate, stmt->opt3, &rowcount_null); - - /* evalaute parameter definition */ - args = evaluate_sp_cursor_param_def(estate, stmt->param_def, "sp_cursorprepexec"); - if (args->numargs != stmt->paramno) - ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("param definition mismatches with inputs"))); - - /* evaluate parameter values */ - evaluate_sp_cursor_param_values(estate, paramno, stmt->params, &values, &nulls); - - enable_sp_cursor_find_param_hook(); - PG_TRY(); { - ret = execute_sp_cursorprepexec(&prepared_handle, - &cursor_handle, - querystr, - 1, /* options: unlike documenation, sp_cursorprepexec doens't take an option value*/ - (scrollopt_null ? NULL : &scrollopt), - (ccopt_null ? NULL : &ccopt), - (rowcount_null ? NULL : &rowcount), - paramno, args->numargs, - args->argtypes, values, nulls); + int scrollopt; + int ccopt; + int rowcount; + bool scrollopt_null = true; + bool ccopt_null = true; + bool rowcount_null = true; + int paramno = stmt->paramno; + Datum *values = NULL; + char *nulls = NULL; + + prepared_handle = exec_eval_int(estate, stmt->handle, &isnull); + if (isnull) + ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("prepared_handle argument of sp_cursorexecute is null"))); + + if (stmt->opt1 != NULL) + scrollopt = exec_eval_int(estate, stmt->opt1, &scrollopt_null); + if (stmt->opt2 != NULL) + ccopt = exec_eval_int(estate, stmt->opt2, &ccopt_null); + if (stmt->opt3 != NULL) + rowcount = exec_eval_int(estate, stmt->opt3, &rowcount_null); + + /* evaluate parameter values */ + evaluate_sp_cursor_param_values(estate, paramno, stmt->params, &values, &nulls); + + ret = execute_sp_cursorexecute(prepared_handle, + &cursor_handle, + (scrollopt_null ? NULL : &scrollopt), + (ccopt_null ? NULL : &ccopt), + (rowcount_null ? NULL : &rowcount), + paramno, values, nulls); + if (ret > 0) + ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("sp_cursorexecute failed: %d", ret))); + + assign_simple_var(estate, (PLtsql_var *) estate->datums[stmt->cursor_handleno], Int32GetDatum(cursor_handle), false, false); + break; } - PG_CATCH(); + case PLTSQL_EXEC_SP_CURSORPREPEXEC: { + int scrollopt; + int ccopt; + int rowcount; + bool scrollopt_null = true; + bool ccopt_null = true; + bool rowcount_null = true; + InlineCodeBlockArgs *args = NULL; + int paramno = stmt->paramno; + Datum *values = NULL; + char *nulls = NULL; + + /* evaulate query string */ + val = exec_eval_expr(estate, stmt->query, &isnull, &restype, &restypmod); + if (isnull) + ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("stmt argument of sp_cursorprepexec is null"))); + querystr = convert_value_to_string(estate, val, restype); + + if (stmt->opt1 != NULL) + scrollopt = exec_eval_int(estate, stmt->opt1, &scrollopt_null); + if (stmt->opt2 != NULL) + ccopt = exec_eval_int(estate, stmt->opt2, &ccopt_null); + if (stmt->opt3 != NULL) + rowcount = exec_eval_int(estate, stmt->opt3, &rowcount_null); + + /* evalaute parameter definition */ + args = evaluate_sp_cursor_param_def(estate, stmt->param_def, "sp_cursorprepexec"); + if (args->numargs != stmt->paramno) + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("param definition mismatches with inputs"))); + + /* evaluate parameter values */ + evaluate_sp_cursor_param_values(estate, paramno, stmt->params, &values, &nulls); + + enable_sp_cursor_find_param_hook(); + PG_TRY(); + { + ret = execute_sp_cursorprepexec(&prepared_handle, + &cursor_handle, + querystr, + 1, /* options: unlike + * documenation, + * sp_cursorprepexec + * doens't take an + * option value */ + (scrollopt_null ? NULL : &scrollopt), + (ccopt_null ? NULL : &ccopt), + (rowcount_null ? NULL : &rowcount), + paramno, args->numargs, + args->argtypes, values, nulls); + } + PG_CATCH(); + { + disable_sp_cursor_find_param_hook(); + PG_RE_THROW(); + } + PG_END_TRY(); disable_sp_cursor_find_param_hook(); - PG_RE_THROW(); - } - PG_END_TRY(); - disable_sp_cursor_find_param_hook(); - if (ret > 0) - ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("sp_cursorprepexec failed: %d", ret))); + if (ret > 0) + ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("sp_cursorprepexec failed: %d", ret))); - assign_simple_var(estate, (PLtsql_var *) estate->datums[stmt->prepared_handleno], Int32GetDatum(prepared_handle), false, false); - assign_simple_var(estate, (PLtsql_var *) estate->datums[stmt->cursor_handleno], Int32GetDatum(cursor_handle), false, false); - break; - } + assign_simple_var(estate, (PLtsql_var *) estate->datums[stmt->prepared_handleno], Int32GetDatum(prepared_handle), false, false); + assign_simple_var(estate, (PLtsql_var *) estate->datums[stmt->cursor_handleno], Int32GetDatum(cursor_handle), false, false); + break; + } case PLTSQL_EXEC_SP_CURSORUNPREPARE: - { - prepared_handle = exec_eval_int(estate, stmt->handle, &isnull); - if (isnull) - ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("prepared_handle argument of sp_cursorunprepare is null"))); + { + prepared_handle = exec_eval_int(estate, stmt->handle, &isnull); + if (isnull) + ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("prepared_handle argument of sp_cursorunprepare is null"))); - ret = execute_sp_cursorunprepare(prepared_handle); + ret = execute_sp_cursorunprepare(prepared_handle); - if (ret > 0) - ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("sp_cursorunprepare failed: %d", ret))); - break; - } + if (ret > 0) + ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("sp_cursorunprepare failed: %d", ret))); + break; + } case PLTSQL_EXEC_SP_CURSORFETCH: - { - int fetchtype; - int rownum; - int nrows; - bool fetchtype_null = true; - bool rownum_null = true; - bool nrows_null = true; - - cursor_handle = exec_eval_int(estate, stmt->handle, &isnull); - if (isnull) - ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("cursor argument of sp_cursorfetch is null"))); - - if (stmt->opt1 != NULL) - fetchtype = exec_eval_int(estate, stmt->opt1, &fetchtype_null); - if (stmt->opt2 != NULL) - rownum = exec_eval_int(estate, stmt->opt2, &rownum_null); - if (stmt->opt3 != NULL) - nrows = exec_eval_int(estate, stmt->opt3, &nrows_null); - - ret = execute_sp_cursorfetch(cursor_handle, - (fetchtype_null ? NULL : &fetchtype), - (rownum_null ? NULL : &rownum), - (nrows_null ? NULL : &nrows)); - if (ret > 0) - ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("sp_cursorfetch failed: %d", ret))); - break; - } - case PLTSQL_EXEC_SP_CURSOROPTION: - { - int code; - int ivalue; - char *cvalue; - - cursor_handle = exec_eval_int(estate, stmt->handle, &isnull); - if (isnull) - ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("cursor argument of sp_cursoroption is null"))); - - code = exec_eval_int(estate, stmt->opt1, &isnull); - if (isnull) - ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("code argument of sp_cursoroption is null"))); - - if (code == 0x2) /* special case */ { - val = exec_eval_expr(estate, stmt->opt2, &isnull, &restype, &restypmod); + int fetchtype; + int rownum; + int nrows; + bool fetchtype_null = true; + bool rownum_null = true; + bool nrows_null = true; + + cursor_handle = exec_eval_int(estate, stmt->handle, &isnull); if (isnull) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("value argument of sp_cursoroption is null"))); - cvalue = convert_value_to_string(estate, val, restype); - - ret = execute_sp_cursoroption2(cursor_handle, code, cvalue); + errmsg("cursor argument of sp_cursorfetch is null"))); + + if (stmt->opt1 != NULL) + fetchtype = exec_eval_int(estate, stmt->opt1, &fetchtype_null); + if (stmt->opt2 != NULL) + rownum = exec_eval_int(estate, stmt->opt2, &rownum_null); + if (stmt->opt3 != NULL) + nrows = exec_eval_int(estate, stmt->opt3, &nrows_null); + + ret = execute_sp_cursorfetch(cursor_handle, + (fetchtype_null ? NULL : &fetchtype), + (rownum_null ? NULL : &rownum), + (nrows_null ? NULL : &nrows)); + if (ret > 0) + ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("sp_cursorfetch failed: %d", ret))); + break; } - else + case PLTSQL_EXEC_SP_CURSOROPTION: { - ivalue = exec_eval_int(estate, stmt->opt2, &isnull); + int code; + int ivalue; + char *cvalue; + + cursor_handle = exec_eval_int(estate, stmt->handle, &isnull); if (isnull) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("value argument of sp_cursoroption is null"))); - - ret = execute_sp_cursoroption(cursor_handle, code, ivalue); - } + errmsg("cursor argument of sp_cursoroption is null"))); - if (ret > 0) - ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("sp_cursoroption failed: %d", ret))); - break; - } - case PLTSQL_EXEC_SP_CURSORCLOSE: - { - cursor_handle = exec_eval_int(estate, stmt->handle, &isnull); - if (isnull) - ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("cursor argument of sp_cursorfetch is null"))); + code = exec_eval_int(estate, stmt->opt1, &isnull); + if (isnull) + ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("code argument of sp_cursoroption is null"))); - ret = execute_sp_cursorclose(cursor_handle); + if (code == 0x2) /* special case */ + { + val = exec_eval_expr(estate, stmt->opt2, &isnull, &restype, &restypmod); + if (isnull) + ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("value argument of sp_cursoroption is null"))); + cvalue = convert_value_to_string(estate, val, restype); - if (ret > 0) - ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("sp_cursorclose failed: %d", ret))); - break; - } - case PLTSQL_EXEC_SP_EXECUTESQL: - { - Datum batch; - char *batchstr; - bool isnull; - Oid restype; - int32 restypmod; - int save_nestlevel; - int scope_level; - InlineCodeBlockArgs *args = NULL; - - batch = exec_eval_expr(estate, stmt->query, &isnull, &restype, &restypmod); - if (isnull) - ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("batch string argument of sp_executesql is null"))); + ret = execute_sp_cursoroption2(cursor_handle, code, cvalue); + } + else + { + ivalue = exec_eval_int(estate, stmt->opt2, &isnull); + if (isnull) + ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("value argument of sp_cursoroption is null"))); - batchstr = convert_value_to_string(estate, batch, restype); + ret = execute_sp_cursoroption(cursor_handle, code, ivalue); + } - args = create_args(0); - if (stmt->param_def) + if (ret > 0) + ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("sp_cursoroption failed: %d", ret))); + break; + } + case PLTSQL_EXEC_SP_CURSORCLOSE: { - Datum paramdef; - Oid restype; - int32 restypmod; - char *paramdefstr; - bool isnull; - - /* - * Evaluate the parameter definition - */ - paramdef = exec_eval_expr(estate, stmt->param_def, &isnull, &restype, &restypmod); + cursor_handle = exec_eval_int(estate, stmt->handle, &isnull); + if (isnull) + ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("cursor argument of sp_cursorfetch is null"))); + ret = execute_sp_cursorclose(cursor_handle); + + if (ret > 0) + ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("sp_cursorclose failed: %d", ret))); + break; + } + case PLTSQL_EXEC_SP_EXECUTESQL: + { + Datum batch; + char *batchstr; + bool isnull; + Oid restype; + int32 restypmod; + int save_nestlevel; + int scope_level; + InlineCodeBlockArgs *args = NULL; + + batch = exec_eval_expr(estate, stmt->query, &isnull, &restype, &restypmod); if (isnull) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("NULL param definition"))); + errmsg("batch string argument of sp_executesql is null"))); - paramdefstr = convert_value_to_string(estate, paramdef, restype); + batchstr = convert_value_to_string(estate, batch, restype); - if (strcmp(paramdefstr, "") != 0) /* check edge cases for sp_executesql */ + args = create_args(0); + if (stmt->param_def) { - read_param_def(args, paramdefstr); + Datum paramdef; + Oid restype; + int32 restypmod; + char *paramdefstr; + bool isnull; - if (args->numargs != stmt->paramno) - ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("param definition mismatches with inputs"))); + /* + * Evaluate the parameter definition + */ + paramdef = exec_eval_expr(estate, stmt->param_def, &isnull, &restype, &restypmod); + + if (isnull) + ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("NULL param definition"))); + + paramdefstr = convert_value_to_string(estate, paramdef, restype); + + if (strcmp(paramdefstr, "") != 0) /* check edge cases for + * sp_executesql */ + { + read_param_def(args, paramdefstr); + + if (args->numargs != stmt->paramno) + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("param definition mismatches with inputs"))); + } } - } - save_nestlevel = pltsql_new_guc_nest_level(); - scope_level = pltsql_new_scope_identity_nest_level(); + save_nestlevel = pltsql_new_guc_nest_level(); + scope_level = pltsql_new_scope_identity_nest_level(); - PG_TRY(); - { - if (strcmp(batchstr, "") != 0) /* check edge cases for sp_executesql */ + PG_TRY(); { - ret = execute_batch(estate, batchstr, args, stmt->params); - } + if (strcmp(batchstr, "") != 0) /* check edge cases for + * sp_executesql */ + { + ret = execute_batch(estate, batchstr, args, stmt->params); + } - if (stmt->return_code_dno != -1) + if (stmt->return_code_dno != -1) + { + exec_assign_value(estate, estate->datums[stmt->return_code_dno], Int32GetDatum(ret), false, INT4OID, 0); + } + } + PG_FINALLY(); { - exec_assign_value(estate, estate->datums[stmt->return_code_dno], Int32GetDatum(ret), false, INT4OID, 0); + pltsql_revert_guc(save_nestlevel); + pltsql_revert_last_scope_identity(scope_level); } + PG_END_TRY(); + break; } - PG_FINALLY(); - { - pltsql_revert_guc(save_nestlevel); - pltsql_revert_last_scope_identity(scope_level); - } - PG_END_TRY(); - break; - } case PLTSQL_EXEC_SP_EXECUTE: - { - int handle = exec_eval_int(estate, stmt->handle, &isnull); - InlineCodeBlockArgs *args; - PLtsql_function *func; + { + int handle = exec_eval_int(estate, stmt->handle, &isnull); + InlineCodeBlockArgs *args; + PLtsql_function *func; - if (isnull) - ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("handle argument of sp_execute is null"))); + if (isnull) + ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("handle argument of sp_execute is null"))); - func = find_cached_batch(handle); - if (!func) - ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("Prepared statement not found: %d", handle))); + func = find_cached_batch(handle); + if (!func) + ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("Prepared statement not found: %d", handle))); - Assert(func->inline_args); - args = clone_inline_args(func->inline_args); - args->options = (BATCH_OPTION_EXEC_CACHED_PLAN | - BATCH_OPTION_NO_FREE); - args->handle = handle; + Assert(func->inline_args); + args = clone_inline_args(func->inline_args); + args->options = (BATCH_OPTION_EXEC_CACHED_PLAN | + BATCH_OPTION_NO_FREE); + args->handle = handle; - ret = execute_batch(estate, NULL, args, stmt->params); - break; - } + ret = execute_batch(estate, NULL, args, stmt->params); + break; + } case PLTSQL_EXEC_SP_PREPEXEC: - { - Datum batch; - char *batchstr; - bool isnull; - Oid restype; - int32 restypmod; - InlineCodeBlockArgs *args = NULL; - Datum paramdef; - char *paramdefstr; - - batch = exec_eval_expr(estate, stmt->query, &isnull, &restype, &restypmod); - if (isnull) - ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("batch string argument of sp_prepexec is null"))); + { + Datum batch; + char *batchstr; + bool isnull; + Oid restype; + int32 restypmod; + InlineCodeBlockArgs *args = NULL; + Datum paramdef; + char *paramdefstr; + + batch = exec_eval_expr(estate, stmt->query, &isnull, &restype, &restypmod); + if (isnull) + ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("batch string argument of sp_prepexec is null"))); - batchstr = convert_value_to_string(estate, batch, restype); + batchstr = convert_value_to_string(estate, batch, restype); - args = create_args(0); + args = create_args(0); - /* - * Evaluate the parameter definition - */ - paramdef = exec_eval_expr(estate, stmt->param_def, &isnull, &restype, &restypmod); + /* + * Evaluate the parameter definition + */ + paramdef = exec_eval_expr(estate, stmt->param_def, &isnull, &restype, &restypmod); - if (!isnull) - { - paramdefstr = convert_value_to_string(estate, paramdef, restype); + if (!isnull) + { + paramdefstr = convert_value_to_string(estate, paramdef, restype); - read_param_def(args, paramdefstr); + read_param_def(args, paramdefstr); - if (args->numargs != stmt->paramno) - ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("param definition mismatches with inputs"))); - } + if (args->numargs != stmt->paramno) + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("param definition mismatches with inputs"))); + } - args->options = (BATCH_OPTION_CACHE_PLAN | - BATCH_OPTION_NO_FREE); + args->options = (BATCH_OPTION_CACHE_PLAN | + BATCH_OPTION_NO_FREE); - ret = execute_batch(estate, batchstr, args, stmt->params); + ret = execute_batch(estate, batchstr, args, stmt->params); - assign_simple_var(estate, (PLtsql_var *) estate->datums[stmt->prepared_handleno], - Int32GetDatum(args->handle), false, false); - break; + assign_simple_var(estate, (PLtsql_var *) estate->datums[stmt->prepared_handleno], + Int32GetDatum(args->handle), false, false); + break; - } + } default: break; } @@ -2064,8 +2104,8 @@ static int exec_stmt_deallocate(PLtsql_execstate *estate, PLtsql_stmt_deallocate *stmt) { PLtsql_var *curvar; - Portal portal; - char *curname; + Portal portal; + char *curname; MemoryContext oldcontext; Assert(estate->datums[stmt->curvar]->dtype == PLTSQL_DTYPE_VAR); @@ -2089,7 +2129,7 @@ exec_stmt_deallocate(PLtsql_execstate *estate, PLtsql_stmt_deallocate *stmt) portal = SPI_cursor_find(curname); if (portal) { - if(IS_TDS_CLIENT() && portal->portalPinned) + if (IS_TDS_CLIENT() && portal->portalPinned) UnpinPortal(portal); @@ -2125,7 +2165,7 @@ static int exec_stmt_decl_cursor(PLtsql_execstate *estate, PLtsql_stmt_decl_cursor *stmt) { PLtsql_var *curvar; - char *curname; + char *curname; MemoryContext oldcontext; Assert(estate->datums[stmt->curvar]->dtype == PLTSQL_DTYPE_VAR); @@ -2133,7 +2173,7 @@ exec_stmt_decl_cursor(PLtsql_execstate *estate, PLtsql_stmt_decl_cursor *stmt) curvar = (PLtsql_var *) estate->datums[stmt->curvar]; Assert(is_cursor_datatype(curvar->datatype->typoid)); if (!curvar->isconst) - return PLTSQL_RC_OK; /* cursor variable. nothing to do here */ + return PLTSQL_RC_OK; /* cursor variable. nothing to do here */ if (!pltsql_declare_cursor(estate, curvar, stmt->cursor_explicit_expr, stmt->cursor_options)) { @@ -2149,12 +2189,12 @@ exec_stmt_decl_cursor(PLtsql_execstate *estate, PLtsql_stmt_decl_cursor *stmt) } static char * -transform_tsql_temp_tables(char * dynstmt) +transform_tsql_temp_tables(char *dynstmt) { StringInfoData ds; - char *cp; - char *word; - char *prev_word; + char *cp; + char *word; + char *prev_word; initStringInfo(&ds); prev_word = NULL; @@ -2164,12 +2204,12 @@ transform_tsql_temp_tables(char * dynstmt) if (cp[0] == '#' && is_char_identstart(cp[1])) { /* - * Quote this local temporary table identifier. next_word stops as - * soon as it encounters a non-ident character such as '#', we point - * it to the next character as the start of word while specifying - * the '#' prefix explicitly in the format string. + * Quote this local temporary table identifier. next_word stops + * as soon as it encounters a non-ident character such as '#', we + * point it to the next character as the start of word while + * specifying the '#' prefix explicitly in the format string. */ - word = next_word(cp+1); + word = next_word(cp + 1); appendStringInfo(&ds, "\"#%s\"", word); cp += strlen(word); } @@ -2180,7 +2220,7 @@ transform_tsql_temp_tables(char * dynstmt) /* CREATE TABLE # -> CREATE TEMPORARY TABLE # */ if ((prev_word && (pg_strcasecmp(prev_word, "CREATE") == 0)) && - (pg_strcasecmp(word, "TABLE") == 0) && + (pg_strcasecmp(word, "TABLE") == 0) && is_next_temptbl(cp)) { appendStringInfo(&ds, "TEMPORARY %s", word); @@ -2201,6 +2241,7 @@ static char * next_word(char *dyntext) { StringInfoData ds; + initStringInfo(&ds); while (*dyntext && is_char_identpart(*dyntext)) @@ -2212,7 +2253,7 @@ next_word(char *dyntext) static bool is_next_temptbl(char *dyntext) { - while (*++dyntext && scanner_isspace(*dyntext)); /* skip whitespace */ + while (*++dyntext && scanner_isspace(*dyntext)); /* skip whitespace */ return (dyntext[0] == '#' && is_char_identstart(dyntext[1])); } @@ -2220,17 +2261,17 @@ is_next_temptbl(char *dyntext) static bool is_char_identstart(char c) { - return ((c == '_') || + return ((c == '_') || (c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z') || - (c >= '\200' && c <= '\377')); + (c >= 'a' && c <= 'z') || + (c >= '\200' && c <= '\377')); } static bool is_char_identpart(char c) { return ((is_char_identstart(c)) || - (c >= '0' && c <= '9')); + (c >= '0' && c <= '9')); } /* @@ -2239,12 +2280,12 @@ is_char_identpart(char c) void read_param_def(InlineCodeBlockArgs *args, const char *paramdefstr) { - List *parsetree; - List *params; - ListCell *lc; - int i = 0; - const char *str1 = "CREATE PROC p_tmp_spexecutesql ("; - const char *str2 = ") AS BEGIN END; DROP PROC p_tmp_spexecutesql;"; + List *parsetree; + List *params; + ListCell *lc; + int i = 0; + const char *str1 = "CREATE PROC p_tmp_spexecutesql ("; + const char *str2 = ") AS BEGIN END; DROP PROC p_tmp_spexecutesql;"; StringInfoData proc_stmt; Assert(args); @@ -2256,8 +2297,8 @@ read_param_def(InlineCodeBlockArgs *args, const char *paramdefstr) } /* - * Create a fake CREATE PROCEDURE statement to get the param - * definition parse tree. + * Create a fake CREATE PROCEDURE statement to get the param definition + * parse tree. */ initStringInfo(&proc_stmt); appendStringInfoString(&proc_stmt, str1); @@ -2265,19 +2306,22 @@ read_param_def(InlineCodeBlockArgs *args, const char *paramdefstr) appendStringInfoString(&proc_stmt, str2); parsetree = raw_parser(proc_stmt.data, RAW_PARSE_DEFAULT); - - /* + + /* * Seperate each param definition, and calculate the total number of * definitions. */ params = ((CreateFunctionStmt *) (((RawStmt *) linitial(parsetree))->stmt))->parameters; - /* Throw error if the provided number of arguments are more than the max allowed limit. */ + /* + * Throw error if the provided number of arguments are more than the max + * allowed limit. + */ if (list_length(params) > PREPARE_STMT_MAX_ARGS) - ereport(ERROR, + ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("Too many arguments were provided: %d. The maximum allowed limit is %d", - list_length(params), PREPARE_STMT_MAX_ARGS))); + errmsg("Too many arguments were provided: %d. The maximum allowed limit is %d", + list_length(params), PREPARE_STMT_MAX_ARGS))); args->numargs = list_length(params); args->argtypes = (Oid *) palloc(sizeof(Oid) * args->numargs); @@ -2287,16 +2331,17 @@ read_param_def(InlineCodeBlockArgs *args, const char *paramdefstr) foreach(lc, params) { - FunctionParameter *p; + FunctionParameter *p; p = (FunctionParameter *) lfirst(lc); args->argnames[i] = p->name; args->argmodes[i] = p->mode; /* - * Handle User defined types with schema qualifiers. Convert logical Schema Name to - * Physical Schema Name. Note: The list length can not be more than 2 since db name - * can not be a qualifier for a UDT and error will be thrown in the parser itself. + * Handle User defined types with schema qualifiers. Convert logical + * Schema Name to Physical Schema Name. Note: The list length can not + * be more than 2 since db name can not be a qualifier for a UDT and + * error will be thrown in the parser itself. */ rewrite_plain_name(p->argType->names); @@ -2305,7 +2350,8 @@ read_param_def(InlineCodeBlockArgs *args, const char *paramdefstr) } } -InlineCodeBlockArgs *create_args(int numargs) +InlineCodeBlockArgs * +create_args(int numargs) { InlineCodeBlockArgs *args; @@ -2319,7 +2365,8 @@ InlineCodeBlockArgs *create_args(int numargs) return args; } -void cache_inline_args(PLtsql_function *func, InlineCodeBlockArgs *args) +void +cache_inline_args(PLtsql_function *func, InlineCodeBlockArgs *args) { MemoryContext oldcontext; @@ -2329,17 +2376,18 @@ void cache_inline_args(PLtsql_function *func, InlineCodeBlockArgs *args) MemoryContextSwitchTo(oldcontext); } -InlineCodeBlockArgs *clone_inline_args(InlineCodeBlockArgs *args) +InlineCodeBlockArgs * +clone_inline_args(InlineCodeBlockArgs *args) { InlineCodeBlockArgs *clone; - clone = create_args(args->numargs); - memcpy(clone->argtypes, args->argtypes, sizeof(Oid) * args->numargs); - memcpy(clone->argtypmods, args->argtypmods, sizeof(int32) * args->numargs); - memcpy(clone->argnames, args->argnames, sizeof(char *) * args->numargs); - memcpy(clone->argmodes, args->argmodes, sizeof(char) * args->numargs); + clone = create_args(args->numargs); + memcpy(clone->argtypes, args->argtypes, sizeof(Oid) * args->numargs); + memcpy(clone->argtypmods, args->argtypmods, sizeof(int32) * args->numargs); + memcpy(clone->argnames, args->argnames, sizeof(char *) * args->numargs); + memcpy(clone->argmodes, args->argmodes, sizeof(char) * args->numargs); - return clone; + return clone; } /* @@ -2347,16 +2395,16 @@ InlineCodeBlockArgs *clone_inline_args(InlineCodeBlockArgs *args) */ static void read_param_val(PLtsql_execstate *estate, List *params, InlineCodeBlockArgs *args, - FunctionCallInfo fcinfo, PLtsql_row *row) + FunctionCallInfo fcinfo, PLtsql_row *row) { - ListCell *lc; - bool *assigned; - int i = 0; - int j = 0; - int nfields = 0; - int n_extra_args = fcinfo->nargs; - - /* + ListCell *lc; + bool *assigned; + int i = 0; + int j = 0; + int nfields = 0; + int n_extra_args = fcinfo->nargs; + + /* * An array to record which parameters have already been given a value */ assigned = (bool *) palloc0(args->numargs * sizeof(bool)); @@ -2367,7 +2415,7 @@ read_param_val(PLtsql_execstate *estate, List *params, InlineCodeBlockArgs *args { tsql_exec_param *p; Datum paramval; - Oid restype; + Oid restype; int32 restypmod; bool isnull; @@ -2381,22 +2429,22 @@ read_param_val(PLtsql_execstate *estate, List *params, InlineCodeBlockArgs *args /* Check if the param's declared mode matches called mode */ if (!check_spexecutesql_param(&(args->argmodes[i]), p)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("param %d defined as mode %c but received mode %c", - i + 1, args->argmodes[i], p->mode))); + errmsg("param %d defined as mode %c but received mode %c", + i + 1, args->argmodes[i], p->mode))); /* Evaluate expression for IN/INOUT param */ paramval = exec_eval_expr(estate, p->expr, &isnull, &restype, &restypmod); /* Insert param info into fcinfo */ - if (isnull) + if (isnull) { fcinfo->args[i + n_extra_args].value = (Datum) 0; fcinfo->args[i + n_extra_args].isnull = true; } else { - /* Do type cast if needed */ - paramval = exec_cast_value(estate, paramval, &isnull, restype, restypmod, + /* Do type cast if needed */ + paramval = exec_cast_value(estate, paramval, &isnull, restype, restypmod, args->argtypes[i], args->argtypmods[i]); fcinfo->args[i + n_extra_args].value = paramval; @@ -2410,6 +2458,7 @@ read_param_val(PLtsql_execstate *estate, List *params, InlineCodeBlockArgs *args /* The first i + 1 params have already been assigned */ assigned[i++] = true; } + /* * Assign the named parameters according to the param name */ @@ -2423,8 +2472,8 @@ read_param_val(PLtsql_execstate *estate, List *params, InlineCodeBlockArgs *args /* Check if the param's declared mode matches called mode */ if (!check_spexecutesql_param(&(args->argmodes[j]), p)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("param %s defined as mode %c but received mode %c", - p->name, args->argmodes[j], p->mode))); + errmsg("param %s defined as mode %c but received mode %c", + p->name, args->argmodes[j], p->mode))); /* Evaluate expression for IN/INOUT param */ paramval = exec_eval_expr(estate, p->expr, &isnull, &restype, &restypmod); @@ -2439,7 +2488,7 @@ read_param_val(PLtsql_execstate *estate, List *params, InlineCodeBlockArgs *args { /* Do type cast if needed */ paramval = exec_cast_value(estate, paramval, &isnull, restype, restypmod, - args->argtypes[j], args->argtypmods[j]); + args->argtypes[j], args->argtypmods[j]); fcinfo->args[j + n_extra_args].value = paramval; fcinfo->args[j + n_extra_args].isnull = false; @@ -2454,19 +2503,19 @@ read_param_val(PLtsql_execstate *estate, List *params, InlineCodeBlockArgs *args break; } if (j == args->numargs - 1) - ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("param \"%s\" not defined", p->name))); + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("param \"%s\" not defined", p->name))); } } } - /* + /* * Check if all defined params are assigned */ for (j = 0; j < args->numargs; j++) if (!assigned[j]) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("missing argument value for param %d", j))); + errmsg("missing argument value for param %d", j))); row->nfields = nfields; @@ -2494,15 +2543,15 @@ check_spexecutesql_param(char *defmode, tsql_exec_param *p) } else ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("unexpected parameter mode %c", *defmode))); + errmsg("unexpected parameter mode %c", *defmode))); return true; } static int exec_eval_int(PLtsql_execstate *estate, - PLtsql_expr *expr, - bool *isNull) + PLtsql_expr *expr, + bool *isNull) { Datum exprdatum; Oid exprtypeid; @@ -2515,9 +2564,10 @@ exec_eval_int(PLtsql_execstate *estate, return DatumGetInt32(exprdatum); } -static Node *get_underlying_node_from_implicit_casting(Node *n, NodeTag underlying_nodetype) +static Node * +get_underlying_node_from_implicit_casting(Node *n, NodeTag underlying_nodetype) { - FuncExpr* funcexpr = NULL; + FuncExpr *funcexpr = NULL; if (nodeTag(n) == underlying_nodetype) return n; @@ -2526,21 +2576,26 @@ static Node *get_underlying_node_from_implicit_casting(Node *n, NodeTag underlyi funcexpr = (FuncExpr *) n; else if (IsA(n, CoerceToDomain)) { - /* coerce-to-domain can be added before actual casting. It is already handled and we don't need this to handle output param. ignoring it.*/ + /* + * coerce-to-domain can be added before actual casting. It is already + * handled and we don't need this to handle output param. ignoring it. + */ CoerceToDomain *c = (CoerceToDomain *) n; + if (c->coercionformat == COERCE_IMPLICIT_CAST) return get_underlying_node_from_implicit_casting((Node *) c->arg, underlying_nodetype); else - return NULL; /* not an implicit-casting. stop */ + return NULL; /* not an implicit-casting. stop */ } else if (IsA(n, CoerceViaIO)) { /* no casting function. cocerce-via-io used instead */ CoerceViaIO *c = (CoerceViaIO *) n; + if (c->coerceformat == COERCE_IMPLICIT_CAST) return get_underlying_node_from_implicit_casting((Node *) c->arg, underlying_nodetype); else - return NULL; /* not an implicit-casting. stop */ + return NULL; /* not an implicit-casting. stop */ } if (!funcexpr) @@ -2559,9 +2614,9 @@ static Node *get_underlying_node_from_implicit_casting(Node *n, NodeTag underlyi return linitial(funcexpr->args); /* - * up to two implict castings are nested consecutively. - * inner is about type casting (i.e. int4->numeric) and outer is for typmod handling (numeric->numeric with different typmod) - * check one-level more here + * up to two implict castings are nested consecutively. inner is about + * type casting (i.e. int4->numeric) and outer is for typmod handling + * (numeric->numeric with different typmod) check one-level more here */ if (!IsA(linitial(funcexpr->args), FuncExpr)) return NULL; @@ -2585,14 +2640,15 @@ static Node *get_underlying_node_from_implicit_casting(Node *n, NodeTag underlyi static int exec_stmt_usedb(PLtsql_execstate *estate, PLtsql_stmt_usedb *stmt) { - char message[128]; - char * old_db_name; - int16 old_db_id; - int16 new_db_id; + char message[128]; + char *old_db_name; + int16 old_db_id; + int16 new_db_id; PLExecStateCallStack *top_es_entry; + if (pltsql_explain_only) { - return exec_stmt_usedb_explain(estate, stmt, false /* shouldRestoreDb */); + return exec_stmt_usedb_explain(estate, stmt, false /* shouldRestoreDb */ ); } old_db_name = get_cur_db_name(); old_db_id = get_cur_db_id(); @@ -2609,39 +2665,46 @@ exec_stmt_usedb(PLtsql_execstate *estate, PLtsql_stmt_usedb *stmt) /* Release the session-level shared lock on the old logical db */ UnlockLogicalDatabaseForSession(old_db_id, ShareLock, false); - /* Get a session-level shared lock on the new logical db we are about to use */ + /* + * Get a session-level shared lock on the new logical db we are about to + * use + */ if (!TryLockLogicalDatabaseForSession(new_db_id, ShareLock)) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("Cannot use database \"%s\", failed to obtain lock. " - "\"%s\" is probably undergoing DDL statements in another session.", + "\"%s\" is probably undergoing DDL statements in another session.", stmt->db_name, stmt->db_name))); - /* Same as set_session_properties() but skips checks as they were done before locking */ + /* + * Same as set_session_properties() but skips checks as they were done + * before locking + */ set_cur_user_db_and_path(stmt->db_name); - top_es_entry = exec_state_call_stack->next; - while(top_es_entry != NULL) - { - /*traverse through the estate stack. If the occurrence of - * execute() is found in the stack, suppress the database context - * message and avoid sending env token and message to user. - */ - if(top_es_entry->estate && top_es_entry->estate->err_stmt && - (top_es_entry->estate->err_stmt->cmd_type == PLTSQL_STMT_EXEC_BATCH)) - return PLTSQL_RC_OK; - else - top_es_entry = top_es_entry->next; - } - - snprintf(message, sizeof(message), "Changed database context to '%s'.", stmt->db_name); + top_es_entry = exec_state_call_stack->next; + while (top_es_entry != NULL) + { + /* + * traverse through the estate stack. If the occurrence of execute() + * is found in the stack, suppress the database context message and + * avoid sending env token and message to user. + */ + if (top_es_entry->estate && top_es_entry->estate->err_stmt && + (top_es_entry->estate->err_stmt->cmd_type == PLTSQL_STMT_EXEC_BATCH)) + return PLTSQL_RC_OK; + else + top_es_entry = top_es_entry->next; + } + + snprintf(message, sizeof(message), "Changed database context to '%s'.", stmt->db_name); /* send env change token to user */ if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->send_env_change) ((*pltsql_protocol_plugin_ptr)->send_env_change) (1, stmt->db_name, old_db_name); /* send message to user */ if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->send_info) ((*pltsql_protocol_plugin_ptr)->send_info) (0, 1, 0, message, 0); - + return PLTSQL_RC_OK; } @@ -2655,9 +2718,9 @@ exec_stmt_usedb_explain(PLtsql_execstate *estate, PLtsql_stmt_usedb *stmt, bool const char *old_db_name; const char *initial_database_name; const char *queryText; - int16 old_db_id; - int16 new_db_id; - int16 initial_database_id; + int16 old_db_id; + int16 new_db_id; + int16 initial_database_id; if (!pltsql_explain_only) return PLTSQL_RC_OK; @@ -2672,7 +2735,7 @@ exec_stmt_usedb_explain(PLtsql_execstate *estate, PLtsql_stmt_usedb *stmt, bool queryText = psprintf("USE DATABASE %s", stmt->db_name); append_explain_info(NULL, queryText); } - + /* Gather name and id of the original database the user was connected to */ initial_database_name = get_explain_database(); if (initial_database_name == NULL) @@ -2689,37 +2752,42 @@ exec_stmt_usedb_explain(PLtsql_execstate *estate, PLtsql_stmt_usedb *stmt, bool ereport(ERROR, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", stmt->db_name))); - + } check_session_db_access(stmt->db_name); - /* Release the session-level shared lock on the old logical db if its not the user's original database */ + /* + * Release the session-level shared lock on the old logical db if its not + * the user's original database + */ if (old_db_id != initial_database_id) UnlockLogicalDatabaseForSession(old_db_id, ShareLock, false); - /* Get a session-level shared lock on the new logical db we are about to use. If Restoring the original DB, its - There is no need to reacquire a lock since we never released the lock in the the initial db - */ + /* + * Get a session-level shared lock on the new logical db we are about to + * use. If Restoring the original DB, its There is no need to reacquire a + * lock since we never released the lock in the the initial db + */ if (!TryLockLogicalDatabaseForSession(new_db_id, ShareLock) && !shouldRestoreDb) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("Cannot use database \"%s\", failed to obtain lock. " - "\"%s\" is probably undergoing DDL statements in another session.", + "\"%s\" is probably undergoing DDL statements in another session.", stmt->db_name, stmt->db_name))); set_cur_user_db_and_path(stmt->db_name); - + return PLTSQL_RC_OK; } static int exec_stmt_grantdb(PLtsql_execstate *estate, PLtsql_stmt_grantdb *stmt) { - char *dbname = get_cur_db_name(); - char *login = GetUserNameFromId(GetSessionUserId(), false); - bool login_is_db_owner; - Oid datdba; - ListCell *lc; + char *dbname = get_cur_db_name(); + char *login = GetUserNameFromId(GetSessionUserId(), false); + bool login_is_db_owner; + Oid datdba; + ListCell *lc; /* * If the login is not the db owner or the login is not the member of @@ -2730,21 +2798,22 @@ exec_stmt_grantdb(PLtsql_execstate *estate, PLtsql_stmt_grantdb *stmt) if (!is_member_of_role(GetSessionUserId(), datdba) && !login_is_db_owner) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("Grantor does not have GRANT permission."))); - + errmsg("Grantor does not have GRANT permission."))); + foreach(lc, stmt->grantees) { - char *grantee_name = (char *) lfirst(lc); + char *grantee_name = (char *) lfirst(lc); + if (strcmp(grantee_name, "dbo") == 0 || strcmp(grantee_name, "db_owner") == 0 - || strcmp(grantee_name, login) == 0) + || strcmp(grantee_name, login) == 0) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("Cannot grant or revoke permissions to dbo, db_owner or yourself."))); + errmsg("Cannot grant or revoke permissions to dbo, db_owner or yourself."))); if (!stmt->is_grant && strcmp(grantee_name, "guest") == 0 - && (strcmp(dbname, "master") == 0 || strcmp(dbname, "tempdb") == 0)) + && (strcmp(dbname, "master") == 0 || strcmp(dbname, "tempdb") == 0)) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("Cannot disable access to the guest user in master or tempdb."))); + errmsg("Cannot disable access to the guest user in master or tempdb."))); alter_user_can_connect(stmt->is_grant, grantee_name, dbname); } return PLTSQL_RC_OK; @@ -2813,10 +2882,11 @@ exec_stmt_insert_execute_select(PLtsql_execstate *estate, PLtsql_expr *query) return PLTSQL_RC_OK; } -int exec_stmt_insert_bulk(PLtsql_execstate *estate, PLtsql_stmt_insert_bulk *stmt) +int +exec_stmt_insert_bulk(PLtsql_execstate *estate, PLtsql_stmt_insert_bulk *stmt) { - MemoryContext oldContext; - Oid schema_oid = InvalidOid; + MemoryContext oldContext; + Oid schema_oid = InvalidOid; oldContext = MemoryContextSwitchTo(TopMemoryContext); @@ -2829,30 +2899,35 @@ int exec_stmt_insert_bulk(PLtsql_execstate *estate, PLtsql_stmt_insert_bulk *stm cstmt->attlist = NIL; cstmt->cur_batch_num = 1; - if (!stmt->db_name || stmt->db_name[0] == (char)'\0') + if (!stmt->db_name || stmt->db_name[0] == (char) '\0') stmt->db_name = get_cur_db_name(); if (stmt->schema_name && stmt->db_name) { cstmt->relation->schemaname = get_physical_schema_name(stmt->db_name, - stmt->schema_name); + stmt->schema_name); schema_oid = LookupExplicitNamespace(cstmt->relation->schemaname, true); if (!OidIsValid(schema_oid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_SCHEMA), - errmsg("schema \"%s\" does not exist", + errmsg("schema \"%s\" does not exist", stmt->schema_name))); } /* save the table name for the next Bulk load Request */ cstmt->relation->relname = pstrdup(stmt->table_name); - /* if columns to be inserted into are explicitly mentioned then update the table name with them */ + /* + * if columns to be inserted into are explicitly mentioned then update the + * table name with them + */ if (stmt->column_refs) { - ListCell *lc; - foreach (lc, stmt->column_refs) + ListCell *lc; + + foreach(lc, stmt->column_refs) { - char *temp = pstrdup((char *)lfirst(lc)); + char *temp = pstrdup((char *) lfirst(lc)); + cstmt->attlist = lappend(cstmt->attlist, temp); } } @@ -2880,14 +2955,14 @@ int exec_stmt_insert_bulk(PLtsql_execstate *estate, PLtsql_stmt_insert_bulk *stm uint64 execute_bulk_load_insert(int ncol, int nrow, - Datum *Values, bool *Nulls) + Datum *Values, bool *Nulls) { - uint64 retValue = -1; - Snapshot snap; + uint64 retValue = -1; + Snapshot snap; /* - * Bulk Copy can be triggered with 0 rows. We can also use this - * to cleanup after all rows are inserted. + * Bulk Copy can be triggered with 0 rows. We can also use this to cleanup + * after all rows are inserted. */ if (nrow == 0 && ncol == 0) { @@ -2919,10 +2994,10 @@ execute_bulk_load_insert(int ncol, int nrow, PG_TRY(); { - cstmt->nrow = nrow; - cstmt->ncol = ncol; - cstmt->Values = Values; - cstmt->Nulls = Nulls; + cstmt->nrow = nrow; + cstmt->ncol = ncol; + cstmt->Values = Values; + cstmt->Nulls = Nulls; snap = GetTransactionSnapshot(); PushActiveSnapshot(snap); @@ -2934,15 +3009,19 @@ execute_bulk_load_insert(int ncol, int nrow, } PG_CATCH(); { - /* In an error condition, the caller calls the function again to do the cleanup. */ + /* + * In an error condition, the caller calls the function again to do + * the cleanup. + */ MemoryContext oldcontext; + if (ActiveSnapshotSet() && GetActiveSnapshot() == snap) PopActiveSnapshot(); oldcontext = CurrentMemoryContext; /* - * If a transaction block is already in progress then abort it, - * else rollback entire transaction. + * If a transaction block is already in progress then abort it, else + * rollback entire transaction. */ if (!IsTransactionBlockActive()) { @@ -2968,9 +3047,9 @@ execute_bulk_load_insert(int ncol, int nrow, int execute_plan_and_push_result(PLtsql_execstate *estate, PLtsql_expr *expr, ParamListInfo paramLI) { - Portal portal; - bool success; - uint64 processed = 0; + Portal portal; + bool success; + uint64 processed = 0; DestReceiver *receiver; QueryCompletion qc; @@ -2979,7 +3058,7 @@ execute_plan_and_push_result(PLtsql_execstate *estate, PLtsql_expr *expr, ParamL if (portal == NULL) elog(ERROR, "could not open implicit cursor for query \"%s\": %s", - expr->query, SPI_result_code_string(SPI_result)); + expr->query, SPI_result_code_string(SPI_result)); if (pltsql_explain_only) { @@ -2992,12 +3071,12 @@ execute_plan_and_push_result(PLtsql_execstate *estate, PLtsql_expr *expr, ParamL } success = PortalRun(portal, - FETCH_ALL, - true, - true, - receiver, - receiver, - &qc); + FETCH_ALL, + true, + true, + receiver, + receiver, + &qc); if (success) { @@ -3017,7 +3096,7 @@ execute_plan_and_push_result(PLtsql_execstate *estate, PLtsql_expr *expr, ParamL static void get_param_mode(List *params, int paramno, char **modes) { - ListCell *lc; + ListCell *lc; int i = 0; if (paramno == 0) @@ -3031,19 +3110,21 @@ get_param_mode(List *params, int paramno, char **modes) foreach(lc, params) { - tsql_exec_param *p; + tsql_exec_param *p; p = (tsql_exec_param *) lfirst(lc); (*modes)[i++] = p->mode; } } -int get_insert_bulk_rows_per_batch() +int +get_insert_bulk_rows_per_batch() { return insert_bulk_rows_per_batch; } -int get_insert_bulk_kilobytes_per_batch() +int +get_insert_bulk_kilobytes_per_batch() { return insert_bulk_kilobytes_per_batch; } diff --git a/contrib/babelfishpg_tsql/src/pl_exec.c b/contrib/babelfishpg_tsql/src/pl_exec.c index 4a97dd7179..6df672f6be 100644 --- a/contrib/babelfishpg_tsql/src/pl_exec.c +++ b/contrib/babelfishpg_tsql/src/pl_exec.c @@ -64,11 +64,11 @@ #include "guc.h" #include "catalog.h" -uint64 rowcount_var = 0; -List *columns_updated_list = NIL; +uint64 rowcount_var = 0; +List *columns_updated_list = NIL; static char *original_query_string = NULL; -int fetch_status_var = 0; +int fetch_status_var = 0; typedef struct { @@ -169,7 +169,7 @@ typedef struct /* lookup key for cast info */ typedef struct /* cast_hash table entry */ { - pltsql_CastHashKey key; /* hash key --- MUST BE FIRST */ + pltsql_CastHashKey key; /* hash key --- MUST BE FIRST */ Expr *cast_expr; /* cast expression, or NULL if no-op cast */ CachedExpression *cast_cexpr; /* cached expression backing the above */ /* ExprState is valid only when cast_lxid matches current LXID */ @@ -259,178 +259,178 @@ static HTAB *shared_cast_hash = NULL; * Local function forward declarations ************************************************************/ static void coerce_function_result_tuple(PLtsql_execstate *estate, - TupleDesc tupdesc); + TupleDesc tupdesc); static void pltsql_exec_error_callback(void *arg); -void copy_pltsql_datums(PLtsql_execstate *estate, - PLtsql_function *func); +void copy_pltsql_datums(PLtsql_execstate *estate, + PLtsql_function *func); static void pltsql_fulfill_promise(PLtsql_execstate *estate, - PLtsql_var *var); + PLtsql_var *var); static MemoryContext get_stmt_mcontext(PLtsql_execstate *estate); static void push_stmt_mcontext(PLtsql_execstate *estate); static void pop_stmt_mcontext(PLtsql_execstate *estate); -static int exec_stmt_block(PLtsql_execstate *estate, - PLtsql_stmt_block *block); -static int exec_stmts(PLtsql_execstate *estate, - List *stmts); -static int exec_stmt(PLtsql_execstate *estate, - PLtsql_stmt *stmt); -static int exec_stmt_assign(PLtsql_execstate *estate, - PLtsql_stmt_assign *stmt); -static int exec_stmt_perform(PLtsql_execstate *estate, - PLtsql_stmt_perform *stmt); -static int exec_stmt_call(PLtsql_execstate *estate, - PLtsql_stmt_call *stmt); -static int exec_stmt_getdiag(PLtsql_execstate *estate, - PLtsql_stmt_getdiag *stmt); -static int exec_stmt_if(PLtsql_execstate *estate, - PLtsql_stmt_if *stmt); -static int exec_stmt_case(PLtsql_execstate *estate, - PLtsql_stmt_case *stmt); -static int exec_stmt_loop(PLtsql_execstate *estate, - PLtsql_stmt_loop *stmt); -static int exec_stmt_while(PLtsql_execstate *estate, - PLtsql_stmt_while *stmt); -static int exec_stmt_fori(PLtsql_execstate *estate, - PLtsql_stmt_fori *stmt); -static int exec_stmt_fors(PLtsql_execstate *estate, - PLtsql_stmt_fors *stmt); -static int exec_stmt_forc(PLtsql_execstate *estate, - PLtsql_stmt_forc *stmt); -static int exec_stmt_foreach_a(PLtsql_execstate *estate, - PLtsql_stmt_foreach_a *stmt); -static int exec_stmt_open(PLtsql_execstate *estate, - PLtsql_stmt_open *stmt); -static int exec_stmt_fetch(PLtsql_execstate *estate, - PLtsql_stmt_fetch *stmt); -static int exec_stmt_close(PLtsql_execstate *estate, - PLtsql_stmt_close *stmt); -static int exec_stmt_exit(PLtsql_execstate *estate, - PLtsql_stmt_exit *stmt); -static int exec_stmt_return(PLtsql_execstate *estate, - PLtsql_stmt_return *stmt); -static int exec_stmt_return_next(PLtsql_execstate *estate, - PLtsql_stmt_return_next *stmt); -static int exec_stmt_return_query(PLtsql_execstate *estate, - PLtsql_stmt_return_query *stmt); -static int exec_stmt_raise(PLtsql_execstate *estate, - PLtsql_stmt_raise *stmt); -static int exec_stmt_assert(PLtsql_execstate *estate, - PLtsql_stmt_assert *stmt); -static int exec_stmt_execsql(PLtsql_execstate *estate, - PLtsql_stmt_execsql *stmt); -static void updateColumnUpdatedList(PLtsql_expr* expr, int i); -static int exec_stmt_dynexecute(PLtsql_execstate *estate, - PLtsql_stmt_dynexecute *stmt); -static int exec_stmt_dynfors(PLtsql_execstate *estate, - PLtsql_stmt_dynfors *stmt); -static int exec_stmt_commit(PLtsql_execstate *estate, - PLtsql_stmt_commit *stmt); -static int exec_stmt_rollback(PLtsql_execstate *estate, - PLtsql_stmt_rollback *stmt); -static int exec_stmt_set(PLtsql_execstate *estate, - PLtsql_stmt_set *stmt); - -void pltsql_estate_setup(PLtsql_execstate *estate, - PLtsql_function *func, - ReturnSetInfo *rsi, - EState *simple_eval_estate); -void exec_eval_cleanup(PLtsql_execstate *estate); - -int exec_fmtonly(PLtsql_execstate *estate, - PLtsql_stmt_execsql *stmt); +static int exec_stmt_block(PLtsql_execstate *estate, + PLtsql_stmt_block *block); +static int exec_stmts(PLtsql_execstate *estate, + List *stmts); +static int exec_stmt(PLtsql_execstate *estate, + PLtsql_stmt *stmt); +static int exec_stmt_assign(PLtsql_execstate *estate, + PLtsql_stmt_assign *stmt); +static int exec_stmt_perform(PLtsql_execstate *estate, + PLtsql_stmt_perform *stmt); +static int exec_stmt_call(PLtsql_execstate *estate, + PLtsql_stmt_call *stmt); +static int exec_stmt_getdiag(PLtsql_execstate *estate, + PLtsql_stmt_getdiag *stmt); +static int exec_stmt_if(PLtsql_execstate *estate, + PLtsql_stmt_if *stmt); +static int exec_stmt_case(PLtsql_execstate *estate, + PLtsql_stmt_case *stmt); +static int exec_stmt_loop(PLtsql_execstate *estate, + PLtsql_stmt_loop *stmt); +static int exec_stmt_while(PLtsql_execstate *estate, + PLtsql_stmt_while *stmt); +static int exec_stmt_fori(PLtsql_execstate *estate, + PLtsql_stmt_fori *stmt); +static int exec_stmt_fors(PLtsql_execstate *estate, + PLtsql_stmt_fors *stmt); +static int exec_stmt_forc(PLtsql_execstate *estate, + PLtsql_stmt_forc *stmt); +static int exec_stmt_foreach_a(PLtsql_execstate *estate, + PLtsql_stmt_foreach_a *stmt); +static int exec_stmt_open(PLtsql_execstate *estate, + PLtsql_stmt_open *stmt); +static int exec_stmt_fetch(PLtsql_execstate *estate, + PLtsql_stmt_fetch *stmt); +static int exec_stmt_close(PLtsql_execstate *estate, + PLtsql_stmt_close *stmt); +static int exec_stmt_exit(PLtsql_execstate *estate, + PLtsql_stmt_exit *stmt); +static int exec_stmt_return(PLtsql_execstate *estate, + PLtsql_stmt_return *stmt); +static int exec_stmt_return_next(PLtsql_execstate *estate, + PLtsql_stmt_return_next *stmt); +static int exec_stmt_return_query(PLtsql_execstate *estate, + PLtsql_stmt_return_query *stmt); +static int exec_stmt_raise(PLtsql_execstate *estate, + PLtsql_stmt_raise *stmt); +static int exec_stmt_assert(PLtsql_execstate *estate, + PLtsql_stmt_assert *stmt); +static int exec_stmt_execsql(PLtsql_execstate *estate, + PLtsql_stmt_execsql *stmt); +static void updateColumnUpdatedList(PLtsql_expr *expr, int i); +static int exec_stmt_dynexecute(PLtsql_execstate *estate, + PLtsql_stmt_dynexecute *stmt); +static int exec_stmt_dynfors(PLtsql_execstate *estate, + PLtsql_stmt_dynfors *stmt); +static int exec_stmt_commit(PLtsql_execstate *estate, + PLtsql_stmt_commit *stmt); +static int exec_stmt_rollback(PLtsql_execstate *estate, + PLtsql_stmt_rollback *stmt); +static int exec_stmt_set(PLtsql_execstate *estate, + PLtsql_stmt_set *stmt); + +void pltsql_estate_setup(PLtsql_execstate *estate, + PLtsql_function *func, + ReturnSetInfo *rsi, + EState *simple_eval_estate); +void exec_eval_cleanup(PLtsql_execstate *estate); + +int exec_fmtonly(PLtsql_execstate *estate, + PLtsql_stmt_execsql *stmt); static void exec_check_rw_parameter(PLtsql_expr *expr, int target_dno); static bool contains_target_param(Node *node, int *target_dno); static bool exec_eval_simple_expr(PLtsql_execstate *estate, - PLtsql_expr *expr, - Datum *result, - bool *isNull, - Oid *rettype, - int32 *rettypmod); + PLtsql_expr *expr, + Datum *result, + bool *isNull, + Oid *rettype, + int32 *rettypmod); static void exec_assign_expr(PLtsql_execstate *estate, - PLtsql_datum *target, - PLtsql_expr *expr); + PLtsql_datum *target, + PLtsql_expr *expr); static void exec_assign_c_string(PLtsql_execstate *estate, - PLtsql_datum *target, - const char *str); + PLtsql_datum *target, + const char *str); static void exec_assign_value(PLtsql_execstate *estate, - PLtsql_datum *target, - Datum value, bool isNull, - Oid valtype, int32 valtypmod); + PLtsql_datum *target, + Datum value, bool isNull, + Oid valtype, int32 valtypmod); static void exec_eval_datum(PLtsql_execstate *estate, - PLtsql_datum *datum, - Oid *typeid, - int32 *typetypmod, - Datum *value, - bool *isnull); -static int exec_eval_integer(PLtsql_execstate *estate, - PLtsql_expr *expr, - bool *isNull); + PLtsql_datum *datum, + Oid *typeid, + int32 *typetypmod, + Datum *value, + bool *isnull); +static int exec_eval_integer(PLtsql_execstate *estate, + PLtsql_expr *expr, + bool *isNull); static bool exec_eval_boolean(PLtsql_execstate *estate, - PLtsql_expr *expr, - bool *isNull); + PLtsql_expr *expr, + bool *isNull); static Datum exec_eval_expr(PLtsql_execstate *estate, - PLtsql_expr *expr, - bool *isNull, - Oid *rettype, - int32 *rettypmod); -static int exec_run_select(PLtsql_execstate *estate, - PLtsql_expr *expr, long maxtuples, Portal *portalP); -static int exec_for_query(PLtsql_execstate *estate, PLtsql_stmt_forq *stmt, - Portal portal, bool prefetch_ok); + PLtsql_expr *expr, + bool *isNull, + Oid *rettype, + int32 *rettypmod); +static int exec_run_select(PLtsql_execstate *estate, + PLtsql_expr *expr, long maxtuples, Portal *portalP); +static int exec_for_query(PLtsql_execstate *estate, PLtsql_stmt_forq *stmt, + Portal portal, bool prefetch_ok); static ParamListInfo setup_param_list(PLtsql_execstate *estate, - PLtsql_expr *expr); + PLtsql_expr *expr); static ParamExternData *pltsql_param_fetch(ParamListInfo params, - int paramid, bool speculative, - ParamExternData *workspace); + int paramid, bool speculative, + ParamExternData *workspace); static void pltsql_param_compile(ParamListInfo params, Param *param, - ExprState *state, - Datum *resv, bool *resnull); + ExprState *state, + Datum *resv, bool *resnull); static void pltsql_param_eval_var(ExprState *state, ExprEvalStep *op, - ExprContext *econtext); + ExprContext *econtext); static void pltsql_param_eval_var_ro(ExprState *state, ExprEvalStep *op, - ExprContext *econtext); + ExprContext *econtext); static void pltsql_param_eval_recfield(ExprState *state, ExprEvalStep *op, - ExprContext *econtext); + ExprContext *econtext); static void pltsql_param_eval_generic(ExprState *state, ExprEvalStep *op, - ExprContext *econtext); + ExprContext *econtext); static void pltsql_param_eval_generic_ro(ExprState *state, ExprEvalStep *op, - ExprContext *econtext); + ExprContext *econtext); static void exec_move_row(PLtsql_execstate *estate, - PLtsql_variable *target, - HeapTuple tup, TupleDesc tupdesc); + PLtsql_variable *target, + HeapTuple tup, TupleDesc tupdesc); static void revalidate_rectypeid(PLtsql_rec *rec); static ExpandedRecordHeader *make_expanded_record_for_rec(PLtsql_execstate *estate, - PLtsql_rec *rec, - TupleDesc srctupdesc, - ExpandedRecordHeader *srcerh); + PLtsql_rec *rec, + TupleDesc srctupdesc, + ExpandedRecordHeader *srcerh); static void exec_move_row_from_fields(PLtsql_execstate *estate, - PLtsql_variable *target, - ExpandedRecordHeader *newerh, - Datum *values, bool *nulls, - TupleDesc tupdesc); + PLtsql_variable *target, + ExpandedRecordHeader *newerh, + Datum *values, bool *nulls, + TupleDesc tupdesc); static bool compatible_tupdescs(TupleDesc src_tupdesc, TupleDesc dst_tupdesc); static HeapTuple make_tuple_from_row(PLtsql_execstate *estate, - PLtsql_row *row, - TupleDesc tupdesc); + PLtsql_row *row, + TupleDesc tupdesc); static TupleDesc deconstruct_composite_datum(Datum value, - HeapTupleData *tmptup); + HeapTupleData *tmptup); static void exec_move_row_from_datum(PLtsql_execstate *estate, - PLtsql_variable *target, - Datum value); + PLtsql_variable *target, + Datum value); static void instantiate_empty_record_variable(PLtsql_execstate *estate, - PLtsql_rec *rec); + PLtsql_rec *rec); static char *convert_value_to_string(PLtsql_execstate *estate, - Datum value, Oid valtype); + Datum value, Oid valtype); static Datum exec_cast_value(PLtsql_execstate *estate, - Datum value, bool *isnull, - Oid valtype, int32 valtypmod, - Oid reqtype, int32 reqtypmod); + Datum value, bool *isnull, + Oid valtype, int32 valtypmod, + Oid reqtype, int32 reqtypmod); static pltsql_CastHashEntry *get_cast_hashentry(PLtsql_execstate *estate, - Oid srctype, int32 srctypmod, - Oid dsttype, int32 dsttypmod); + Oid srctype, int32 srctypmod, + Oid dsttype, int32 dsttypmod); static void exec_init_tuple_store(PLtsql_execstate *estate); static void exec_set_found(PLtsql_execstate *estate, bool state); static void exec_set_fetch_status(PLtsql_execstate *estate, int status); @@ -438,23 +438,23 @@ static void exec_set_rowcount(uint64 rowno); static void exec_set_error(PLtsql_execstate *estate, int error, int pg_error, bool error_mapping_failed); static void pltsql_create_econtext(PLtsql_execstate *estate); static void pltsql_commit_not_required_impl_txn(PLtsql_execstate *estate); -void pltsql_destroy_econtext(PLtsql_execstate *estate); -void pltsql_estate_cleanup(void); +void pltsql_destroy_econtext(PLtsql_execstate *estate); +void pltsql_estate_cleanup(void); static void assign_simple_var(PLtsql_execstate *estate, PLtsql_var *var, - Datum newvalue, bool isnull, bool freeable); -/*static*/ void assign_text_var(PLtsql_execstate *estate, PLtsql_var *var, - const char *str); + Datum newvalue, bool isnull, bool freeable); + /* static */ void assign_text_var(PLtsql_execstate *estate, PLtsql_var *var, + const char *str); static void assign_record_var(PLtsql_execstate *estate, PLtsql_rec *rec, - ExpandedRecordHeader *erh); + ExpandedRecordHeader *erh); static PreparedParamsData *exec_eval_using_params(PLtsql_execstate *estate, - List *params); + List *params); static Portal exec_dynquery_with_params(PLtsql_execstate *estate, - PLtsql_expr *dynquery, List *params, - const char *portalname, int cursorOptions); + PLtsql_expr *dynquery, List *params, + const char *portalname, int cursorOptions); static char *format_expr_params(PLtsql_execstate *estate, - const PLtsql_expr *expr); + const PLtsql_expr *expr); static char *format_preparedparamsdata(PLtsql_execstate *estate, - const PreparedParamsData *ppd); + const PreparedParamsData *ppd); static void pltsql_update_identity_insert_sequence(PLtsql_expr *expr); static void pltsql_clean_table_variables(PLtsql_execstate *estate, PLtsql_function *func); @@ -462,11 +462,11 @@ static void pltsql_clean_table_variables(PLtsql_execstate *estate, PLtsql_functi static void pltsql_init_exec_error_data(PLtsqlErrorData *error_data); static void pltsql_copy_exec_error_data(PLtsqlErrorData *src, PLtsqlErrorData *dst, MemoryContext dstCxt); PLtsql_estate_err *pltsql_clone_estate_err(PLtsql_estate_err *err); -static bool reset_search_path(PLtsql_stmt_execsql *stmt, char **old_search_path, bool* reset_session_properties, bool inside_trigger); +static bool reset_search_path(PLtsql_stmt_execsql *stmt, char **old_search_path, bool *reset_session_properties, bool inside_trigger); extern void pltsql_init_anonymous_cursors(PLtsql_execstate *estate); extern void pltsql_cleanup_local_cursors(PLtsql_execstate *estate); -extern void pltsql_get_cursor_definition(char *curname, PLtsql_expr **explicit_expr, int* cursor_options); +extern void pltsql_get_cursor_definition(char *curname, PLtsql_expr **explicit_expr, int *cursor_options); extern void pltsql_update_cursor_fetch_status(char *curname, int fetch_status); extern void pltsql_update_cursor_row_count(char *curname, int64 row_count); extern void pltsql_update_cursor_last_operation(char *curname, int last_operation); @@ -475,14 +475,14 @@ extern char *pltsql_demangle_curname(char *curname); extern bool suppress_string_truncation_error; -extern void exec_prepare_plan(PLtsql_execstate *estate, - PLtsql_expr *expr, int cursorOptions, - bool keepplan); +extern void exec_prepare_plan(PLtsql_execstate *estate, + PLtsql_expr *expr, int cursorOptions, + bool keepplan); extern SPIPlanPtr prepare_stmt_execsql(PLtsql_execstate *estate, PLtsql_function *func, PLtsql_stmt_execsql *stmt, bool keepplan); extern void exec_save_simple_expr(PLtsql_expr *expr, CachedPlan *cplan); extern int -execute_plan_and_push_result(PLtsql_execstate *estate, PLtsql_expr *expr, ParamListInfo paramLI); + execute_plan_and_push_result(PLtsql_execstate *estate, PLtsql_expr *expr, ParamListInfo paramLI); /* ---------- * pltsql_exec_function Called by the call handler for @@ -499,7 +499,7 @@ execute_plan_and_push_result(PLtsql_execstate *estate, PLtsql_expr *expr, ParamL */ Datum pltsql_exec_function(PLtsql_function *func, FunctionCallInfo fcinfo, - EState *simple_eval_estate, bool atomic) + EState *simple_eval_estate, bool atomic) { PLtsql_execstate estate; ErrorContextCallback plerrcontext; @@ -510,7 +510,7 @@ pltsql_exec_function(PLtsql_function *func, FunctionCallInfo fcinfo, * Setup the execution state */ pltsql_estate_setup(&estate, func, (ReturnSetInfo *) fcinfo->resultinfo, - simple_eval_estate); + simple_eval_estate); estate.atomic = atomic; /* @@ -634,7 +634,7 @@ pltsql_exec_function(PLtsql_function *func, FunctionCallInfo fcinfo, * Set the magic variable FOUND to false */ exec_set_found(&estate, false); - exec_set_fetch_status(&estate, -9); /* not fetching */ + exec_set_fetch_status(&estate, -9); /* not fetching */ /* * Let the instrumentation plugin peek at this function @@ -644,219 +644,226 @@ pltsql_exec_function(PLtsql_function *func, FunctionCallInfo fcinfo, PG_TRY(); { - - ExecConfig_t config; - - /* - * Now call the toplevel block of statements - */ - estate.err_text = NULL; - estate.err_stmt = (PLtsql_stmt *) (func->action); - config.trace_mode = 0; - if (pltsql_trace_exec_codes) - config.trace_mode |= TRACE_EXEC_CODES; - if (pltsql_trace_exec_counts) - config.trace_mode |= TRACE_EXEC_COUNTS; - if (pltsql_trace_exec_time) - config.trace_mode |= TRACE_EXEC_TIME; + ExecConfig_t config; - rc = exec_stmt_iterative(&estate, func->exec_codes, &config); - - if (rc != PLTSQL_RC_RETURN) - { - estate.err_stmt = NULL; + /* + * Now call the toplevel block of statements + */ estate.err_text = NULL; - ereport(ERROR, - (errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT), - errmsg("control reached end of function without RETURN"))); - } - - /* - * We got a return value - process it - */ - estate.err_stmt = NULL; - estate.err_text = gettext_noop("while casting return value to function's return type"); + estate.err_stmt = (PLtsql_stmt *) (func->action); - fcinfo->isnull = estate.retisnull; + config.trace_mode = 0; + if (pltsql_trace_exec_codes) + config.trace_mode |= TRACE_EXEC_CODES; + if (pltsql_trace_exec_counts) + config.trace_mode |= TRACE_EXEC_COUNTS; + if (pltsql_trace_exec_time) + config.trace_mode |= TRACE_EXEC_TIME; - if (estate.retisset || estate.insert_exec) - { - ReturnSetInfo *rsi = estate.rsi; + rc = exec_stmt_iterative(&estate, func->exec_codes, &config); - /* Check caller can handle a set result */ - if (!rsi || !IsA(rsi, ReturnSetInfo) || - (rsi->allowedModes & SFRM_Materialize) == 0) + if (rc != PLTSQL_RC_RETURN) + { + estate.err_stmt = NULL; + estate.err_text = NULL; ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("set-valued function called in context that cannot accept a set"))); - rsi->returnMode = SFRM_Materialize; + (errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT), + errmsg("control reached end of function without RETURN"))); + } - /* If we produced any tuples, send back the result */ - if (estate.tuple_store) + /* + * We got a return value - process it + */ + estate.err_stmt = NULL; + estate.err_text = gettext_noop("while casting return value to function's return type"); + + fcinfo->isnull = estate.retisnull; + + if (estate.retisset || estate.insert_exec) { - MemoryContext oldcxt; + ReturnSetInfo *rsi = estate.rsi; + + /* Check caller can handle a set result */ + if (!rsi || !IsA(rsi, ReturnSetInfo) || + (rsi->allowedModes & SFRM_Materialize) == 0) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("set-valued function called in context that cannot accept a set"))); + rsi->returnMode = SFRM_Materialize; + + /* If we produced any tuples, send back the result */ + if (estate.tuple_store) + { + MemoryContext oldcxt; - rsi->setResult = estate.tuple_store; - oldcxt = MemoryContextSwitchTo(estate.tuple_store_cxt); - rsi->setDesc = CreateTupleDescCopy(estate.tuple_store_desc); - MemoryContextSwitchTo(oldcxt); + rsi->setResult = estate.tuple_store; + oldcxt = MemoryContextSwitchTo(estate.tuple_store_cxt); + rsi->setDesc = CreateTupleDescCopy(estate.tuple_store_desc); + MemoryContextSwitchTo(oldcxt); + } + estate.retval = (Datum) 0; + fcinfo->isnull = true; } - estate.retval = (Datum) 0; - fcinfo->isnull = true; - } - else if (!estate.retisnull) - { - /* - * Cast result value to function's declared result type, and copy it - * out to the upper executor memory context. We must treat tuple - * results specially in order to deal with cases like rowtypes - * involving dropped columns. - */ - if (estate.retistuple) + else if (!estate.retisnull) { - /* Don't need coercion if rowtype is known to match */ - if (func->fn_rettype == estate.rettype && - func->fn_rettype != RECORDOID) + /* + * Cast result value to function's declared result type, and copy + * it out to the upper executor memory context. We must treat + * tuple results specially in order to deal with cases like + * rowtypes involving dropped columns. + */ + if (estate.retistuple) { - /* - * Copy the tuple result into upper executor memory context. - * However, if we have a R/W expanded datum, we can just - * transfer its ownership out to the upper context. - */ - estate.retval = SPI_datumTransfer(estate.retval, - false, - -1); + /* Don't need coercion if rowtype is known to match */ + if (func->fn_rettype == estate.rettype && + func->fn_rettype != RECORDOID) + { + /* + * Copy the tuple result into upper executor memory + * context. However, if we have a R/W expanded datum, we + * can just transfer its ownership out to the upper + * context. + */ + estate.retval = SPI_datumTransfer(estate.retval, + false, + -1); + } + else + { + /* + * Need to look up the expected result type. XXX would be + * better to cache the tupdesc instead of repeating + * get_call_result_type(), but the only easy place to save + * it is in the PLtsql_function struct, and that's too + * long-lived: composite types could change during the + * existence of a PLtsql_function. + */ + TypeFuncClass resultType; + Oid resultTypeId; + TupleDesc tupdesc; + + /* + * If the function call oid is invalid, then this is a + * sp_executesql procedure created by inline handler. We + * look at its cached tupdesc instead of fetching result + * type info from pg_proc. + */ + if (fcinfo->flinfo->fn_oid == InvalidOid) + { + resultTypeId = func->fn_rettype; + tupdesc = func->fn_tupdesc; + if (tupdesc) + resultType = TYPEFUNC_COMPOSITE; + else + elog(ERROR, "expecting the inline code to have a tuple descriptor"); + } + else + resultType = get_call_result_type(fcinfo, &resultTypeId, &tupdesc); + + switch (resultType) + { + case TYPEFUNC_COMPOSITE: + /* got the expected result rowtype, now coerce it */ + coerce_function_result_tuple(&estate, tupdesc); + break; + case TYPEFUNC_COMPOSITE_DOMAIN: + /* got the expected result rowtype, now coerce it */ + coerce_function_result_tuple(&estate, tupdesc); + /* and check domain constraints */ + /* XXX allowing caching here would be good, too */ + domain_check(estate.retval, false, resultTypeId, + NULL, NULL); + break; + case TYPEFUNC_RECORD: + + /* + * Failed to determine actual type of RECORD. We + * could raise an error here, but what this means + * in practice is that the caller is expecting any + * old generic rowtype, so we don't really need to + * be restrictive. Pass back the generated result + * as-is. + */ + estate.retval = SPI_datumTransfer(estate.retval, + false, + -1); + break; + default: + /* shouldn't get here if retistuple is true ... */ + elog(ERROR, "return type must be a row type"); + break; + } + } } else { - /* - * Need to look up the expected result type. XXX would be - * better to cache the tupdesc instead of repeating - * get_call_result_type(), but the only easy place to save it - * is in the PLtsql_function struct, and that's too - * long-lived: composite types could change during the - * existence of a PLtsql_function. - */ - TypeFuncClass resultType; - Oid resultTypeId; - TupleDesc tupdesc; + int rettypmod = -1; - /* - * If the function call oid is invalid, then this is a - * sp_executesql procedure created by inline handler. We - * look at its cached tupdesc instead of fetching result - * type info from pg_proc. - */ - if (fcinfo->flinfo->fn_oid == InvalidOid) + /* check if return type typmod is specifieddf in probin */ + if (!func->fn_retset && func->fn_rettype != VOIDOID) { - resultTypeId = func->fn_rettype; - tupdesc = func->fn_tupdesc; - if (tupdesc) - resultType = TYPEFUNC_COMPOSITE; - else - elog(ERROR, "expecting the inline code to have a tuple descriptor"); + rettypmod = probin_read_ret_typmod(func->fn_oid, func->fn_nargs, func->fn_rettype); + suppress_string_truncation_error = true; + estate.retval = exec_cast_value(&estate, + estate.retval, + &fcinfo->isnull, + estate.rettype, + -1, + func->fn_rettype, + rettypmod); + suppress_string_truncation_error = false; } else - resultType = get_call_result_type(fcinfo, &resultTypeId, &tupdesc); - - switch (resultType) { - case TYPEFUNC_COMPOSITE: - /* got the expected result rowtype, now coerce it */ - coerce_function_result_tuple(&estate, tupdesc); - break; - case TYPEFUNC_COMPOSITE_DOMAIN: - /* got the expected result rowtype, now coerce it */ - coerce_function_result_tuple(&estate, tupdesc); - /* and check domain constraints */ - /* XXX allowing caching here would be good, too */ - domain_check(estate.retval, false, resultTypeId, - NULL, NULL); - break; - case TYPEFUNC_RECORD: - - /* - * Failed to determine actual type of RECORD. We - * could raise an error here, but what this means in - * practice is that the caller is expecting any old - * generic rowtype, so we don't really need to be - * restrictive. Pass back the generated result as-is. - */ - estate.retval = SPI_datumTransfer(estate.retval, - false, - -1); - break; - default: - /* shouldn't get here if retistuple is true ... */ - elog(ERROR, "return type must be a row type"); - break; + /* Scalar case: use exec_cast_value */ + estate.retval = exec_cast_value(&estate, + estate.retval, + &fcinfo->isnull, + estate.rettype, + -1, + func->fn_rettype, + rettypmod); } + + + /* + * If the function's return type isn't by value, copy the + * value into upper executor memory context. However, if we + * have a R/W expanded datum, we can just transfer its + * ownership out to the upper executor context. + */ + if (!fcinfo->isnull && !func->fn_retbyval) + estate.retval = SPI_datumTransfer(estate.retval, + false, + func->fn_rettyplen); } } else { - int rettypmod = -1; - /* check if return type typmod is specifieddf in probin */ - if(!func->fn_retset && func->fn_rettype != VOIDOID) - { - rettypmod = probin_read_ret_typmod(func->fn_oid, func->fn_nargs, func->fn_rettype); - suppress_string_truncation_error = true; - estate.retval = exec_cast_value(&estate, - estate.retval, - &fcinfo->isnull, - estate.rettype, - -1, - func->fn_rettype, - rettypmod); - suppress_string_truncation_error = false; - } - else - { - /* Scalar case: use exec_cast_value */ - estate.retval = exec_cast_value(&estate, - estate.retval, - &fcinfo->isnull, - estate.rettype, - -1, - func->fn_rettype, - rettypmod); - } - - /* - * If the function's return type isn't by value, copy the value - * into upper executor memory context. However, if we have a R/W - * expanded datum, we can just transfer its ownership out to the - * upper executor context. + * We're returning a NULL, which normally requires no conversion + * work regardless of datatypes. But, if we are casting it to a + * domain return type, we'd better check that the domain's + * constraints pass. */ - if (!fcinfo->isnull && !func->fn_retbyval) - estate.retval = SPI_datumTransfer(estate.retval, - false, - func->fn_rettyplen); + if (func->fn_retisdomain) + estate.retval = exec_cast_value(&estate, + estate.retval, + &fcinfo->isnull, + estate.rettype, + -1, + func->fn_rettype, + -1); } - } - else - { - /* - * We're returning a NULL, which normally requires no conversion work - * regardless of datatypes. But, if we are casting it to a domain - * return type, we'd better check that the domain's constraints pass. - */ - if (func->fn_retisdomain) - estate.retval = exec_cast_value(&estate, - estate.retval, - &fcinfo->isnull, - estate.rettype, - -1, - func->fn_rettype, - -1); - } } PG_CATCH(); { - /* The purpose of this try-catch to call clean-up routines for estate. Errors will be re-thrwon. */ + /* + * The purpose of this try-catch to call clean-up routines for estate. + * Errors will be re-thrwon. + */ /* Close/Deallocate LOCAL cursors */ pltsql_cleanup_local_cursors(&estate); @@ -1023,7 +1030,7 @@ coerce_function_result_tuple(PLtsql_execstate *estate, TupleDesc tupdesc) */ HeapTuple pltsql_exec_trigger(PLtsql_function *func, - TriggerData *trigdata) + TriggerData *trigdata) { PLtsql_execstate estate; ErrorContextCallback plerrcontext; @@ -1115,7 +1122,7 @@ pltsql_exec_trigger(PLtsql_function *func, * Set the magic variable FOUND to false */ exec_set_found(&estate, false); - exec_set_fetch_status(&estate, -9); /* not fetching */ + exec_set_fetch_status(&estate, -9); /* not fetching */ /* * Let the instrumentation plugin peek at this function @@ -1126,96 +1133,125 @@ pltsql_exec_trigger(PLtsql_function *func, PG_TRY(); { - ExecConfig_t config; + ExecConfig_t config; - /* - * Now call the toplevel block of statements - */ - estate.err_text = NULL; - estate.err_stmt = (PLtsql_stmt *) (func->action); + /* + * Now call the toplevel block of statements + */ + estate.err_text = NULL; + estate.err_stmt = (PLtsql_stmt *) (func->action); - config.trace_mode = 0; - if (pltsql_trace_exec_codes) - config.trace_mode |= TRACE_EXEC_CODES; - if (pltsql_trace_exec_counts) - config.trace_mode |= TRACE_EXEC_COUNTS; - if (pltsql_trace_exec_time) - config.trace_mode |= TRACE_EXEC_TIME; + config.trace_mode = 0; + if (pltsql_trace_exec_codes) + config.trace_mode |= TRACE_EXEC_CODES; + if (pltsql_trace_exec_counts) + config.trace_mode |= TRACE_EXEC_COUNTS; + if (pltsql_trace_exec_time) + config.trace_mode |= TRACE_EXEC_TIME; - rc = exec_stmt_iterative(&estate, func->exec_codes, &config); + rc = exec_stmt_iterative(&estate, func->exec_codes, &config); - /* - * Only complain about missing RETURN in trigger procedure if not - * in SQL_DIALECT_TSQL - */ - if (rc != PLTSQL_RC_RETURN && sql_dialect != SQL_DIALECT_TSQL) - { - estate.err_stmt = NULL; - estate.err_text = NULL; - ereport(ERROR, - (errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT), - errmsg("control reached end of trigger procedure without RETURN"))); - } + /* + * Only complain about missing RETURN in trigger procedure if not in + * SQL_DIALECT_TSQL + */ + if (rc != PLTSQL_RC_RETURN && sql_dialect != SQL_DIALECT_TSQL) + { + estate.err_stmt = NULL; + estate.err_text = NULL; + ereport(ERROR, + (errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT), + errmsg("control reached end of trigger procedure without RETURN"))); + } - /* - * TSQL triggers terminate if there is no transaction - * active at the end - */ - if (pltsql_support_tsql_transactions() && !pltsql_disable_txn_in_triggers && NestedTranCount == 0) - ereport(ERROR, - (errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT), - errmsg("The transaction ended in the trigger. The batch has been aborted."))); + /* + * TSQL triggers terminate if there is no transaction active at the + * end + */ + if (pltsql_support_tsql_transactions() && !pltsql_disable_txn_in_triggers && NestedTranCount == 0) + ereport(ERROR, + (errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT), + errmsg("The transaction ended in the trigger. The batch has been aborted."))); - /* - * If an error was encountered when executing trigger. - */ - if (pltsql_support_tsql_transactions() && !pltsql_disable_txn_in_triggers && exec_state_call_stack->error_data.trigger_error) - ereport(ERROR, - (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), - errmsg("An error was raised during trigger execution. The batch has been aborted and the user transaction, if any, has been rolled back."))); + /* + * If an error was encountered when executing trigger. + */ + if (pltsql_support_tsql_transactions() && !pltsql_disable_txn_in_triggers && exec_state_call_stack->error_data.trigger_error) + ereport(ERROR, + (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), + errmsg("An error was raised during trigger execution. The batch has been aborted and the user transaction, if any, has been rolled back."))); - estate.err_stmt = NULL; - estate.err_text = gettext_noop("during function exit"); + estate.err_stmt = NULL; + estate.err_text = gettext_noop("during function exit"); - if (estate.retisset) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("trigger procedure cannot return a set"))); + if (estate.retisset) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("trigger procedure cannot return a set"))); - /* - * Check that the returned tuple structure has the same attributes, the - * relation that fired the trigger has. A per-statement trigger always - * needs to return NULL, so we ignore any return value the function itself - * produces (XXX: is this a good idea?) - * - * XXX This way it is possible, that the trigger returns a tuple where - * attributes don't have the correct atttypmod's length. It's up to the - * trigger's programmer to ensure that this doesn't happen. Jan - */ - if (estate.retisnull || !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) - rettup = NULL; - else - { - TupleDesc retdesc; - TupleConversionMap *tupmap; + /* + * Check that the returned tuple structure has the same attributes, + * the relation that fired the trigger has. A per-statement trigger + * always needs to return NULL, so we ignore any return value the + * function itself produces (XXX: is this a good idea?) + * + * XXX This way it is possible, that the trigger returns a tuple where + * attributes don't have the correct atttypmod's length. It's up to + * the trigger's programmer to ensure that this doesn't happen. Jan + */ + if (estate.retisnull || !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) + rettup = NULL; + else + { + TupleDesc retdesc; + TupleConversionMap *tupmap; - /* We assume exec_stmt_return verified that result is composite */ - Assert(type_is_rowtype(estate.rettype)); + /* We assume exec_stmt_return verified that result is composite */ + Assert(type_is_rowtype(estate.rettype)); - /* We can special-case expanded records for speed */ - if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(estate.retval))) - { - ExpandedRecordHeader *erh = (ExpandedRecordHeader *) DatumGetEOHP(estate.retval); + /* We can special-case expanded records for speed */ + if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(estate.retval))) + { + ExpandedRecordHeader *erh = (ExpandedRecordHeader *) DatumGetEOHP(estate.retval); - Assert(erh->er_magic == ER_MAGIC); + Assert(erh->er_magic == ER_MAGIC); - /* Extract HeapTuple and TupleDesc */ - rettup = expanded_record_get_tuple(erh); - Assert(rettup); - retdesc = expanded_record_get_tupdesc(erh); + /* Extract HeapTuple and TupleDesc */ + rettup = expanded_record_get_tuple(erh); + Assert(rettup); + retdesc = expanded_record_get_tupdesc(erh); - if (retdesc != RelationGetDescr(trigdata->tg_relation)) + if (retdesc != RelationGetDescr(trigdata->tg_relation)) + { + /* check rowtype compatibility */ + tupmap = convert_tuples_by_position(retdesc, + RelationGetDescr(trigdata->tg_relation), + gettext_noop("returned row structure does not match the structure of the triggering table")); + /* it might need conversion */ + if (tupmap) + rettup = execute_attr_map_tuple(rettup, tupmap); + /* no need to free map, we're about to return anyway */ + } + + /* + * Copy tuple to upper executor memory. But if user just did + * "return new" or "return old" without changing anything, + * there's no need to copy; we can return the original tuple + * (which will save a few cycles in trigger.c as well as + * here). + */ + if (rettup != trigdata->tg_newtuple && + rettup != trigdata->tg_trigtuple) + rettup = SPI_copytuple(rettup); + } + else { + /* Convert composite datum to a HeapTuple and TupleDesc */ + HeapTupleData tmptup; + + retdesc = deconstruct_composite_datum(estate.retval, &tmptup); + rettup = &tmptup; + /* check rowtype compatibility */ tupmap = convert_tuples_by_position(retdesc, RelationGetDescr(trigdata->tg_relation), @@ -1223,47 +1259,22 @@ pltsql_exec_trigger(PLtsql_function *func, /* it might need conversion */ if (tupmap) rettup = execute_attr_map_tuple(rettup, tupmap); + + ReleaseTupleDesc(retdesc); /* no need to free map, we're about to return anyway */ - } - /* - * Copy tuple to upper executor memory. But if user just did - * "return new" or "return old" without changing anything, there's - * no need to copy; we can return the original tuple (which will - * save a few cycles in trigger.c as well as here). - */ - if (rettup != trigdata->tg_newtuple && - rettup != trigdata->tg_trigtuple) + /* Copy tuple to upper executor memory */ rettup = SPI_copytuple(rettup); + } } - else - { - /* Convert composite datum to a HeapTuple and TupleDesc */ - HeapTupleData tmptup; - - retdesc = deconstruct_composite_datum(estate.retval, &tmptup); - rettup = &tmptup; - - /* check rowtype compatibility */ - tupmap = convert_tuples_by_position(retdesc, - RelationGetDescr(trigdata->tg_relation), - gettext_noop("returned row structure does not match the structure of the triggering table")); - /* it might need conversion */ - if (tupmap) - rettup = execute_attr_map_tuple(rettup, tupmap); - - ReleaseTupleDesc(retdesc); - /* no need to free map, we're about to return anyway */ - - /* Copy tuple to upper executor memory */ - rettup = SPI_copytuple(rettup); - } - } } PG_CATCH(); { - /* The purpose of this try-catch to call clean-up routines for estate. Errors will be re-thrwon. */ + /* + * The purpose of this try-catch to call clean-up routines for estate. + * Errors will be re-thrwon. + */ /* Close/Deallocate LOCAL cursors */ pltsql_cleanup_local_cursors(&estate); @@ -1342,40 +1353,43 @@ pltsql_exec_event_trigger(PLtsql_function *func, EventTriggerData *trigdata) PG_TRY(); { - ExecConfig_t config; + ExecConfig_t config; - /* - * Now call the toplevel block of statements - */ - estate.err_text = NULL; - estate.err_stmt = (PLtsql_stmt *) (func->action); - - config.trace_mode = 0; - if (pltsql_trace_exec_codes) - config.trace_mode |= TRACE_EXEC_CODES; - if (pltsql_trace_exec_counts) - config.trace_mode |= TRACE_EXEC_COUNTS; - if (pltsql_trace_exec_time) - config.trace_mode |= TRACE_EXEC_TIME; + /* + * Now call the toplevel block of statements + */ + estate.err_text = NULL; + estate.err_stmt = (PLtsql_stmt *) (func->action); - rc = exec_stmt_iterative(&estate, func->exec_codes, &config); + config.trace_mode = 0; + if (pltsql_trace_exec_codes) + config.trace_mode |= TRACE_EXEC_CODES; + if (pltsql_trace_exec_counts) + config.trace_mode |= TRACE_EXEC_COUNTS; + if (pltsql_trace_exec_time) + config.trace_mode |= TRACE_EXEC_TIME; - if (rc != PLTSQL_RC_RETURN) - { - estate.err_stmt = NULL; - estate.err_text = NULL; - ereport(ERROR, - (errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT), - errmsg("control reached end of trigger procedure without RETURN"))); - } + rc = exec_stmt_iterative(&estate, func->exec_codes, &config); - estate.err_stmt = NULL; - estate.err_text = gettext_noop("during function exit"); + if (rc != PLTSQL_RC_RETURN) + { + estate.err_stmt = NULL; + estate.err_text = NULL; + ereport(ERROR, + (errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT), + errmsg("control reached end of trigger procedure without RETURN"))); + } + + estate.err_stmt = NULL; + estate.err_text = gettext_noop("during function exit"); } PG_CATCH(); { - /* The purpose of this try-catch to call clean-up routines for estate. Errors will be re-thrwon. */ + /* + * The purpose of this try-catch to call clean-up routines for estate. + * Errors will be re-thrwon. + */ /* Close/Deallocate LOCAL cursors */ pltsql_cleanup_local_cursors(&estate); @@ -1471,7 +1485,7 @@ pltsql_exec_error_callback(void *arg) */ void copy_pltsql_datums(PLtsql_execstate *estate, - PLtsql_function *func) + PLtsql_function *func) { int ndatums = estate->ndatums; PLtsql_datum **indatums; @@ -1552,7 +1566,7 @@ copy_pltsql_datums(PLtsql_execstate *estate, */ static void pltsql_fulfill_promise(PLtsql_execstate *estate, - PLtsql_var *var) + PLtsql_var *var) { MemoryContext oldcontext; @@ -1899,7 +1913,7 @@ exec_stmt_block(PLtsql_execstate *estate, PLtsql_stmt_block *block) MemoryContext oldcontext = CurrentMemoryContext; ResourceOwner oldowner = CurrentResourceOwner; ExprContext *old_eval_econtext = estate->eval_econtext; - ErrorData *save_cur_error = estate->cur_error->error; + ErrorData *save_cur_error = estate->cur_error->error; MemoryContext stmt_mcontext; @@ -2164,7 +2178,10 @@ exec_stmt(PLtsql_execstate *estate, PLtsql_stmt *stmt) PLtsql_stmt *save_estmt; int rc = -1; - /* Store the Current Line Number of the current query, incase we stumble upon a runtime error. */ + /* + * Store the Current Line Number of the current query, incase we stumble + * upon a runtime error. + */ CurrentLineNumber = stmt->lineno; save_estmt = estate->err_stmt; estate->err_stmt = stmt; @@ -2233,9 +2250,9 @@ exec_stmt(PLtsql_execstate *estate, PLtsql_stmt *stmt) rc = exec_stmt_exit(estate, (PLtsql_stmt_exit *) stmt); break; - case PLTSQL_STMT_INSERT_BULK: - rc = exec_stmt_insert_bulk(estate, (PLtsql_stmt_insert_bulk *) stmt); - break; + case PLTSQL_STMT_INSERT_BULK: + rc = exec_stmt_insert_bulk(estate, (PLtsql_stmt_insert_bulk *) stmt); + break; case PLTSQL_STMT_RETURN: rc = exec_stmt_return(estate, (PLtsql_stmt_return *) stmt); @@ -2713,10 +2730,10 @@ exec_stmt_if(PLtsql_execstate *estate, PLtsql_stmt_if *stmt) return exec_stmts(estate, elif->stmts); } - if (stmt->else_body) - return exec_stmt(estate, stmt->else_body); - else - return PLTSQL_RC_OK; + if (stmt->else_body) + return exec_stmt(estate, stmt->else_body); + else + return PLTSQL_RC_OK; } @@ -2754,9 +2771,9 @@ exec_stmt_case(PLtsql_execstate *estate, PLtsql_stmt_case *stmt) if (t_var->datatype->typoid != t_typoid || t_var->datatype->atttypmod != t_typmod) t_var->datatype = pltsql_build_datatype(t_typoid, - t_typmod, - estate->func->fn_input_collation, - NULL); + t_typmod, + estate->func->fn_input_collation, + NULL); /* now we can assign to the variable */ exec_assign_value(estate, @@ -3122,10 +3139,10 @@ exec_stmt_forc(PLtsql_execstate *estate, PLtsql_stmt_forc *stmt) else { /* - * T-SQL cursor variable can refer to another constant cursor. - * look up cursor hash to get cursor definition. + * T-SQL cursor variable can refer to another constant cursor. look up + * cursor hash to get cursor definition. */ - int cursor_options; + int cursor_options; pltsql_get_cursor_definition(TextDatumGetCString(curvar->value), &query, &cursor_options); if (query == NULL) @@ -3265,7 +3282,7 @@ exec_stmt_foreach_a(PLtsql_execstate *estate, PLtsql_stmt_foreach_a *stmt) } else loop_var_elem_type = get_element_type(pltsql_exec_get_datum_type(estate, - loop_var)); + loop_var)); /* * Sanity-check the loop variable type. We don't try very hard here, and @@ -3395,6 +3412,7 @@ exec_stmt_return(PLtsql_execstate *estate, PLtsql_stmt_return *stmt) if (estate->func->is_mstvf) { PLtsql_stmt_return_query *return_table; + return_table = (PLtsql_stmt_return_query *) palloc0(sizeof(PLtsql_stmt_return_query)); return_table->cmd_type = PLTSQL_STMT_RETURN_TABLE; return_table->query = NULL; @@ -3419,28 +3437,26 @@ exec_stmt_return(PLtsql_execstate *estate, PLtsql_stmt_return *stmt) estate->rettype = InvalidOid; /* - * In TSQL, every procedure returns an int32 value, and may also - * return a tuple full of OUT values. - * - * Since we have to return both, we store the return code in a - * global variable - the caller (of this procedure) may capture - * that return code in exec_stmt_exec() + * In TSQL, every procedure returns an int32 value, and may also return a + * tuple full of OUT values. + * + * Since we have to return both, we store the return code in a global + * variable - the caller (of this procedure) may capture that return code + * in exec_stmt_exec() * * We store the return code first, then handle any OUT parameters */ if (estate->func->fn_prokind == PROKIND_PROCEDURE) { /* - * TSQL rules: - * Every procedure returns an int32 value - * The default return code is 0 - * A NULL return code is translated to 0 + * TSQL rules: Every procedure returns an int32 value The default + * return code is 0 A NULL return code is translated to 0 */ if (stmt->expr) { - int32 rettypmod; - bool isnull; - Oid rettype; + int32 rettypmod; + bool isnull; + Oid rettype; pltsql_proc_return_code = exec_eval_expr(estate, stmt->expr, &isnull, @@ -3458,7 +3474,7 @@ exec_stmt_return(PLtsql_execstate *estate, PLtsql_stmt_return *stmt) pltsql_proc_return_code = 0; } } - + /* * Special case path when the RETURN expression is a simple variable * reference; in particular, this path is always taken in functions with @@ -3538,11 +3554,11 @@ exec_stmt_return(PLtsql_execstate *estate, PLtsql_stmt_return *stmt) default: elog(ERROR, "unrecognized dtype: %d", retvar->dtype); } - - exec_set_rowcount(1); + + exec_set_rowcount(1); return PLTSQL_RC_RETURN; } - + if (stmt->expr != NULL) { int32 rettypmod; @@ -3562,7 +3578,7 @@ exec_stmt_return(PLtsql_execstate *estate, PLtsql_stmt_return *stmt) (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("cannot return non-composite value from function returning composite type"))); - exec_set_rowcount(1); + exec_set_rowcount(1); return PLTSQL_RC_RETURN; } @@ -3879,7 +3895,7 @@ exec_stmt_return_query(PLtsql_execstate *estate, estate->eval_processed = processed; exec_set_rowcount(processed); - exec_set_found(estate, processed != 0); + exec_set_found(estate, processed != 0); return PLTSQL_RC_OK; } @@ -4188,9 +4204,9 @@ exec_stmt_assert(PLtsql_execstate *estate, PLtsql_stmt_assert *stmt) */ void pltsql_estate_setup(PLtsql_execstate *estate, - PLtsql_function *func, - ReturnSetInfo *rsi, - EState *simple_eval_estate) + PLtsql_function *func, + ReturnSetInfo *rsi, + EState *simple_eval_estate) { HASHCTL ctl; PLExecStateCallStack *es_cs_entry; @@ -4214,7 +4230,7 @@ pltsql_estate_setup(PLtsql_execstate *estate, estate->atomic = true; estate->exitlabel = NULL; - + estate->cur_error = (PLtsql_estate_err *) palloc(sizeof(PLtsql_estate_err)); estate->cur_error->error = NULL; estate->cur_error->procedure = NULL; @@ -4318,7 +4334,7 @@ pltsql_estate_setup(PLtsql_execstate *estate, */ estate->insert_exec = (func->fn_prokind == PROKIND_PROCEDURE || strcmp(func->fn_signature, "inline_code_block") == 0) - && rsi; + && rsi; estate->explain_infos = NIL; @@ -4328,10 +4344,10 @@ pltsql_estate_setup(PLtsql_execstate *estate, pltsql_create_econtext(estate); /* - * Let the plugin see this function before we initialize any local - * PL/tsql variables - note that we also give the plugin a few function - * pointers so it can call back into PL/tsql for doing things like - * variable assignments and stack traces + * Let the plugin see this function before we initialize any local PL/tsql + * variables - note that we also give the plugin a few function pointers + * so it can call back into PL/tsql for doing things like variable + * assignments and stack traces */ if (*pltsql_plugin_ptr) { @@ -4423,21 +4439,19 @@ commit_stmt(PLtsql_execstate *estate, bool txnStarted) MemoryContextSwitchTo(oldcontext); /* - * A null econtext stack indicates commit/rollback/rollback to - * savepoint. - * Make simple_eval_estate to null so that a new value - * is assigned in pltsql_create_econtext. - * Only required when using shared simple eval state, otherwise - * eval state is create in procedure context itself and transactions - * do not affect it + * A null econtext stack indicates commit/rollback/rollback to savepoint. + * Make simple_eval_estate to null so that a new value is assigned in + * pltsql_create_econtext. Only required when using shared simple eval + * state, otherwise eval state is create in procedure context itself and + * transactions do not affect it */ if (estate->use_shared_simple_eval_state && simple_econtext_stack == NULL) estate->simple_eval_estate = NULL; + /* * simple_econtext_stack being NULL only reliably identifies - * commit/rollback but not rollback to savepoint. Check top - * econtext stack entry to find if it was deleted due to rollback - * to savepoint command. + * commit/rollback but not rollback to savepoint. Check top econtext stack + * entry to find if it was deleted due to rollback to savepoint command. * We recreate econtext if a transaction event is detected */ if (simple_econtext_stack == NULL || topEntry != simple_econtext_stack) @@ -4445,13 +4459,14 @@ commit_stmt(PLtsql_execstate *estate, bool txnStarted) } static -bool is_start_implicit_txn_utility_command(Node* parsetree) +bool +is_start_implicit_txn_utility_command(Node *parsetree) { if (parsetree != NULL) { switch (nodeTag(parsetree)) { - /* BEGIN TRAN */ + /* BEGIN TRAN */ case T_TransactionStmt: { TransactionStmt *stmt = (TransactionStmt *) parsetree; @@ -4462,13 +4477,12 @@ bool is_start_implicit_txn_utility_command(Node* parsetree) return false; } - /* - * DROP TABLE - * DROP PROCEDURE - */ + /* + * DROP TABLE DROP PROCEDURE + */ case T_DropStmt: { - ObjectType type = ((DropStmt *) parsetree)->removeType; + ObjectType type = ((DropStmt *) parsetree)->removeType; if (type == OBJECT_TABLE || type == OBJECT_PROCEDURE) return true; @@ -4476,7 +4490,7 @@ bool is_start_implicit_txn_utility_command(Node* parsetree) return false; } - /* ALTER PROCEDURE */ + /* ALTER PROCEDURE */ case T_AlterFunctionStmt: { if (((AlterFunctionStmt *) parsetree)->objtype == OBJECT_PROCEDURE) @@ -4485,7 +4499,7 @@ bool is_start_implicit_txn_utility_command(Node* parsetree) return false; } - /* CREATE PROCEDURE */ + /* CREATE PROCEDURE */ case T_CreateFunctionStmt: { if (((CreateFunctionStmt *) parsetree)->is_procedure) @@ -4494,7 +4508,7 @@ bool is_start_implicit_txn_utility_command(Node* parsetree) return false; } - /* SELECT ... INTO */ + /* SELECT ... INTO */ case T_CreateTableAsStmt: { if (((CreateTableAsStmt *) parsetree)->objtype == OBJECT_TABLE) @@ -4502,12 +4516,10 @@ bool is_start_implicit_txn_utility_command(Node* parsetree) else return false; } - /* - * CREATE TABLE - * TRUNCATE TABLE - * ALTER TABLE - * GRANT / REVOKE - */ + + /* + * CREATE TABLE TRUNCATE TABLE ALTER TABLE GRANT / REVOKE + */ case T_CreateStmt: case T_TruncateStmt: case T_AlterTableStmt: @@ -4528,40 +4540,43 @@ is_impl_txn_required_for_execsql(PLtsql_stmt_execsql *stmt) CachedPlanSource *cachedPlanSource = (CachedPlanSource *) linitial(expr->plan->plancache_list); /* - * If node is NULL, that means query is of one of INSERT/UPDATE/DELETE - * so we start implicit transaction for it. Else query is a utility - * command and we need to identify whether it qualifies to start an - * implicit transaction + * If node is NULL, that means query is of one of INSERT/UPDATE/DELETE so + * we start implicit transaction for it. Else query is a utility command + * and we need to identify whether it qualifies to start an implicit + * transaction */ - Node *node = linitial_node(Query, cachedPlanSource->query_list)->utilityStmt; + Node *node = linitial_node(Query, cachedPlanSource->query_list)->utilityStmt; if (node != NULL && !is_start_implicit_txn_utility_command(node)) return false; - /* For SELECT statements we only need implicit transaction if SELECT is from a table */ + /* + * For SELECT statements we only need implicit transaction if SELECT is + * from a table + */ if (stmt->need_to_push_result || stmt->is_tsql_select_assign_stmt) { - ListCell *lc; + ListCell *lc; if (cachedPlanSource->gplan) { foreach(lc, cachedPlanSource->gplan->stmt_list) { - PlannedStmt *ps = (PlannedStmt*) lfirst(lc); + PlannedStmt *ps = (PlannedStmt *) lfirst(lc); if (ps->commandType == CMD_SELECT) { - ListCell *rt; + ListCell *rt; foreach(rt, ps->rtable) { RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt); /* - * If range table entry is of kind ordinary relation and - * relation kind is a simple table, we require an - * implicit transaction. - */ + * If range table entry is of kind ordinary relation + * and relation kind is a simple table, we require an + * implicit transaction. + */ if (rte->rtekind == RTE_RELATION && rte->relkind == 'r') return true; } @@ -4589,48 +4604,53 @@ exec_stmt_execsql(PLtsql_execstate *estate, int rc; PLtsql_expr *expr = stmt->sqlstmt; Portal portal = NULL; - ListCell *lc; - CachedPlan *cp; - bool is_returning = false; - bool is_select = true; - /* Temporarily disable FMTONLY as it is causing issues with Import-Export. - * Reenable if a use-case is found. - */ - bool fmtonly_enabled = true; - CmdType cmd = CMD_UNKNOWN; + ListCell *lc; + CachedPlan *cp; + bool is_returning = false; + bool is_select = true; + + /* + * Temporarily disable FMTONLY as it is causing issues with Import-Export. + * Reenable if a use-case is found. + */ + bool fmtonly_enabled = true; + CmdType cmd = CMD_UNKNOWN; bool enable_txn_in_triggers = !pltsql_disable_txn_in_triggers; - StringInfoData query; + StringInfoData query; Oid current_user_id = GetUserId(); bool need_path_reset = false; - char *cur_dbname = get_cur_db_name(); - bool reset_session_properties = false; - bool inside_trigger = false; + char *cur_dbname = get_cur_db_name(); + bool reset_session_properties = false; + bool inside_trigger = false; + /* fetch current search_path */ - char *old_search_path = NULL; + char *old_search_path = NULL; + if (stmt->original_query) original_query_string = stmt->original_query; if (stmt->is_cross_db) { - char *login = GetUserNameFromId(GetSessionUserId(), false); - char *user = get_user_for_database(stmt->db_name); + char *login = GetUserNameFromId(GetSessionUserId(), false); + char *user = get_user_for_database(stmt->db_name); if (user) SetCurrentRoleId(GetSessionUserId(), false); else ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_DATABASE), - errmsg("The server principal \"%s\" is not able to access " - "the database \"%s\" under the current security context", - login, stmt->db_name))); + (errcode(ERRCODE_UNDEFINED_DATABASE), + errmsg("The server principal \"%s\" is not able to access " + "the database \"%s\" under the current security context", + login, stmt->db_name))); + /* - * When there is cross db reference to sys or information_schema schemas, - * Change the session property. + * When there is cross db reference to sys or information_schema + * schemas, Change the session property. */ if (stmt->schema_name != NULL && (strcmp(stmt->schema_name, "sys") == 0 || strcmp(stmt->schema_name, "information_schema") == 0)) set_session_properties(stmt->db_name); } - if(stmt->is_dml || stmt->is_ddl || stmt->is_create_view) + if (stmt->is_dml || stmt->is_ddl || stmt->is_create_view) { if (stmt->is_schema_specified) estate->schema_name = stmt->schema_name; @@ -4643,381 +4663,411 @@ exec_stmt_execsql(PLtsql_execstate *estate, PG_TRY(); { - /* Handle naked SELECT stmt differently for INSERT ... EXECUTE */ - if (stmt->need_to_push_result && estate->insert_exec) - { - int ret = exec_stmt_insert_execute_select(estate, expr); - - if (stmt->is_cross_db) - SetCurrentRoleId(current_user_id, false); - - return ret; - } - - if (expr->plan == NULL) - { - /* - * If the set_fmtonly guc is set, we need to rewrite any statements as exec - * statements that invoke sp_describe_first_result_set. For now, only - * transform SELECT statements. - */ - if (pltsql_fmtonly && is_select && !strcasestr(estate->func->fn_signature, "sp_describe_first_result_set") && fmtonly_enabled && strcasestr(stmt->sqlstmt->query, "SELECT *")) - { - initStringInfo(&query); - appendStringInfo(&query, "SELECT TOP 0"); - appendStringInfoString(&query, stmt->sqlstmt->query + 6); - stmt->sqlstmt->query = pstrdup(query.data); - } - prepare_stmt_execsql(estate, estate->func, stmt, true); - } + /* Handle naked SELECT stmt differently for INSERT ... EXECUTE */ + if (stmt->need_to_push_result && estate->insert_exec) + { + int ret = exec_stmt_insert_execute_select(estate, expr); - /* - * Set up ParamListInfo to pass to executor - */ - paramLI = setup_param_list(estate, expr); + if (stmt->is_cross_db) + SetCurrentRoleId(current_user_id, false); + return ret; + } - /* - * Check whether the statement is an INSERT/DELETE with RETURNING - */ - cp = SPI_plan_get_cached_plan(expr->plan); - if (cp) - { - int i; - i = 0; - foreach(lc, cp->stmt_list) + if (expr->plan == NULL) { - PlannedStmt *ps = (PlannedStmt*) lfirst(lc); - if (ps->hasReturning) + /* + * If the set_fmtonly guc is set, we need to rewrite any + * statements as exec statements that invoke + * sp_describe_first_result_set. For now, only transform SELECT + * statements. + */ + if (pltsql_fmtonly && is_select && !strcasestr(estate->func->fn_signature, "sp_describe_first_result_set") && fmtonly_enabled && strcasestr(stmt->sqlstmt->query, "SELECT *")) { - is_returning = true; - if(ps->commandType == CMD_INSERT) - cmd = CMD_INSERT; - else if (ps->commandType == CMD_DELETE) - cmd = CMD_DELETE; - else if (ps->commandType == CMD_UPDATE) - cmd = CMD_UPDATE; - break; - } - if (ps->commandType != CMD_SELECT) - { - is_select = false; - } - if (ps->commandType == CMD_UPDATE || ps->commandType == CMD_INSERT){ - updateColumnUpdatedList(expr, i); + initStringInfo(&query); + appendStringInfo(&query, "SELECT TOP 0"); + appendStringInfoString(&query, stmt->sqlstmt->query + 6); + stmt->sqlstmt->query = pstrdup(query.data); } - ++i; + prepare_stmt_execsql(estate, estate->func, stmt, true); } - ReleaseCachedPlan(cp, CurrentResourceOwner); - } - - - /* - * If we have INTO, then we only need one row back ... but if we have INTO - * STRICT, ask for two rows, so that we can verify the statement returns - * only one. INSERT/UPDATE/DELETE are always treated strictly. Without - * INTO, just run the statement to completion (tcount = 0). - * - * We could just ask for two rows always when using INTO, but there are - * some cases where demanding the extra row costs significant time, eg by - * forcing completion of a sequential scan. So don't do it unless we need - * to enforce strictness. - */ - if (stmt->into) - { - if (stmt->strict || stmt->mod_stmt) - tcount = 2; - else - tcount = 1; - } - else - tcount = 0; + /* + * Set up ParamListInfo to pass to executor + */ + paramLI = setup_param_list(estate, expr); - /* - * If we started an implicit_transaction for this statement, - * check the query plan to see if we actually require it or - * not - */ - if (estate->impl_txn_type == PLTSQL_IMPL_TRAN_START) - { - if (!is_impl_txn_required_for_execsql(stmt)) - pltsql_commit_not_required_impl_txn(estate); - else - estate->impl_txn_type = PLTSQL_IMPL_TRAN_ON; - } - - /* - * if ANTLR is enabled, PLtsql_stmt_push_result will be replaced with PLtsql_stmt_execsql - * with flag need_to_push_result ON. To txn behavior makes consistent regardless of ANTLR, - * adjust enable_txn_in_triggers as same as exec_stmt_push_result. - * same for tsql_select_assign_stmt (select @a=1). with ANTLR=off, it is handled in PLtsql_stmt_query_set. - */ - if (stmt->need_to_push_result || stmt->is_tsql_select_assign_stmt || stmt->mod_stmt_tablevar) - enable_txn_in_triggers = false; - if (enable_txn_in_triggers) - { - /* Open nesting level in engine */ - BeginCompositeTriggers(CurrentMemoryContext); - /* TSQL commands must run inside an explicit transaction */ - if (!pltsql_disable_batch_auto_commit && pltsql_support_tsql_transactions() && - stmt->txn_data == NULL && !IsTransactionBlockActive()) + /* + * Check whether the statement is an INSERT/DELETE with RETURNING + */ + cp = SPI_plan_get_cached_plan(expr->plan); + if (cp) { - MemoryContext oldCxt = CurrentMemoryContext; - elog(DEBUG4, "TQL TXN Start internal transaction for SQL"); - pltsql_start_txn(); - MemoryContextSwitchTo(oldCxt); - estate->tsql_trigger_flags |= TSQL_TRAN_STARTED; - } - estate->tsql_trigger_flags |= TSQL_TRIGGER_STARTED; - } - /* - * Execute the plan. If tsql_identity_insert is valid, do not push the output - * to the receiver so as to not break BABEL-792 implementation. - * - * TODO: in ANTLR, stmt_push_result is already incorporated into stmt_execsql. - * We don't need additional function exec_run_dml_with_output(). We can clean up it later. - */ - if (is_returning && !tsql_identity_insert.valid && !stmt->is_tsql_select_assign_stmt) - rc = exec_run_dml_with_output(estate, (PLtsql_stmt_push_result *) stmt, - portal, expr, cmd, paramLI); - else if (stmt->need_to_push_result) - rc = execute_plan_and_push_result(estate, expr, paramLI); - else if (stmt->txn_data != NULL && !pltsql_support_tsql_transactions()) - { - elog(DEBUG2, "TSQL TXN Execute transaction command with PG semantics"); - rc = execute_txn_command(estate, stmt); + int i; - if (stmt->txn_data != NULL && - (stmt->txn_data->stmt_kind == TRANS_STMT_ROLLBACK || - stmt->txn_data->stmt_kind == TRANS_STMT_ROLLBACK_TO)) - restore_session_properties(); - } - else - rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI, - estate->readonly_func, tcount); + i = 0; + foreach(lc, cp->stmt_list) + { + PlannedStmt *ps = (PlannedStmt *) lfirst(lc); - /* - * Check for error, and set FOUND if appropriate (for historical reasons - * we set FOUND only for certain query types). Also Assert that we - * identified the statement type the same as SPI did. - */ - switch (rc) - { - case PLTSQL_RC_OK: - Assert(stmt->txn_data != NULL); - break; - case SPI_OK_SELECT: - Assert(!stmt->mod_stmt); - exec_set_found(estate, (SPI_processed != 0)); - break; + if (ps->hasReturning) + { + is_returning = true; + if (ps->commandType == CMD_INSERT) + cmd = CMD_INSERT; + else if (ps->commandType == CMD_DELETE) + cmd = CMD_DELETE; + else if (ps->commandType == CMD_UPDATE) + cmd = CMD_UPDATE; + break; + } + if (ps->commandType != CMD_SELECT) + { + is_select = false; + } + if (ps->commandType == CMD_UPDATE || ps->commandType == CMD_INSERT) + { + updateColumnUpdatedList(expr, i); + } + ++i; + } + ReleaseCachedPlan(cp, CurrentResourceOwner); + } - case SPI_OK_INSERT: - case SPI_OK_UPDATE: - case SPI_OK_DELETE: - case SPI_OK_INSERT_RETURNING: - case SPI_OK_UPDATE_RETURNING: - case SPI_OK_DELETE_RETURNING: - Assert(stmt->mod_stmt); - exec_set_found(estate, (SPI_processed != 0)); - break; - case SPI_OK_SELINTO: - Assert(!stmt->mod_stmt); - break; - case SPI_OK_UTILITY: - /* INSERT ... EXECUTE can invoke a procedure while mod_stmt is true */ - break; + /* + * If we have INTO, then we only need one row back ... but if we have + * INTO STRICT, ask for two rows, so that we can verify the statement + * returns only one. INSERT/UPDATE/DELETE are always treated + * strictly. Without INTO, just run the statement to completion + * (tcount = 0). + * + * We could just ask for two rows always when using INTO, but there + * are some cases where demanding the extra row costs significant + * time, eg by forcing completion of a sequential scan. So don't do + * it unless we need to enforce strictness. + */ + if (stmt->into) + { + if (stmt->strict || stmt->mod_stmt) + tcount = 2; + else + tcount = 1; + } + else + tcount = 0; - case SPI_OK_REWRITTEN: - /* - * The command was rewritten into another kind of command. It's - * not clear what FOUND would mean in that case (and SPI doesn't - * return the row count either), so just set it to false. Note - * that we can't assert anything about mod_stmt here. - */ - exec_set_found(estate, false); - break; + /* + * If we started an implicit_transaction for this statement, check the + * query plan to see if we actually require it or not + */ + if (estate->impl_txn_type == PLTSQL_IMPL_TRAN_START) + { + if (!is_impl_txn_required_for_execsql(stmt)) + pltsql_commit_not_required_impl_txn(estate); + else + estate->impl_txn_type = PLTSQL_IMPL_TRAN_ON; + } - /* Some SPI errors deserve specific error messages */ - case SPI_ERROR_COPY: - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot COPY to/from client in PL/tsql"))); - break; + /* + * if ANTLR is enabled, PLtsql_stmt_push_result will be replaced with + * PLtsql_stmt_execsql with flag need_to_push_result ON. To txn + * behavior makes consistent regardless of ANTLR, adjust + * enable_txn_in_triggers as same as exec_stmt_push_result. same for + * tsql_select_assign_stmt (select @a=1). with ANTLR=off, it is + * handled in PLtsql_stmt_query_set. + */ + if (stmt->need_to_push_result || stmt->is_tsql_select_assign_stmt || stmt->mod_stmt_tablevar) + enable_txn_in_triggers = false; - case SPI_ERROR_TRANSACTION: - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("unsupported transaction command in PL/tsql"))); - break; + if (enable_txn_in_triggers) + { + /* Open nesting level in engine */ + BeginCompositeTriggers(CurrentMemoryContext); + /* TSQL commands must run inside an explicit transaction */ + if (!pltsql_disable_batch_auto_commit && pltsql_support_tsql_transactions() && + stmt->txn_data == NULL && !IsTransactionBlockActive()) + { + MemoryContext oldCxt = CurrentMemoryContext; - default: - elog(ERROR, "SPI_execute_plan_with_paramlist failed executing query \"%s\": %s", - expr->query, SPI_result_code_string(rc)); - break; - } + elog(DEBUG4, "TQL TXN Start internal transaction for SQL"); + pltsql_start_txn(); + MemoryContextSwitchTo(oldCxt); + estate->tsql_trigger_flags |= TSQL_TRAN_STARTED; + } + estate->tsql_trigger_flags |= TSQL_TRIGGER_STARTED; + } - if (enable_txn_in_triggers) - { - if (!stmt->need_to_push_result) // before trigger execution , set the rowcount + /* + * Execute the plan. If tsql_identity_insert is valid, do not push the + * output to the receiver so as to not break BABEL-792 implementation. + * + * TODO: in ANTLR, stmt_push_result is already incorporated into + * stmt_execsql. We don't need additional function + * exec_run_dml_with_output(). We can clean up it later. + */ + if (is_returning && !tsql_identity_insert.valid && !stmt->is_tsql_select_assign_stmt) + rc = exec_run_dml_with_output(estate, (PLtsql_stmt_push_result *) stmt, + portal, expr, cmd, paramLI); + else if (stmt->need_to_push_result) + rc = execute_plan_and_push_result(estate, expr, paramLI); + else if (stmt->txn_data != NULL && !pltsql_support_tsql_transactions()) { - exec_set_rowcount(SPI_processed); - } - /* Close nesting level on engine side */ - EndCompositeTriggers(false); - estate->tsql_trigger_flags &= ~TSQL_TRIGGER_STARTED; - } + elog(DEBUG2, "TSQL TXN Execute transaction command with PG semantics"); + rc = execute_txn_command(estate, stmt); - if (columns_updated_list != NIL && 0 == pltsql_trigger_depth){ - ListCell* lc; - foreach(lc, columns_updated_list){ - List* list = (List*)lfirst(lc); - if (list != NIL) - list_free_deep(list); + if (stmt->txn_data != NULL && + (stmt->txn_data->stmt_kind == TRANS_STMT_ROLLBACK || + stmt->txn_data->stmt_kind == TRANS_STMT_ROLLBACK_TO)) + restore_session_properties(); } - list_free(columns_updated_list); - columns_updated_list = NIL; - } + else + rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI, + estate->readonly_func, tcount); - if (!stmt->need_to_push_result) // already set in execute_plan_and_push_result - { - /* All variants should save result info for GET DIAGNOSTICS */ - estate->eval_processed = SPI_processed; - exec_set_rowcount(SPI_processed); - } + /* + * Check for error, and set FOUND if appropriate (for historical + * reasons we set FOUND only for certain query types). Also Assert + * that we identified the statement type the same as SPI did. + */ + switch (rc) + { + case PLTSQL_RC_OK: + Assert(stmt->txn_data != NULL); + break; + case SPI_OK_SELECT: + Assert(!stmt->mod_stmt); + exec_set_found(estate, (SPI_processed != 0)); + break; - /* Process INTO if present */ - if (stmt->into || stmt->is_tsql_select_assign_stmt) - { - SPITupleTable *tuptab = SPI_tuptable; - uint64 n = SPI_processed; - PLtsql_variable *target; + case SPI_OK_INSERT: + case SPI_OK_UPDATE: + case SPI_OK_DELETE: + case SPI_OK_INSERT_RETURNING: + case SPI_OK_UPDATE_RETURNING: + case SPI_OK_DELETE_RETURNING: + Assert(stmt->mod_stmt); + exec_set_found(estate, (SPI_processed != 0)); + break; - /* If the statement did not return a tuple table, complain */ - if (tuptab == NULL) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("INTO used with a command that cannot return data"))); + case SPI_OK_SELINTO: + Assert(!stmt->mod_stmt); + break; + case SPI_OK_UTILITY: - /* Fetch target's datum entry */ - target = (PLtsql_variable *) estate->datums[stmt->target->dno]; + /* + * INSERT ... EXECUTE can invoke a procedure while mod_stmt is + * true + */ + break; - /* - * If SELECT ... INTO specified STRICT, and the query didn't find - * exactly one row, throw an error. If STRICT was not specified, then - * allow the query to find any number of rows. - */ - if (n == 0) - { - if (stmt->strict) - { - char *errdetail; + case SPI_OK_REWRITTEN: - if (estate->func->print_strict_params) - errdetail = format_expr_params(estate, expr); - else - errdetail = NULL; + /* + * The command was rewritten into another kind of command. + * It's not clear what FOUND would mean in that case (and SPI + * doesn't return the row count either), so just set it to + * false. Note that we can't assert anything about mod_stmt + * here. + */ + exec_set_found(estate, false); + break; + /* Some SPI errors deserve specific error messages */ + case SPI_ERROR_COPY: ereport(ERROR, - (errcode(ERRCODE_NO_DATA_FOUND), - errmsg("query returned no rows"), - errdetail ? errdetail_internal("parameters: %s", errdetail) : 0)); - } + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot COPY to/from client in PL/tsql"))); + break; + + case SPI_ERROR_TRANSACTION: + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("unsupported transaction command in PL/tsql"))); + break; + + default: + elog(ERROR, "SPI_execute_plan_with_paramlist failed executing query \"%s\": %s", + expr->query, SPI_result_code_string(rc)); + break; + } - if (!stmt->is_tsql_select_assign_stmt) + if (enable_txn_in_triggers) + { + if (!stmt->need_to_push_result) + /* before trigger execution, set the rowcount */ { - /* set the target to NULL(s) */ - exec_move_row(estate, target, NULL, tuptab->tupdesc); + exec_set_rowcount(SPI_processed); } - else + /* Close nesting level on engine side */ + EndCompositeTriggers(false); + estate->tsql_trigger_flags &= ~TSQL_TRIGGER_STARTED; + } + + if (columns_updated_list != NIL && 0 == pltsql_trigger_depth) + { + ListCell *lc; + + foreach(lc, columns_updated_list) { - /* A SELECT statement that returns zero rows will leave the target(s) unchanged */ + List *list = (List *) lfirst(lc); + + if (list != NIL) + list_free_deep(list); } + list_free(columns_updated_list); + columns_updated_list = NIL; } - else + + if (!stmt->need_to_push_result) + /* already set in execute_plan_and_push_result */ { - /* if is_tsql_select_assign_stmt is set on mod_stmt, INTO is injected by the extension. do not check the # of result strictly */ - if (n > 1 && (stmt->strict || (stmt->mod_stmt && !stmt->is_tsql_select_assign_stmt))) - { - char *errdetail; + /* All variants should save result info for GET DIAGNOSTICS */ + estate->eval_processed = SPI_processed; + exec_set_rowcount(SPI_processed); + } - if (estate->func->print_strict_params) - errdetail = format_expr_params(estate, expr); - else - errdetail = NULL; + /* Process INTO if present */ + if (stmt->into || stmt->is_tsql_select_assign_stmt) + { + SPITupleTable *tuptab = SPI_tuptable; + uint64 n = SPI_processed; + PLtsql_variable *target; + /* If the statement did not return a tuple table, complain */ + if (tuptab == NULL) ereport(ERROR, - (errcode(ERRCODE_TOO_MANY_ROWS), - errmsg("query returned more than one row"), - errdetail ? errdetail_internal("parameters: %s", errdetail) : 0)); - } + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("INTO used with a command that cannot return data"))); + + /* Fetch target's datum entry */ + target = (PLtsql_variable *) estate->datums[stmt->target->dno]; - if (!stmt->is_tsql_select_assign_stmt) + /* + * If SELECT ... INTO specified STRICT, and the query didn't find + * exactly one row, throw an error. If STRICT was not specified, + * then allow the query to find any number of rows. + */ + if (n == 0) { - /* Put the first result row into the target */ - exec_move_row(estate, target, tuptab->vals[0], tuptab->tupdesc); + if (stmt->strict) + { + char *errdetail; + + if (estate->func->print_strict_params) + errdetail = format_expr_params(estate, expr); + else + errdetail = NULL; + + ereport(ERROR, + (errcode(ERRCODE_NO_DATA_FOUND), + errmsg("query returned no rows"), + errdetail ? errdetail_internal("parameters: %s", errdetail) : 0)); + } + + if (!stmt->is_tsql_select_assign_stmt) + { + /* set the target to NULL(s) */ + exec_move_row(estate, target, NULL, tuptab->tupdesc); + } + else + { + /* + * A SELECT statement that returns zero rows will leave + * the target(s) unchanged + */ + } } else { /* - * A SELECT statement that returns more than one row will assign the values in the *last* row. - * - * Like SET command, string truncation error needs to be ignored silently. - * Please note that value is already evaluated so this flag will not affect the evaluating expression itself. + * if is_tsql_select_assign_stmt is set on mod_stmt, INTO is + * injected by the extension. do not check the # of result + * strictly */ - suppress_string_truncation_error = true; - exec_move_row(estate, target, tuptab->vals[n-1], tuptab->tupdesc); - suppress_string_truncation_error = false; + if (n > 1 && (stmt->strict || (stmt->mod_stmt && !stmt->is_tsql_select_assign_stmt))) + { + char *errdetail; + + if (estate->func->print_strict_params) + errdetail = format_expr_params(estate, expr); + else + errdetail = NULL; + + ereport(ERROR, + (errcode(ERRCODE_TOO_MANY_ROWS), + errmsg("query returned more than one row"), + errdetail ? errdetail_internal("parameters: %s", errdetail) : 0)); + } + + if (!stmt->is_tsql_select_assign_stmt) + { + /* Put the first result row into the target */ + exec_move_row(estate, target, tuptab->vals[0], tuptab->tupdesc); + } + else + { + /* + * A SELECT statement that returns more than one row will + * assign the values in the *last* row. + * + * Like SET command, string truncation error needs to be + * ignored silently. Please note that value is already + * evaluated so this flag will not affect the evaluating + * expression itself. + */ + suppress_string_truncation_error = true; + exec_move_row(estate, target, tuptab->vals[n - 1], tuptab->tupdesc); + suppress_string_truncation_error = false; + } } - } - /* Clean up */ - exec_eval_cleanup(estate); - SPI_freetuptable(SPI_tuptable); - } + /* Clean up */ + exec_eval_cleanup(estate); + SPI_freetuptable(SPI_tuptable); + } - /* If query affects IDENTITY_INSERT relation then update sequence */ - pltsql_update_identity_insert_sequence(expr); + /* If query affects IDENTITY_INSERT relation then update sequence */ + pltsql_update_identity_insert_sequence(expr); - /* Expect SPI_tuptable to be NULL else complain */ - if (SPI_tuptable != NULL) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("query has no destination for result data"), - (rc == SPI_OK_SELECT) ? errhint("If you want to discard the results of a SELECT, use PERFORM instead.") : 0)); + /* Expect SPI_tuptable to be NULL else complain */ + if (SPI_tuptable != NULL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("query has no destination for result data"), + (rc == SPI_OK_SELECT) ? errhint("If you want to discard the results of a SELECT, use PERFORM instead.") : 0)); - /* - * Always commit to match auto commit behavior for each - * statement inside batch or procedure, but not user-defined function - * or procedure invoked by INSERT ... EXECUTE. - */ - /* TODO To let procedure call from PSQL work with old semantics */ - if ((!pltsql_disable_batch_auto_commit || (stmt->txn_data != NULL)) && - pltsql_support_tsql_transactions() && - (enable_txn_in_triggers || estate->trigdata == NULL) && - !(estate->func->fn_prokind == PROKIND_FUNCTION && - estate->func->fn_is_trigger == PLTSQL_NOT_TRIGGER && - strcmp(estate->func->fn_signature, "inline_code_block") != 0) && - !estate->insert_exec) - { - commit_stmt(estate, (estate->tsql_trigger_flags & TSQL_TRAN_STARTED)); + /* + * Always commit to match auto commit behavior for each statement + * inside batch or procedure, but not user-defined function or + * procedure invoked by INSERT ... EXECUTE. + */ + /* TODO To let procedure call from PSQL work with old semantics */ + if ((!pltsql_disable_batch_auto_commit || (stmt->txn_data != NULL)) && + pltsql_support_tsql_transactions() && + (enable_txn_in_triggers || estate->trigdata == NULL) && + !(estate->func->fn_prokind == PROKIND_FUNCTION && + estate->func->fn_is_trigger == PLTSQL_NOT_TRIGGER && + strcmp(estate->func->fn_signature, "inline_code_block") != 0) && + !estate->insert_exec) + { + commit_stmt(estate, (estate->tsql_trigger_flags & TSQL_TRAN_STARTED)); - if (stmt->txn_data != NULL && - (stmt->txn_data->stmt_kind == TRANS_STMT_ROLLBACK || - stmt->txn_data->stmt_kind == TRANS_STMT_ROLLBACK_TO)) - restore_session_properties(); - } + if (stmt->txn_data != NULL && + (stmt->txn_data->stmt_kind == TRANS_STMT_ROLLBACK || + stmt->txn_data->stmt_kind == TRANS_STMT_ROLLBACK_TO)) + restore_session_properties(); + } } PG_CATCH(); { if (need_path_reset) - (void) set_config_option("search_path", old_search_path, - PGC_USERSET, PGC_S_SESSION, - GUC_ACTION_SAVE, true, 0, false); - if(reset_session_properties) + (void) set_config_option("search_path", old_search_path, + PGC_USERSET, PGC_S_SESSION, + GUC_ACTION_SAVE, true, 0, false); + if (reset_session_properties) { set_session_properties(cur_dbname); SetCurrentRoleId(current_user_id, false); @@ -5033,10 +5083,10 @@ exec_stmt_execsql(PLtsql_execstate *estate, PG_END_TRY(); if (need_path_reset) - (void) set_config_option("search_path", old_search_path, - PGC_USERSET, PGC_S_SESSION, - GUC_ACTION_SAVE, true, 0, false); - if(reset_session_properties) + (void) set_config_option("search_path", old_search_path, + PGC_USERSET, PGC_S_SESSION, + GUC_ACTION_SAVE, true, 0, false); + if (reset_session_properties) { set_session_properties(cur_dbname); SetCurrentRoleId(current_user_id, false); @@ -5051,51 +5101,61 @@ exec_stmt_execsql(PLtsql_execstate *estate, return PLTSQL_RC_OK; } -static void updateColumnUpdatedList(PLtsql_expr* expr, int i){ - ListCell* lcj; - List* curr_columns_list; +static void +updateColumnUpdatedList(PLtsql_expr *expr, int i) +{ + ListCell *lcj; + List *curr_columns_list; TargetEntry *target_entry; - Relation rel; - TupleDesc tupdesc; + Relation rel; + TupleDesc tupdesc; MemoryContext oldContext; UpdatedColumn *updateColumn; - int length; - Query *query; - List* targetList; - query = (Query *)list_nth( - ((CachedPlanSource *)list_nth(expr->plan->plancache_list, 0))->query_list - ,i); - targetList = + int length; + Query *query; + List *targetList; + + query = (Query *) list_nth( + ((CachedPlanSource *) list_nth(expr->plan->plancache_list, 0))->query_list + ,i); + targetList = query->targetList; if (query->rtable == NULL || targetList == NULL) return; - rel = RelationIdGetRelation(((RangeTblEntry *)list_nth(query->rtable,query->resultRelation-1))->relid); - if (!rel || rel->rd_islocaltemp || !rel->rd_isvalid){ + rel = RelationIdGetRelation(((RangeTblEntry *) list_nth(query->rtable, query->resultRelation - 1))->relid); + if (!rel || rel->rd_islocaltemp || !rel->rd_isvalid) + { RelationClose(rel); return; } - if (rel->trigdesc && rel->trigdesc->numtriggers > 0){ - // we only need call this structure inside triggers - foreach(lcj, targetList){ - target_entry = (TargetEntry*)lfirst(lcj); + if (rel->trigdesc && rel->trigdesc->numtriggers > 0) + { + /* we only need call this structure inside triggers */ + foreach(lcj, targetList) + { + target_entry = (TargetEntry *) lfirst(lcj); tupdesc = RelationGetDescr(rel); oldContext = MemoryContextSwitchTo(TopMemoryContext); length = list_length(columns_updated_list); - updateColumn = (UpdatedColumn *)palloc(sizeof(UpdatedColumn)); + updateColumn = (UpdatedColumn *) palloc(sizeof(UpdatedColumn)); updateColumn->x_attnum = target_entry->resno; updateColumn->trigger_depth = pltsql_trigger_depth; updateColumn->total_columns = tupdesc->natts; updateColumn->column_name = target_entry->resname; - if (length < pltsql_trigger_depth + 1){ + if (length < pltsql_trigger_depth + 1) + { curr_columns_list = NIL; - while (length < pltsql_trigger_depth){ + while (length < pltsql_trigger_depth) + { columns_updated_list = lappend(columns_updated_list, NIL); length++; } curr_columns_list = list_make1(updateColumn); columns_updated_list = lappend(columns_updated_list, curr_columns_list); - }else{ - curr_columns_list = (List *)list_nth(columns_updated_list, pltsql_trigger_depth); + } + else + { + curr_columns_list = (List *) list_nth(columns_updated_list, pltsql_trigger_depth); curr_columns_list = lappend(curr_columns_list, updateColumn); } MemoryContextSwitchTo(oldContext); @@ -5112,18 +5172,18 @@ static void updateColumnUpdatedList(PLtsql_expr* expr, int i){ int exec_fmtonly(PLtsql_execstate *estate, - PLtsql_stmt_execsql *stmt) + PLtsql_stmt_execsql *stmt) { - volatile LocalTransactionId before_lxid; - LocalTransactionId after_lxid; - SimpleEcontextStackEntry *topEntry; + volatile LocalTransactionId before_lxid; + LocalTransactionId after_lxid; + SimpleEcontextStackEntry *topEntry; - PLtsql_stmt_exec *estmt; - StringInfoData ss; - SPIPlanPtr plan; + PLtsql_stmt_exec *estmt; + StringInfoData ss; + SPIPlanPtr plan; - Node *node; - FuncExpr *funcexpr; + Node *node; + FuncExpr *funcexpr; HeapTuple func_tuple; List *funcargs; Oid *argtypes; @@ -5132,62 +5192,64 @@ exec_fmtonly(PLtsql_execstate *estate, char *parammodes; MemoryContext oldcontext; PLtsql_row *row; - int rc; + int rc; SPIExecuteOptions options; - PLtsql_expr *expr = stmt->sqlstmt; + PLtsql_expr *expr = stmt->sqlstmt; int nfields; - int i; - ListCell *lc; - ParamListInfo paramLI; - PLtsql_var *return_code; - Query* query; - - estmt = (PLtsql_stmt_exec *) palloc0(sizeof(*estmt)); - estmt->cmd_type = PLTSQL_STMT_EXEC; - estmt->lineno = stmt->lineno; - estmt->is_call = true; - estmt->return_code_dno = -1; // Value? - - initStringInfo(&ss); - appendStringInfo(&ss, "EXEC sp_describe_first_result_set N'"); - appendStringInfoString(&ss, expr->query); - appendStringInfo(&ss, "', null, 0;"); - estmt->expr = (PLtsql_expr *) palloc0(sizeof(estmt->expr)); - estmt->expr->query = strdup(ss.data); - estmt->expr->plan = NULL; - estmt->expr->paramnos = NULL; - estmt->expr->rwparam = -1; - estmt->expr->ns = pltsql_ns_top(); - - estate->ndatums = 2; - - /* - * Begin exec_stmt_exec section - */ - plan = estmt->expr->plan; - plan = prepare_stmt_exec(estate, estate->func, estmt, estate->atomic); - - query = linitial_node(Query, ((CachedPlanSource *) linitial(plan->plancache_list))->query_list); - - - node = query->utilityStmt; + int i; + ListCell *lc; + ParamListInfo paramLI; + PLtsql_var *return_code; + Query *query; + + estmt = (PLtsql_stmt_exec *) palloc0(sizeof(*estmt)); + estmt->cmd_type = PLTSQL_STMT_EXEC; + estmt->lineno = stmt->lineno; + estmt->is_call = true; + estmt->return_code_dno = -1; + /* Value ? */ + + initStringInfo(&ss); + appendStringInfo(&ss, "EXEC sp_describe_first_result_set N'"); + appendStringInfoString(&ss, expr->query); + appendStringInfo(&ss, "', null, 0;"); + estmt->expr = (PLtsql_expr *) palloc0(sizeof(estmt->expr)); + estmt->expr->query = strdup(ss.data); + estmt->expr->plan = NULL; + estmt->expr->paramnos = NULL; + estmt->expr->rwparam = -1; + estmt->expr->ns = pltsql_ns_top(); + + estate->ndatums = 2; + + /* + * Begin exec_stmt_exec section + */ + plan = estmt->expr->plan; + plan = prepare_stmt_exec(estate, estate->func, estmt, estate->atomic); + + query = linitial_node(Query, ((CachedPlanSource *) linitial(plan->plancache_list))->query_list); + + + node = query->utilityStmt; funcexpr = ((CallStmt *) node)->funcexpr; - func_tuple = SearchSysCache1(PROCOID, - ObjectIdGetDatum(funcexpr->funcid)); + func_tuple = SearchSysCache1(PROCOID, + ObjectIdGetDatum(funcexpr->funcid)); - if (!HeapTupleIsValid(func_tuple)) - elog(ERROR, "cache lookup failed for function %u", - funcexpr->funcid); + if (!HeapTupleIsValid(func_tuple)) + elog(ERROR, "cache lookup failed for function %u", + funcexpr->funcid); - /* + /* * Extract function arguments, and expand any named-arg notation */ funcargs = expand_function_arguments(funcexpr->args, - false, - funcexpr->funcresulttype, - func_tuple); - /* + false, + funcexpr->funcresulttype, + func_tuple); + + /* * Get the argument names and modes, too */ get_func_arg_info(func_tuple, &argtypes, &argnames, &argmodes); @@ -5209,102 +5271,108 @@ exec_fmtonly(PLtsql_execstate *estate, MemoryContextSwitchTo(oldcontext); /* - * Examine procedure's argument list. Each output arg position - * should be an unadorned pltsql variable (Datum), which we can - * insert into the row Datum. + * Examine procedure's argument list. Each output arg position should be + * an unadorned pltsql variable (Datum), which we can insert into the row + * Datum. */ nfields = 0; i = 0; foreach(lc, funcargs) { - Node *n = lfirst(lc); + Node *n = lfirst(lc); - if (argmodes && - (argmodes[i] == PROARGMODE_INOUT || - argmodes[i] == PROARGMODE_OUT)) + if (argmodes && + (argmodes[i] == PROARGMODE_INOUT || + argmodes[i] == PROARGMODE_OUT)) + { + if (parammodes && + parammodes[i] != PROARGMODE_INOUT && + parammodes[i] != PROARGMODE_OUT) { - if (parammodes && - parammodes[i] != PROARGMODE_INOUT && - parammodes[i] != PROARGMODE_OUT) - { - /* - * If an INOUT arg is called without OUTPUT, it should be treated like an - * IN param. Put -1 to param id. We can skip assigning actual value. - */ - row->varnos[nfields++] = -1; - } - else if (IsA(n, Param)) - { - Param *param = (Param *) n; + /* + * If an INOUT arg is called without OUTPUT, it should be + * treated like an IN param. Put -1 to param id. We can skip + * assigning actual value. + */ + row->varnos[nfields++] = -1; + } + else if (IsA(n, Param)) + { + Param *param = (Param *) n; - /* paramid is offset by 1 (see make_datum_param()) */ - row->varnos[nfields++] = param->paramid - 1; - } - else if (get_underlying_node_from_implicit_casting(n, T_Param) != NULL) - { - /* - * Other than PL/pgsql, T-SQL allows implicit casting in INOUT and OUT params. - * - * In PG, if implcit casting is added (i.e. int->bigint), it throws an error - * "corresponding argument is not writable" (see the else-clause) - * - * In T-SQL, if arg node is an implicit casting, we will strip the casting. - * Actual casting will be done at value assignement with validity check. - */ + /* paramid is offset by 1 (see make_datum_param()) */ + row->varnos[nfields++] = param->paramid - 1; + } + else if (get_underlying_node_from_implicit_casting(n, T_Param) != NULL) + { + /* + * Other than PL/pgsql, T-SQL allows implicit casting in INOUT + * and OUT params. + * + * In PG, if implcit casting is added (i.e. int->bigint), it + * throws an error "corresponding argument is not writable" + * (see the else-clause) + * + * In T-SQL, if arg node is an implicit casting, we will strip + * the casting. Actual casting will be done at value + * assignement with validity check. + */ - Param *param = (Param *) get_underlying_node_from_implicit_casting(n, T_Param); + Param *param = (Param *) get_underlying_node_from_implicit_casting(n, T_Param); - /* paramid is offset by 1 (see make_datum_param()) */ - row->varnos[nfields++] = param->paramid - 1; - } - else if (argmodes[i] == PROARGMODE_INOUT && IsA(n, Const)) - { - /* - * T-SQL allows to pass constant value as an output parameter. - * Put -1 to param id. We can skip assigning actual value. - */ - row->varnos[nfields++] = -1; - } - else if (argmodes[i] == PROARGMODE_INOUT && get_underlying_node_from_implicit_casting(n, T_Const) != NULL) - { - /* mixture case of implicit casting + CONST. We can skip assigning actual value. */ - row->varnos[nfields++] = -1; - } + /* paramid is offset by 1 (see make_datum_param()) */ + row->varnos[nfields++] = param->paramid - 1; + } + else if (argmodes[i] == PROARGMODE_INOUT && IsA(n, Const)) + { + /* + * T-SQL allows to pass constant value as an output parameter. + * Put -1 to param id. We can skip assigning actual value. + */ + row->varnos[nfields++] = -1; + } + else if (argmodes[i] == PROARGMODE_INOUT && get_underlying_node_from_implicit_casting(n, T_Const) != NULL) + { + /* + * mixture case of implicit casting + CONST. We can skip + * assigning actual value. + */ + row->varnos[nfields++] = -1; + } + else + { + /* report error using parameter name, if available */ + if (argnames && argnames[i] && argnames[i][0]) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("procedure parameter \"%s\" is an output parameter but corresponding argument is not writable", + argnames[i]))); else - { - /* report error using parameter name, if available */ - if (argnames && argnames[i] && argnames[i][0]) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("procedure parameter \"%s\" is an output parameter but corresponding argument is not writable", - argnames[i]))); - else - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("procedure parameter %d is an output parameter but corresponding argument is not writable", - i + 1))); - } + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("procedure parameter %d is an output parameter but corresponding argument is not writable", + i + 1))); } - i++; - } - row->nfields = nfields; + } + i++; + } + row->nfields = nfields; estmt->target = (PLtsql_variable *) row; - paramLI = setup_param_list(estate, estmt->expr); + paramLI = setup_param_list(estate, estmt->expr); before_lxid = MyProc->lxid; topEntry = simple_econtext_stack; - /* - * If we started an implicit_transaction for this statement, - * check the query plan to see if we actually require it or - * not + /* + * If we started an implicit_transaction for this statement, check the + * query plan to see if we actually require it or not */ if (estate->impl_txn_type == PLTSQL_IMPL_TRAN_START) { - if (!is_impl_txn_required_for_execsql(stmt)) - pltsql_commit_not_required_impl_txn(estate); + if (!is_impl_txn_required_for_execsql(stmt)) + pltsql_commit_not_required_impl_txn(estate); else estate->impl_txn_type = PLTSQL_IMPL_TRAN_ON; } @@ -5316,11 +5384,11 @@ exec_fmtonly(PLtsql_execstate *estate, rc = SPI_execute_plan_extended(expr->plan, &options); - /* + /* * Copy the procedure's return code into the specified variable * - * Note that the procedure stores its return code in the global - * variable named pltsql_proc_return_code. + * Note that the procedure stores its return code in the global variable + * named pltsql_proc_return_code. */ if (estmt->return_code_dno >= 0) { @@ -5329,48 +5397,48 @@ exec_fmtonly(PLtsql_execstate *estate, exec_assign_value(estate, (PLtsql_datum *) return_code, Int32GetDatum(pltsql_proc_return_code), false, INT4OID, 0); } - if (estmt->expr->plan && !estmt->expr->plan->saved) + if (estmt->expr->plan && !estmt->expr->plan->saved) estmt->expr->plan = NULL; - if (rc < 0) - elog(ERROR, "SPI_execute_plan_with_paramlist failed executing query \"%s\": %s", - estmt->expr->query, SPI_result_code_string(rc)); - - after_lxid = MyProc->lxid; - - if (before_lxid != after_lxid || - simple_econtext_stack == NULL || - topEntry != simple_econtext_stack) - { - /* - * If we are in a new transaction after the call, we need to build new - * simple-expression infrastructure. - */ - if (estate->use_shared_simple_eval_state) - estate->simple_eval_estate = NULL; - pltsql_create_econtext(estate); - } - - /* - * Check result rowcount; if there's one row, assign procedure's output - * values back to the appropriate variables. - */ - if (SPI_processed == 1) - { - SPITupleTable *tuptab = SPI_tuptable; - - if (!stmt->target) - elog(ERROR, "DO statement returned a row"); - - exec_move_row(estate, stmt->target, tuptab->vals[0], tuptab->tupdesc); - } - else if (SPI_processed > 1) - elog(ERROR, "procedure call returned more than one row"); - - exec_eval_cleanup(estate); - SPI_freetuptable(SPI_tuptable); - - return PLTSQL_RC_OK; + if (rc < 0) + elog(ERROR, "SPI_execute_plan_with_paramlist failed executing query \"%s\": %s", + estmt->expr->query, SPI_result_code_string(rc)); + + after_lxid = MyProc->lxid; + + if (before_lxid != after_lxid || + simple_econtext_stack == NULL || + topEntry != simple_econtext_stack) + { + /* + * If we are in a new transaction after the call, we need to build new + * simple-expression infrastructure. + */ + if (estate->use_shared_simple_eval_state) + estate->simple_eval_estate = NULL; + pltsql_create_econtext(estate); + } + + /* + * Check result rowcount; if there's one row, assign procedure's output + * values back to the appropriate variables. + */ + if (SPI_processed == 1) + { + SPITupleTable *tuptab = SPI_tuptable; + + if (!stmt->target) + elog(ERROR, "DO statement returned a row"); + + exec_move_row(estate, stmt->target, tuptab->vals[0], tuptab->tupdesc); + } + else if (SPI_processed > 1) + elog(ERROR, "procedure call returned more than one row"); + + exec_eval_cleanup(estate); + SPI_freetuptable(SPI_tuptable); + + return PLTSQL_RC_OK; } @@ -5380,22 +5448,23 @@ pltsql_update_identity_insert_sequence(PLtsql_expr *expr) { if (tsql_identity_insert.valid) { - ListCell *lc; - bool is_called = false; + ListCell *lc; + bool is_called = false; - /* If present, get the current relation Oid that corresponds to + /* + * If present, get the current relation Oid that corresponds to * IDENTITY_INSERT. - */ + */ foreach(lc, SPI_plan_get_plan_sources(expr->plan)) { CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc); - ListCell *lc_rel; + ListCell *lc_rel; if (plansource->commandTag && plansource->commandTag == CMDTAG_INSERT) { foreach(lc_rel, plansource->relationOids) { - Oid cur_rel = lfirst_oid(lc_rel); + Oid cur_rel = lfirst_oid(lc_rel); if (cur_rel == tsql_identity_insert.rel_oid) { @@ -5411,13 +5480,13 @@ pltsql_update_identity_insert_sequence(PLtsql_expr *expr) if (is_called) { - Relation rel; - TupleDesc tupdesc; - AttrNumber attnum; - char *id_attname = NULL; - Oid seqid = InvalidOid; + Relation rel; + TupleDesc tupdesc; + AttrNumber attnum; + char *id_attname = NULL; + Oid seqid = InvalidOid; SPITupleTable *tuptable = SPI_tuptable; - uint64 n_processed = SPI_processed; + uint64 n_processed = SPI_processed; /* Get the identity column name */ rel = RelationIdGetRelation(tsql_identity_insert.rel_oid); @@ -5426,10 +5495,11 @@ pltsql_update_identity_insert_sequence(PLtsql_expr *expr) for (attnum = 0; attnum < tupdesc->natts; attnum++) { Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum); + if (attr->attidentity) { id_attname = NameStr(attr->attname); - seqid = getIdentitySequence(tsql_identity_insert.rel_oid, attnum+1, false); + seqid = getIdentitySequence(tsql_identity_insert.rel_oid, attnum + 1, false); break; } } @@ -5440,12 +5510,12 @@ pltsql_update_identity_insert_sequence(PLtsql_expr *expr) if (!id_attname) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), - errmsg("IDENTITY column not found"))); + errmsg("IDENTITY column not found"))); /* Check that the tuple table is not empty */ if (tuptable != NULL && n_processed > 0) { - TupleDesc tupdesc_ret = tuptable->tupdesc; + TupleDesc tupdesc_ret = tuptable->tupdesc; /* Obtain the user identity column */ for (attnum = 0; attnum < tupdesc_ret->natts; attnum++) @@ -5455,22 +5525,22 @@ pltsql_update_identity_insert_sequence(PLtsql_expr *expr) /* Find by name since other attributes not defined */ if (strcmp(NameStr(attr->attname), id_attname) == 0) { - int tup_idx; - int64 seq_incr = 0; - int64 last_identity; - int64 min_identity = LONG_MAX; - int64 max_identity = LONG_MIN; - ListCell *seq_lc; - List *seq_options; + int tup_idx; + int64 seq_incr = 0; + int64 last_identity; + int64 min_identity = LONG_MAX; + int64 max_identity = LONG_MIN; + ListCell *seq_lc; + List *seq_options; for (tup_idx = 0; tup_idx < n_processed; tup_idx++) { - bool isnull; - HeapTuple tuple = tuptable->vals[tup_idx]; + bool isnull; + HeapTuple tuple = tuptable->vals[tup_idx]; last_identity = DatumGetInt64(SPI_getbinval(tuple, tupdesc_ret, - attnum+1, + attnum + 1, &isnull)); Assert(!isnull); @@ -5484,14 +5554,14 @@ pltsql_update_identity_insert_sequence(PLtsql_expr *expr) /* * We also need to reset the seed. If the increment * is positive, we need to find the max identity that - * we've inserted. Other wise, we need to set the - * min identity. + * we've inserted. Other wise, we need to set the min + * identity. */ seq_options = sequence_options(seqid); - foreach (seq_lc, seq_options) + foreach(seq_lc, seq_options) { - DefElem *defel = (DefElem *) lfirst(seq_lc); + DefElem *defel = (DefElem *) lfirst(seq_lc); if (strcmp(defel->defname, "increment") == 0) seq_incr = defGetInt64(defel); @@ -5502,7 +5572,8 @@ pltsql_update_identity_insert_sequence(PLtsql_expr *expr) { /* * We want the T-SQL behavior of setval function. - * Please check the variable definition for details. + * Please check the variable definition for + * details. */ pltsql_setval_identity_mode = true; if (seq_incr > 0) @@ -5513,7 +5584,8 @@ pltsql_update_identity_insert_sequence(PLtsql_expr *expr) DirectFunctionCall2(setval_oid, ObjectIdGetDatum(seqid), Int64GetDatum(min_identity)); - else { + else + { /* increment can't be zero */ Assert(0); } @@ -5571,7 +5643,10 @@ exec_stmt_dynexecute(PLtsql_execstate *estate, /* Get the C-String representation */ querystr = convert_value_to_string(estate, query, restype); - /* carry out any local temporary table transformations that may be required */ + /* + * carry out any local temporary table transformations that may be + * required + */ querystr = transform_tsql_temp_tables(querystr); /* copy it into the stmt_mcontext before we clean up */ @@ -5619,9 +5694,9 @@ exec_stmt_dynexecute(PLtsql_execstate *estate, /* * We want to disallow SELECT INTO for now, because its behavior * is not consistent with SELECT INTO in a normal pltsql context. - * (We need to reimplement EXECUTE to parse the string as a - * pltsql command, not just feed it to SPI_execute.) This is not - * a functional limitation because CREATE TABLE AS is allowed. + * (We need to reimplement EXECUTE to parse the string as a pltsql + * command, not just feed it to SPI_execute.) This is not a + * functional limitation because CREATE TABLE AS is allowed. */ ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), @@ -5894,7 +5969,7 @@ exec_stmt_open(PLtsql_execstate *estate, PLtsql_stmt_open *stmt) * T-SQL cursor variable can refer to another constant cursor. * lookup cursor hash to get cursor definition. */ - int cursor_options; + int cursor_options; pltsql_get_cursor_definition(TextDatumGetCString(curvar->value), &query, &cursor_options); if (query == NULL) @@ -5935,7 +6010,7 @@ exec_stmt_open(PLtsql_execstate *estate, PLtsql_stmt_open *stmt) if (stmt_mcontext) MemoryContextReset(stmt_mcontext); - exec_set_rowcount(0); + exec_set_rowcount(0); /* * Different from specification document, tsql sets @@fetch_status to 0 @@ -6012,7 +6087,7 @@ exec_stmt_fetch(PLtsql_execstate *estate, PLtsql_stmt_fetch *stmt) PLtsql_variable *target; - if (stmt->target) /* target is given */ + if (stmt->target) /* target is given */ { /* ---------- * Fetch 1 tuple from the cursor @@ -6032,7 +6107,7 @@ exec_stmt_fetch(PLtsql_execstate *estate, PLtsql_stmt_fetch *stmt) else exec_move_row(estate, target, tuptab->vals[0], tuptab->tupdesc); } - else /* no target. push the result to client */ + else /* no target. push the result to client */ { DestReceiver *receiver; @@ -6111,7 +6186,7 @@ exec_stmt_close(PLtsql_execstate *estate, PLtsql_stmt_close *stmt) */ SPI_cursor_close(portal); - exec_set_rowcount(0); + exec_set_rowcount(0); pltsql_update_cursor_row_count(curname, 0); pltsql_update_cursor_last_operation(curname, 6); @@ -6181,7 +6256,7 @@ exec_stmt_set(PLtsql_execstate *estate, PLtsql_stmt_set *stmt) elog(ERROR, "SPI_execute_plan_extended failed executing query \"%s\": %s", expr->query, SPI_result_code_string(rc)); - exec_set_rowcount(0); + exec_set_rowcount(0); return PLTSQL_RC_OK; } @@ -6214,9 +6289,9 @@ exec_assign_expr(PLtsql_execstate *estate, PLtsql_datum *target, if (pltsql_explain_only && expr->ns) { - int rc; + int rc; PLtsql_nsitem *ns = expr->ns; - StringInfo strinfo = makeStringInfo(); + StringInfo strinfo = makeStringInfo(); while (ns) { @@ -6236,7 +6311,7 @@ exec_assign_expr(PLtsql_execstate *estate, PLtsql_datum *target, if (rc != SPI_OK_SELECT) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("query \"%s\" did not return data", expr->query))); + errmsg("query \"%s\" did not return data", expr->query))); exec_eval_cleanup(estate); return; @@ -6245,11 +6320,12 @@ exec_assign_expr(PLtsql_execstate *estate, PLtsql_datum *target, value = exec_eval_expr(estate, expr, &isnull, &valtype, &valtypmod); /* - * Unlike other scenario using implicit castings to (var)char, (i.e. insert into table) - * SET statement should suppress data truncation error. - * This context cannot be represented in PG casting framework, use a global variable to control this behavior. - * This variable is turned on in exec_assign_value only. - * Please note that "value" is already evaluated so this flag will not affect the evaluating expression itself. + * Unlike other scenario using implicit castings to (var)char, (i.e. + * insert into table) SET statement should suppress data truncation error. + * This context cannot be represented in PG casting framework, use a + * global variable to control this behavior. This variable is turned on in + * exec_assign_value only. Please note that "value" is already evaluated + * so this flag will not affect the evaluating expression itself. */ suppress_string_truncation_error = true; exec_assign_value(estate, target, value, isnull, valtype, valtypmod); @@ -6856,6 +6932,7 @@ exec_eval_datum(PLtsql_execstate *estate, case PLTSQL_DTYPE_TBL: { PLtsql_tbl *tbl = (PLtsql_tbl *) datum; + *typeid = tbl->tbltypeid; *typetypmod = -1; *value = CStringGetDatum(tbl->tblname); @@ -6877,7 +6954,7 @@ exec_eval_datum(PLtsql_execstate *estate, */ Oid pltsql_exec_get_datum_type(PLtsql_execstate *estate, - PLtsql_datum *datum) + PLtsql_datum *datum) { Oid typeid; @@ -6962,8 +7039,8 @@ pltsql_exec_get_datum_type(PLtsql_execstate *estate, */ void pltsql_exec_get_datum_type_info(PLtsql_execstate *estate, - PLtsql_datum *datum, - Oid *typeId, int32 *typMod, Oid *collation) + PLtsql_datum *datum, + Oid *typeId, int32 *typMod, Oid *collation) { switch (datum->dtype) { @@ -7120,7 +7197,7 @@ exec_eval_expr(PLtsql_execstate *estate, Oid *rettype, int32 *rettypmod) { - Datum result = 0; + Datum result = 0; int rc; Form_pg_attribute attr; @@ -7214,10 +7291,11 @@ exec_run_select(PLtsql_execstate *estate, */ if (expr->plan == NULL) exec_prepare_plan(estate, expr, portalP == NULL ? CURSOR_OPT_PARALLEL_OK : 0, true); + /* - * If we started an implicit_transaction for this statement but - * the statement has a simple expression associated with them, - * we no longer require an implicit transaction + * If we started an implicit_transaction for this statement but the + * statement has a simple expression associated with them, we no longer + * require an implicit transaction */ if (estate->impl_txn_type == PLTSQL_IMPL_TRAN_START) { @@ -7457,7 +7535,7 @@ exec_eval_simple_expr(PLtsql_execstate *estate, LocalTransactionId curlxid = MyProc->lxid; CachedPlan *cplan; void *save_setup_arg; - bool need_snapshot; + bool need_snapshot; MemoryContext oldcontext; /* @@ -7471,8 +7549,9 @@ exec_eval_simple_expr(PLtsql_execstate *estate, */ if (expr->expr_simple_in_use && expr->expr_simple_lxid == curlxid) return false; - - /* Ensure that there's a portal-level snapshot, in case this simple + + /* + * Ensure that there's a portal-level snapshot, in case this simple * expression is the first thing evaluated after a COMMIT or ROLLBACK. * We'd have to do this anyway before executing the expression, so we * might as well do it now to ensure that any possible replanning doesn't @@ -7522,10 +7601,10 @@ exec_eval_simple_expr(PLtsql_execstate *estate, /* * Prepare the expression for execution, if it's not been done already in * the current transaction. (This will be forced to happen if we called - * exec_save_simple_expr above.) - * We skip preparation for top level batch when it is not replanned. Top - * level batch memory is not reset due to commit/rollback. There is still - * leak when it is Top level batch + replan and needs fix. + * exec_save_simple_expr above.) We skip preparation for top level batch + * when it is not replanned. Top level batch memory is not reset due to + * commit/rollback. There is still leak when it is Top level batch + + * replan and needs fix. */ if (expr->expr_simple_lxid != curlxid && (expr->expr_simple_state == NULL || estate->use_shared_simple_eval_state)) { @@ -7543,15 +7622,15 @@ exec_eval_simple_expr(PLtsql_execstate *estate, * particular push a new snapshot so that stable functions within the * expression can see updates made so far by our own function. However, * we can skip doing that (and just invoke the expression with the same - * snapshot passed to our function) in some cases, which is useful because - * it's quite expensive relative to the cost of a simple expression. We - * can skip it if the expression contains no stable or volatile functions; - * immutable functions shouldn't need to see our updates. Also, if this - * is a read-only function, we haven't made any updates so again it's okay - * to skip. + * snapshot passed to our function) in some cases, which is useful because + * it's quite expensive relative to the cost of a simple expression. We + * can skip it if the expression contains no stable or volatile functions; + * immutable functions shouldn't need to see our updates. Also, if this + * is a read-only function, we haven't made any updates so again it's okay + * to skip. */ oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); - need_snapshot = (expr->expr_simple_mutable && !estate->readonly_func); + need_snapshot = (expr->expr_simple_mutable && !estate->readonly_func); if (need_snapshot) { CommandCounterIncrement(); @@ -7669,8 +7748,8 @@ setup_param_list(PLtsql_execstate *estate, PLtsql_expr *expr) */ static ParamExternData * pltsql_param_fetch(ParamListInfo params, - int paramid, bool speculative, - ParamExternData *prm) + int paramid, bool speculative, + ParamExternData *prm) { int dno; PLtsql_execstate *estate; @@ -7802,8 +7881,8 @@ pltsql_param_fetch(ParamListInfo params, */ static void pltsql_param_compile(ParamListInfo params, Param *param, - ExprState *state, - Datum *resv, bool *resnull) + ExprState *state, + Datum *resv, bool *resnull) { PLtsql_execstate *estate; PLtsql_expr *expr; @@ -7877,7 +7956,7 @@ pltsql_param_compile(ParamListInfo params, Param *param, */ static void pltsql_param_eval_var(ExprState *state, ExprEvalStep *op, - ExprContext *econtext) + ExprContext *econtext) { ParamListInfo params; PLtsql_execstate *estate; @@ -7909,7 +7988,7 @@ pltsql_param_eval_var(ExprState *state, ExprEvalStep *op, */ static void pltsql_param_eval_var_ro(ExprState *state, ExprEvalStep *op, - ExprContext *econtext) + ExprContext *econtext) { ParamListInfo params; PLtsql_execstate *estate; @@ -7946,7 +8025,7 @@ pltsql_param_eval_var_ro(ExprState *state, ExprEvalStep *op, */ static void pltsql_param_eval_recfield(ExprState *state, ExprEvalStep *op, - ExprContext *econtext) + ExprContext *econtext) { ParamListInfo params; PLtsql_execstate *estate; @@ -8018,7 +8097,7 @@ pltsql_param_eval_recfield(ExprState *state, ExprEvalStep *op, */ static void pltsql_param_eval_generic(ExprState *state, ExprEvalStep *op, - ExprContext *econtext) + ExprContext *econtext) { ParamListInfo params; PLtsql_execstate *estate; @@ -8058,7 +8137,7 @@ pltsql_param_eval_generic(ExprState *state, ExprEvalStep *op, */ static void pltsql_param_eval_generic_ro(ExprState *state, ExprEvalStep *op, - ExprContext *econtext) + ExprContext *econtext) { ParamListInfo params; PLtsql_execstate *estate; @@ -8549,7 +8628,10 @@ exec_move_row_from_fields(PLtsql_execstate *estate, valtypmod = -1; } - /* T-SQL output can take non-writable expression. skip assigning a value if it is not a parameter */ + /* + * T-SQL output can take non-writable expression. skip assigning a + * value if it is not a parameter + */ if (row->varnos[fnum] < 0) continue; @@ -8980,6 +9062,7 @@ convert_value_to_string(PLtsql_execstate *estate, Datum value, Oid valtype) oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); getTypeOutputInfo(valtype, &typoutput, &typIsVarlena); result = OidOutputFunctionCall(typoutput, value); + MemoryContextSwitchTo(oldcontext); return result; @@ -9066,8 +9149,8 @@ get_cast_hashentry(PLtsql_execstate *estate, cast_key.srctypmod = srctypmod; cast_key.dsttypmod = dsttypmod; cast_entry = (pltsql_CastHashEntry *) hash_search(estate->cast_hash, - (void *) &cast_key, - HASH_ENTER, &found); + (void *) &cast_key, + HASH_ENTER, &found); if (!found) /* initialize if new entry */ cast_entry->cast_cexpr = NULL; @@ -9081,7 +9164,7 @@ get_cast_hashentry(PLtsql_execstate *estate, Node *cast_expr; CachedExpression *cast_cexpr; CaseTestExpr *placeholder; - + /* * Drop old cached expression if there is one. */ @@ -9188,9 +9271,9 @@ get_cast_hashentry(PLtsql_execstate *estate, * hash table with the new tree because all pltsql functions within a * given transaction share the same simple_eval_estate. (Well, regular * functions do; DO blocks have private simple_eval_estates, and private - * cast hash tables to go with them.) - * We skip it for top level batch to avoid memory leak. There are still - * cases where memory can leak but we are fixing conservatively. + * cast hash tables to go with them.) We skip it for top level batch to + * avoid memory leak. There are still cases where memory can leak but we + * are fixing conservatively. */ curlxid = MyProc->lxid; if ((cast_entry->cast_lxid != curlxid && (cast_entry->cast_exprstate == NULL || estate->use_shared_simple_eval_state)) || cast_entry->cast_in_use) @@ -9334,10 +9417,12 @@ exec_set_fetch_status(PLtsql_execstate *estate, int status) assign_simple_var(estate, var, Int32GetDatum(status), false, false); /* - * Now, @@ is parsed as a system function (please see TSQL_ATAT in backend gram.y), - * we cannot access estate->fetch_status_varno. - * We will save the fetch status to a global variable and system function _sys.fetch_count() will access it. - * T-SQL document says @@FETCH_STATUS is global to all cursors on a connection, so this is also valid implementation. + * Now, @@ is parsed as a system function (please see TSQL_ATAT in backend + * gram.y), we cannot access estate->fetch_status_varno. We will save the + * fetch status to a global variable and system function + * _sys.fetch_count() will access it. T-SQL document says @@FETCH_STATUS + * is global to all cursors on a connection, so this is also valid + * implementation. */ fetch_status_var = status; } @@ -9345,25 +9430,25 @@ exec_set_fetch_status(PLtsql_execstate *estate, int status) static void exec_set_rowcount(uint64 rowno) { - rowcount_var = rowno; + rowcount_var = rowno; if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->set_at_at_stat_var) - (*pltsql_protocol_plugin_ptr)->set_at_at_stat_var("rowcount", 0, rowcount_var); + (*pltsql_protocol_plugin_ptr)->set_at_at_stat_var("rowcount", 0, rowcount_var); } -int latest_error_code; -int latest_pg_error_code; -bool last_error_mapping_failed; +int latest_error_code; +int latest_pg_error_code; +bool last_error_mapping_failed; static void exec_set_error(PLtsql_execstate *estate, int error, int pg_error, bool error_mapping_failed) { - latest_error_code = error; + latest_error_code = error; latest_pg_error_code = pg_error; last_error_mapping_failed = error_mapping_failed; if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->set_at_at_stat_var) - (*pltsql_protocol_plugin_ptr)->set_at_at_stat_var("error", latest_error_code, 0); + (*pltsql_protocol_plugin_ptr)->set_at_at_stat_var("error", latest_error_code, 0); } /* @@ -9419,9 +9504,8 @@ pltsql_create_econtext(PLtsql_execstate *estate) simple_econtext_stack = entry; /* - * Create a place holder portal to hold snapshot - * to handle transactional commands in PLTSQL batches - * procedures + * Create a place holder portal to hold snapshot to handle transactional + * commands in PLTSQL batches procedures */ if (ActivePortal == NULL && pltsql_snapshot_portal == NULL) { @@ -9440,6 +9524,7 @@ void pltsql_commit_not_required_impl_txn(PLtsql_execstate *estate) { MemoryContext cur_ctxt = CurrentMemoryContext; + elog(DEBUG2, "TSQL TXN Commit implicit transactions for command"); estate->impl_txn_type = PLTSQL_IMPL_TRAN_OFF; pltsql_commit_txn(); @@ -9458,8 +9543,8 @@ pltsql_commit_not_required_impl_txn(PLtsql_execstate *estate) void pltsql_eval_txn_data(PLtsql_execstate *estate, PLtsql_stmt_execsql *stmt, CachedPlanSource *cachedPlanSource) { - char *txn_name = NULL; - Node *node = linitial_node(Query, cachedPlanSource->query_list)->utilityStmt; + char *txn_name = NULL; + Node *node = linitial_node(Query, cachedPlanSource->query_list)->utilityStmt; TransactionStmt *txnStmt = (TransactionStmt *) node; stmt->txn_data->stmt_kind = txnStmt->kind; @@ -9468,10 +9553,10 @@ pltsql_eval_txn_data(PLtsql_execstate *estate, PLtsql_stmt_execsql *stmt, Cached { if (stmt->txn_data->txn_name_expr != NULL) { - Datum val; - bool isnull = true; - Oid restype; - int32 restypmod; + Datum val; + bool isnull = true; + Oid restype; + int32 restypmod; val = exec_eval_expr(estate, stmt->txn_data->txn_name_expr, &isnull, &restype, &restypmod); @@ -9524,6 +9609,7 @@ void pltsql_estate_cleanup(void) { PLExecStateCallStack *top_es_entry; + top_es_entry = exec_state_call_stack->next; if (top_es_entry != NULL) pltsql_copy_exec_error_data(&(exec_state_call_stack->error_data), @@ -9544,6 +9630,7 @@ txn_clean_estate(bool commit) while (simple_econtext_stack != NULL) { SimpleEcontextStackEntry *next; + FreeExprContext(simple_econtext_stack->stack_econtext, commit); next = simple_econtext_stack->next; @@ -9596,7 +9683,7 @@ pltsql_xact_cb(XactEvent event, void *arg) */ void pltsql_subxact_cb(SubXactEvent event, SubTransactionId mySubid, - SubTransactionId parentSubid, void *arg) + SubTransactionId parentSubid, void *arg) { if (event == SUBXACT_EVENT_COMMIT_SUB || event == SUBXACT_EVENT_ABORT_SUB) { @@ -9613,8 +9700,7 @@ pltsql_subxact_cb(SubXactEvent event, SubTransactionId mySubid, } /* - * In case owner sub transaction is rolled back, - * reset snapshot portal + * In case owner sub transaction is rolled back, reset snapshot portal */ if (event == SUBXACT_EVENT_ABORT_SUB && pltsql_snapshot_portal != NULL && @@ -9701,7 +9787,7 @@ assign_simple_var(PLtsql_execstate *estate, PLtsql_var *var, /* * free old value of a text variable and assign new value from C string */ -/*static*/ void + /* static */ void assign_text_var(PLtsql_execstate *estate, PLtsql_var *var, const char *str) { assign_simple_var(estate, var, CStringGetTextDatum(str), false, true); @@ -10001,17 +10087,17 @@ format_preparedparamsdata(PLtsql_execstate *estate, static void pltsql_clean_table_variables(PLtsql_execstate *estate, PLtsql_function *func) { - ListCell *lc; - int n; - int rc; + ListCell *lc; + int n; + int rc; PLtsql_tbl *tbl; - bool old_pltsql_explain_only = pltsql_explain_only; + bool old_pltsql_explain_only = pltsql_explain_only; const char *query_fmt = "DROP TABLE %s"; const char *query; PG_TRY(); { - foreach (lc, func->table_varnos) + foreach(lc, func->table_varnos) { n = lfirst_int(lc); if (estate->datums[n]->dtype != PLTSQL_DTYPE_TBL) @@ -10021,12 +10107,13 @@ pltsql_clean_table_variables(PLtsql_execstate *estate, PLtsql_function *func) continue; query = psprintf(query_fmt, tbl->tblname); - pltsql_explain_only = false; /* Drop temporary table even in EXPLAIN ONLY mode */ + pltsql_explain_only = false; /* Drop temporary table even in + * EXPLAIN ONLY mode */ rc = SPI_execute(query, false, 0); if (rc != SPI_OK_UTILITY) elog(ERROR, "Failed to drop the underlying table %s of table variable %s", - tbl->tblname, tbl->refname); + tbl->tblname, tbl->refname); if (old_pltsql_explain_only) { @@ -10038,13 +10125,14 @@ pltsql_clean_table_variables(PLtsql_execstate *estate, PLtsql_function *func) } PG_CATCH(); { - pltsql_explain_only = old_pltsql_explain_only; /* Recover EXPLAIN ONLY mode */ + pltsql_explain_only = old_pltsql_explain_only; /* Recover EXPLAIN ONLY + * mode */ PG_RE_THROW(); } PG_END_TRY(); } -static void +static void pltsql_init_exec_error_data(PLtsqlErrorData *error_data) { error_data->xact_abort_on = false; @@ -10067,6 +10155,7 @@ pltsql_copy_exec_error_data(PLtsqlErrorData *src, PLtsqlErrorData *dst, MemoryCo if (src->error_procedure != NULL) { MemoryContext oldContext = MemoryContextSwitchTo(dstCtx); + dst->error_procedure = pstrdup(src->error_procedure); MemoryContextSwitchTo(oldContext); } @@ -10080,29 +10169,32 @@ PLtsql_estate_err * pltsql_clone_estate_err(PLtsql_estate_err *err) { PLtsql_estate_err *clone = palloc(sizeof(PLtsql_estate_err)); + memcpy(clone, err, sizeof(PLtsql_estate_err)); return clone; } -static bool reset_search_path(PLtsql_stmt_execsql *stmt, char **old_search_path, bool* reset_session_properties, bool inside_trigger) +static bool +reset_search_path(PLtsql_stmt_execsql *stmt, char **old_search_path, bool *reset_session_properties, bool inside_trigger) { PLExecStateCallStack *top_es_entry; - char *cur_dbname = get_cur_db_name(); - char *new_search_path; - char *physical_schema; - const char *dbo_schema; + char *cur_dbname = get_cur_db_name(); + char *new_search_path; + char *physical_schema; + const char *dbo_schema; + top_es_entry = exec_state_call_stack->next; - while(top_es_entry != NULL) + while (top_es_entry != NULL) { /* - * Traverse through the estate stack. If the occurrence of - * exec in the call stack, update the search path accordingly. + * Traverse through the estate stack. If the occurrence of exec in the + * call stack, update the search path accordingly. */ - if(top_es_entry->estate && top_es_entry->estate->err_stmt && + if (top_es_entry->estate && top_es_entry->estate->err_stmt && top_es_entry->estate->err_stmt->cmd_type == PLTSQL_STMT_EXEC) { - if(top_es_entry->estate->schema_name != NULL && stmt->is_dml) + if (top_es_entry->estate->schema_name != NULL && stmt->is_dml) { if (top_es_entry->estate->db_name == NULL) { @@ -10110,7 +10202,7 @@ static bool reset_search_path(PLtsql_stmt_execsql *stmt, char **old_search_path, * Don't change the search path, if the statement inside * the procedure is a function or schema qualified. */ - if(stmt->func_call || stmt->is_schema_specified) + if (stmt->func_call || stmt->is_schema_specified) break; else { @@ -10134,18 +10226,23 @@ static bool reset_search_path(PLtsql_stmt_execsql *stmt, char **old_search_path, } if (!*old_search_path) { - List *path_oids = fetch_search_path(false); + List *path_oids = fetch_search_path(false); + *old_search_path = flatten_search_path(path_oids); list_free(path_oids); } new_search_path = psprintf("%s, %s, %s", physical_schema, dbo_schema, *old_search_path); - /* Add the schema where the object is referenced and dbo schema to the new search path */ + + /* + * Add the schema where the object is referenced and dbo + * schema to the new search path + */ (void) set_config_option("search_path", new_search_path, - PGC_USERSET, PGC_S_SESSION, - GUC_ACTION_SAVE, true, 0, false); + PGC_USERSET, PGC_S_SESSION, + GUC_ACTION_SAVE, true, 0, false); return true; } - else if(top_es_entry->estate->db_name != NULL && stmt->is_ddl) + else if (top_es_entry->estate->db_name != NULL && stmt->is_ddl) { set_session_properties(top_es_entry->estate->db_name); *reset_session_properties = true; @@ -10153,18 +10250,18 @@ static bool reset_search_path(PLtsql_stmt_execsql *stmt, char **old_search_path, } } /* if the stmt is inside an exec_batch, return false */ - else if(top_es_entry->estate && top_es_entry->estate->err_stmt && - top_es_entry->estate->err_stmt->cmd_type == PLTSQL_STMT_EXEC_BATCH) + else if (top_es_entry->estate && top_es_entry->estate->err_stmt && + top_es_entry->estate->err_stmt->cmd_type == PLTSQL_STMT_EXEC_BATCH) return false; /* - * Traverse through the estate stack, if the stmt is inside trigger - * we set the search path accordingly. + * Traverse through the estate stack, if the stmt is inside trigger we + * set the search path accordingly. */ - else if(top_es_entry->estate && top_es_entry->estate->err_stmt && - top_es_entry->estate->err_stmt->cmd_type == PLTSQL_STMT_EXECSQL) + else if (top_es_entry->estate && top_es_entry->estate->err_stmt && + top_es_entry->estate->err_stmt->cmd_type == PLTSQL_STMT_EXECSQL) { - if(inside_trigger && top_es_entry->estate->schema_name) + if (inside_trigger && top_es_entry->estate->schema_name) { /* * If the object in the stmt is schema qualified or it's a ddl @@ -10178,43 +10275,54 @@ static bool reset_search_path(PLtsql_stmt_execsql *stmt, char **old_search_path, dbo_schema = get_dbo_schema_name(cur_dbname); if (!*old_search_path) { - List *path_oids = fetch_search_path(false); + List *path_oids = fetch_search_path(false); + *old_search_path = flatten_search_path(path_oids); list_free(path_oids); } new_search_path = psprintf("%s, %s, %s", physical_schema, dbo_schema, *old_search_path); - /* Add the schema where the object is referenced and dbo schema to the new search path */ + + /* + * Add the schema where the object is referenced and dbo + * schema to the new search path + */ (void) set_config_option("search_path", new_search_path, - PGC_USERSET, PGC_S_SESSION, - GUC_ACTION_SAVE, true, 0, false); + PGC_USERSET, PGC_S_SESSION, + GUC_ACTION_SAVE, true, 0, false); return true; } } } top_es_entry = top_es_entry->next; } + /* - * When there is a function call: - * search the specified schema for the object. If not found, - * then search the dbo schema. Don't update the path for "sys" schema. + * When there is a function call: search the specified schema for the + * object. If not found, then search the dbo schema. Don't update the path + * for "sys" schema. */ if ((stmt->func_call || stmt->is_create_view) && stmt->schema_name != NULL && - (strcmp(stmt->schema_name, "sys") != 0 && strcmp(stmt->schema_name, "pg_catalog") != 0)) + (strcmp(stmt->schema_name, "sys") != 0 && strcmp(stmt->schema_name, "pg_catalog") != 0)) { cur_dbname = get_cur_db_name(); physical_schema = get_physical_schema_name(cur_dbname, stmt->schema_name); dbo_schema = get_dbo_schema_name(cur_dbname); if (!*old_search_path) { - List *path_oids = fetch_search_path(false); + List *path_oids = fetch_search_path(false); + *old_search_path = flatten_search_path(path_oids); list_free(path_oids); } new_search_path = psprintf("%s, %s, %s", physical_schema, dbo_schema, *old_search_path); - /* Add the schema where the object is referenced and dbo schema to the new search path */ + + /* + * Add the schema where the object is referenced and dbo schema to the + * new search path + */ (void) set_config_option("search_path", new_search_path, - PGC_USERSET, PGC_S_SESSION, - GUC_ACTION_SAVE, true, 0, false); + PGC_USERSET, PGC_S_SESSION, + GUC_ACTION_SAVE, true, 0, false); return true; } return false; diff --git a/contrib/babelfishpg_tsql/src/pl_explain.c b/contrib/babelfishpg_tsql/src/pl_explain.c index 9bfcd2bc8c..a279f7a615 100644 --- a/contrib/babelfishpg_tsql/src/pl_explain.c +++ b/contrib/babelfishpg_tsql/src/pl_explain.c @@ -8,28 +8,30 @@ extern PLtsql_execstate *get_outermost_tsql_estate(int *nestlevel); extern PLtsql_execstate *get_current_tsql_estate(); -bool pltsql_explain_only = false; -bool pltsql_explain_analyze = false; -bool pltsql_explain_verbose = false; -bool pltsql_explain_costs = true; -bool pltsql_explain_settings = false; -bool pltsql_explain_buffers = false; -bool pltsql_explain_wal = false; -bool pltsql_explain_timing = true; -bool pltsql_explain_summary = true; -int pltsql_explain_format = EXPLAIN_FORMAT_TEXT; +bool pltsql_explain_only = false; +bool pltsql_explain_analyze = false; +bool pltsql_explain_verbose = false; +bool pltsql_explain_costs = true; +bool pltsql_explain_settings = false; +bool pltsql_explain_buffers = false; +bool pltsql_explain_wal = false; +bool pltsql_explain_timing = true; +bool pltsql_explain_summary = true; +int pltsql_explain_format = EXPLAIN_FORMAT_TEXT; static ExplainInfo *get_last_explain_info(); -bool is_explain_analyze_mode() +bool +is_explain_analyze_mode() { return (pltsql_explain_analyze && !pltsql_explain_only); } -static ExplainInfo *get_last_explain_info() +static ExplainInfo * +get_last_explain_info() { PLtsql_execstate *pltsql_estate; - int nestlevel; + int nestlevel; if (!pltsql_explain_analyze && !pltsql_explain_only) return NULL; @@ -41,29 +43,34 @@ static ExplainInfo *get_last_explain_info() return (ExplainInfo *) llast(pltsql_estate->explain_infos); } -void increment_explain_indent() +void +increment_explain_indent() { ExplainInfo *einfo = get_last_explain_info(); + if (einfo) einfo->next_indent++; } -void decrement_explain_indent() +void +decrement_explain_indent() { ExplainInfo *einfo = get_last_explain_info(); + if (einfo) einfo->next_indent--; } -void append_explain_info(QueryDesc *queryDesc, const char *queryString) +void +append_explain_info(QueryDesc *queryDesc, const char *queryString) { PLtsql_execstate *pltsql_estate; MemoryContext oldcxt; ExplainState *es; ExplainInfo *einfo; const char *initial_database; - size_t indent; - int nestlevel; + size_t indent; + int nestlevel; if (!pltsql_explain_analyze && !pltsql_explain_only) return; @@ -73,23 +80,24 @@ void append_explain_info(QueryDesc *queryDesc, const char *queryString) return; /* - * In some cases, PLtsql_execstate can be created during ExecutorRun. - * For example, in the case of ITVF (Inline Table-Valued Function), - * exec_stmt_return_query(...) is called inside execute_plan_and_push_result(...) - * and those two functions have different PLtsql_execstate. + * In some cases, PLtsql_execstate can be created during ExecutorRun. For + * example, in the case of ITVF (Inline Table-Valued Function), + * exec_stmt_return_query(...) is called inside + * execute_plan_and_push_result(...) and those two functions have + * different PLtsql_execstate. * - * To show proper query plans we should gather all ExplainInfos until - * the end of a batch execution. So, we need the outermost PLtsql_execstate and - * add ExplainInfo to it. + * To show proper query plans we should gather all ExplainInfos until the + * end of a batch execution. So, we need the outermost PLtsql_execstate + * and add ExplainInfo to it. */ pltsql_estate = get_outermost_tsql_estate(&nestlevel); if (!pltsql_estate) return; /* - * There are some cases where oldcxt is released - * before the end of a batch exeuction, e.g., INSERT statements. - * So, we should choose the parent memory context for ExplainInfo. + * There are some cases where oldcxt is released before the end of a batch + * exeuction, e.g., INSERT statements. So, we should choose the parent + * memory context for ExplainInfo. */ oldcxt = MemoryContextSwitchTo(pltsql_estate->stmt_mcontext_parent); @@ -105,6 +113,7 @@ void append_explain_info(QueryDesc *queryDesc, const char *queryString) if (pltsql_estate->explain_infos) { ExplainInfo *last_einfo = (ExplainInfo *) llast(pltsql_estate->explain_infos); + indent = last_einfo->next_indent; initial_database = last_einfo->initial_database; } @@ -144,8 +153,10 @@ void append_explain_info(QueryDesc *queryDesc, const char *queryString) ExplainPrintTriggers(es, queryDesc); if (es->costs) ExplainPrintJITSummary(es, queryDesc); - if (es->summary) { + if (es->summary) + { PLtsql_execstate *time_state = get_current_tsql_estate(); + ExplainPropertyFloat("Planning Time", "ms", 1000.0 * INSTR_TIME_GET_DOUBLE(time_state->planning_end), 3, es); INSTR_TIME_SET_CURRENT(time_state->execution_end); INSTR_TIME_SUBTRACT(time_state->execution_end, time_state->execution_start); @@ -155,7 +166,10 @@ void append_explain_info(QueryDesc *queryDesc, const char *queryString) } else if (queryString) { - /* In EXPLAIN ONLY mode, queryDesc can be null if it is called from ProcessUtility() */ + /* + * In EXPLAIN ONLY mode, queryDesc can be null if it is called from + * ProcessUtility() + */ ExplainPropertyText("Query Text", queryString, es); } else @@ -185,19 +199,24 @@ void append_explain_info(QueryDesc *queryDesc, const char *queryString) MemoryContextSwitchTo(oldcxt); } -void set_explain_database(const char *db_name) +void +set_explain_database(const char *db_name) { - ExplainInfo *einfo = get_last_explain_info(); - einfo->initial_database = db_name; + ExplainInfo *einfo = get_last_explain_info(); + + einfo->initial_database = db_name; } -const char *get_explain_database(void) +const char * +get_explain_database(void) { - ExplainInfo *einfo = get_last_explain_info(); - if (einfo != NULL) - return einfo->initial_database; - return NULL; + ExplainInfo *einfo = get_last_explain_info(); + + if (einfo != NULL) + return einfo->initial_database; + return NULL; } + /* * The main purpose of this function is for displaying TSQL statements such as PRINT * and THROW during explain. Since babelfish represents most expressions internally @@ -207,14 +226,16 @@ const char *get_explain_database(void) * This functions validates that the expression object exists, has a query text, * and returns a pointer to a new string representing the expression minus the "SELECT " */ -const char *strip_select_from_expr(void * pltsql_expr) +const char * +strip_select_from_expr(void *pltsql_expr) { - PLtsql_expr * expr; + PLtsql_expr *expr; + expr = (PLtsql_expr *) pltsql_expr; if (expr == NULL || expr->query == NULL || strlen(expr->query) <= 7) { ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("invalid expression %p", (void *) expr))); + errmsg("invalid expression %p", (void *) expr))); } return pstrdup(&expr->query[7]); diff --git a/contrib/babelfishpg_tsql/src/pl_explain.h b/contrib/babelfishpg_tsql/src/pl_explain.h index af2ab47cfa..a31ab9f4ee 100644 --- a/contrib/babelfishpg_tsql/src/pl_explain.h +++ b/contrib/babelfishpg_tsql/src/pl_explain.h @@ -12,7 +12,7 @@ extern bool pltsql_explain_buffers; extern bool pltsql_explain_wal; extern bool pltsql_explain_timing; extern bool pltsql_explain_summary; -extern int pltsql_explain_format; +extern int pltsql_explain_format; extern bool is_explain_analyze_mode(void); extern void increment_explain_indent(void); @@ -25,7 +25,7 @@ extern const char *get_explain_database(void); * expr will be a PLtsql_expr * declared as void to avoid including the pltsql.h file * in this file */ -extern const char *strip_select_from_expr(void * expr); +extern const char *strip_select_from_expr(void *expr); -#endif /* PL_EXPLAIN_H */ +#endif /* PL_EXPLAIN_H */ diff --git a/contrib/babelfishpg_tsql/src/pl_funcs-2.c b/contrib/babelfishpg_tsql/src/pl_funcs-2.c index ceeafb18c3..5347259266 100644 --- a/contrib/babelfishpg_tsql/src/pl_funcs-2.c +++ b/contrib/babelfishpg_tsql/src/pl_funcs-2.c @@ -13,28 +13,33 @@ #include "utils/numeric.h" #include "utils/syscache.h" -static int cmpfunc(const void *a, const void *b) +static int +cmpfunc(const void *a, const void *b) { - return ( *(int*)a - *(int*)b ); + return (*(int *) a - *(int *) b); } PG_FUNCTION_INFO_V1(updated); Datum -updated(PG_FUNCTION_ARGS){ +updated(PG_FUNCTION_ARGS) +{ char *column = text_to_cstring(PG_GETARG_TEXT_PP(0)); - char *real_column; - List *curr_columns_list; + char *real_column; + List *curr_columns_list; ListCell *l; - if (pltsql_trigger_depth-1column_name; - if (pg_strcasecmp(real_column, column) == 0){ - PG_RETURN_BOOL(true); - } + if (pltsql_trigger_depth - 1 < list_length(columns_updated_list)) + curr_columns_list = (List *) list_nth(columns_updated_list, pltsql_trigger_depth - 1); + else + curr_columns_list = NIL; + foreach(l, curr_columns_list) + { + real_column = ((UpdatedColumn *) lfirst(l))->column_name; + if (pg_strcasecmp(real_column, column) == 0) + { + PG_RETURN_BOOL(true); } + } PG_RETURN_BOOL(false); } @@ -43,48 +48,60 @@ Datum columnsupdated(PG_FUNCTION_ARGS) { StringInfoData buf; - ListCell *l; + ListCell *l; UpdatedColumn *column; - List* curr_columns_list; - int *columnIndex; - int i; - int length, bufSize, curByteIndex, total_columns = 0; - int8 curBuf; - int j; + List *curr_columns_list; + int *columnIndex; + int i; + int length, + bufSize, + curByteIndex, + total_columns = 0; + int8 curBuf; + int j; + if (columns_updated_list == NULL) { PG_RETURN_NULL(); } - if (pltsql_trigger_depth-1 0){ - columnIndex = (int *) palloc(sizeof(int) * length); + if (length > 0) + { + columnIndex = (int *) palloc(sizeof(int) * length); i = 0; - foreach(l, curr_columns_list){ - column = (UpdatedColumn *)lfirst(l); + foreach(l, curr_columns_list) + { + column = (UpdatedColumn *) lfirst(l); columnIndex[i] = column->x_attnum; total_columns = column->total_columns; ++i; } qsort(columnIndex, length, sizeof(int), cmpfunc); - bufSize = total_columns/8 + 1; + bufSize = total_columns / 8 + 1; curByteIndex = 0; - for (i = 0; i < length; ++i){ - if ( columnIndex[i]/8 > curByteIndex){ - for(j = curByteIndex; j curByteIndex) + { + for (j = curByteIndex; j < columnIndex[i] / 8; ++j) + { pq_writeint8(&buf, curBuf); curBuf = 0; } - curByteIndex = columnIndex[i]/8; + curByteIndex = columnIndex[i] / 8; } - curBuf = curBuf | (1<<(columnIndex[i]%8-1)); + curBuf = curBuf | (1 << (columnIndex[i] % 8 - 1)); } - while(curByteIndex++pltsql_instr_increment_func_metric)) + (*pltsql_instr_plugin_ptr) && + (*pltsql_instr_plugin_ptr)->pltsql_instr_increment_func_metric)) { - char *prefix = "instr_tsql_"; - char *funcname_edited = replace_with_underscore(funcName); - StringInfoData metricName; - initStringInfo(&metricName); + char *prefix = "instr_tsql_"; + char *funcname_edited = replace_with_underscore(funcName); + StringInfoData metricName; + + initStringInfo(&metricName); - appendStringInfoString(&metricName, prefix); - appendStringInfoString(&metricName, funcname_edited); + appendStringInfoString(&metricName, prefix); + appendStringInfoString(&metricName, funcname_edited); if (!(*pltsql_instr_plugin_ptr)->pltsql_instr_increment_func_metric(metricName.data)) { @@ -344,10 +364,10 @@ pre_function_call_hook_impl(const char *funcName) (*pltsql_instr_plugin_ptr)->pltsql_instr_increment_func_metric(metricName.data); } - if(funcname_edited != NULL) - pfree(funcname_edited); - if(metricName.data != NULL) - pfree(metricName.data); + if (funcname_edited != NULL) + pfree(funcname_edited); + if (metricName.data != NULL) + pfree(metricName.data); } } @@ -355,12 +375,14 @@ int32 coalesce_typmod_hook_impl(const CoalesceExpr *cexpr) { /* - * For T-SQL ISNULL, the typmod depends only on the first argument of - * the function unlike PG COALESCE, which checks whether all the data - * types and their typmods are in agreement. + * For T-SQL ISNULL, the typmod depends only on the first argument of the + * function unlike PG COALESCE, which checks whether all the data types + * and their typmods are in agreement. */ - Oid nspoid, pg_catalog_numericoid, sys_decimaloid; + Oid nspoid, + pg_catalog_numericoid, + sys_decimaloid; nspoid = get_namespace_oid("pg_catalog", false); pg_catalog_numericoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, CStringGetDatum("numeric"), ObjectIdGetDatum(nspoid)); @@ -369,8 +391,8 @@ coalesce_typmod_hook_impl(const CoalesceExpr *cexpr) sys_decimaloid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, CStringGetDatum("decimal"), ObjectIdGetDatum(nspoid)); /* - * If data type is numeric/decimal, resolve_numeric_typmod_from_exp - * will figure out the precision and scale. + * If data type is numeric/decimal, resolve_numeric_typmod_from_exp will + * figure out the precision and scale. */ if (cexpr->coalescetype == pg_catalog_numericoid || cexpr->coalescetype == sys_decimaloid) return -1; @@ -391,148 +413,152 @@ free_stmt2(PLtsql_stmt *stmt) switch (stmt->cmd_type) { case PLTSQL_STMT_GOTO: - { - PLtsql_stmt_goto *go = (PLtsql_stmt_goto *) stmt; + { + PLtsql_stmt_goto *go = (PLtsql_stmt_goto *) stmt; - free_expr(go->cond); + free_expr(go->cond); - break; - } + break; + } case PLTSQL_STMT_PRINT: - { - PLtsql_stmt_print *print = (PLtsql_stmt_print *) stmt; - ListCell *l; + { + PLtsql_stmt_print *print = (PLtsql_stmt_print *) stmt; + ListCell *l; - foreach(l, print->exprs) - free_expr((PLtsql_expr *) lfirst(l)); - break; - } + foreach(l, print->exprs) + free_expr((PLtsql_expr *) lfirst(l)); + break; + } - case PLTSQL_STMT_INIT: - { - PLtsql_stmt_init *init = (PLtsql_stmt_init *) stmt; - ListCell *l; + case PLTSQL_STMT_INIT: + { + PLtsql_stmt_init *init = (PLtsql_stmt_init *) stmt; + ListCell *l; - foreach(l, init->inits) - free_stmt((PLtsql_stmt *) lfirst(l)); - break; - } + foreach(l, init->inits) + free_stmt((PLtsql_stmt *) lfirst(l)); + break; + } - case PLTSQL_STMT_QUERY_SET: - { - PLtsql_stmt_query_set *select = (PLtsql_stmt_query_set *) stmt; + case PLTSQL_STMT_QUERY_SET: + { + PLtsql_stmt_query_set *select = (PLtsql_stmt_query_set *) stmt; - free_expr(select->sqlstmt); + free_expr(select->sqlstmt); - break; - } + break; + } - case PLTSQL_STMT_TRY_CATCH: - { - PLtsql_stmt_try_catch *try_catch = (PLtsql_stmt_try_catch *) stmt; - free_stmt((PLtsql_stmt *) try_catch->body); - free_stmt((PLtsql_stmt *) try_catch->handler); - break; - } + case PLTSQL_STMT_TRY_CATCH: + { + PLtsql_stmt_try_catch *try_catch = (PLtsql_stmt_try_catch *) stmt; - case PLTSQL_STMT_PUSH_RESULT: - { - PLtsql_stmt_push_result *push = (PLtsql_stmt_push_result *) stmt; - free_expr(push->query); - break; - } + free_stmt((PLtsql_stmt *) try_catch->body); + free_stmt((PLtsql_stmt *) try_catch->handler); + break; + } - case PLTSQL_STMT_EXEC: - { - PLtsql_stmt_exec *exec = (PLtsql_stmt_exec *) stmt; - free_expr(exec->expr); - break; - } + case PLTSQL_STMT_PUSH_RESULT: + { + PLtsql_stmt_push_result *push = (PLtsql_stmt_push_result *) stmt; + + free_expr(push->query); + break; + } + + case PLTSQL_STMT_EXEC: + { + PLtsql_stmt_exec *exec = (PLtsql_stmt_exec *) stmt; + + free_expr(exec->expr); + break; + } case PLTSQL_STMT_EXEC_BATCH: - { - PLtsql_stmt_exec_batch *exec = (PLtsql_stmt_exec_batch *) stmt; + { + PLtsql_stmt_exec_batch *exec = (PLtsql_stmt_exec_batch *) stmt; - free_expr(exec->expr); + free_expr(exec->expr); - break; - } + break; + } case PLTSQL_STMT_EXEC_SP: - { - PLtsql_stmt_exec_sp *exec = (PLtsql_stmt_exec_sp *) stmt; - ListCell *l; - - if (exec->handle) - free_expr(exec->handle); - if (exec->query) - free_expr(exec->query); - if (exec->param_def) - free_expr(exec->param_def); - foreach(l, exec->params) - free_expr((PLtsql_expr *) ((tsql_exec_param *) lfirst(l))->expr); - if (exec->opt1) - free_expr(exec->opt1); - if (exec->opt2) - free_expr(exec->opt2); - if (exec->opt3) - free_expr(exec->opt3); - break; - } + { + PLtsql_stmt_exec_sp *exec = (PLtsql_stmt_exec_sp *) stmt; + ListCell *l; + + if (exec->handle) + free_expr(exec->handle); + if (exec->query) + free_expr(exec->query); + if (exec->param_def) + free_expr(exec->param_def); + foreach(l, exec->params) + free_expr((PLtsql_expr *) ((tsql_exec_param *) lfirst(l))->expr); + if (exec->opt1) + free_expr(exec->opt1); + if (exec->opt2) + free_expr(exec->opt2); + if (exec->opt3) + free_expr(exec->opt3); + break; + } case PLTSQL_STMT_DECL_TABLE: - { - /* Nothing to free */ - break; - } + { + /* Nothing to free */ + break; + } case PLTSQL_STMT_RETURN_TABLE: - { - free_return_query((PLtsql_stmt_return_query *) stmt); - break; - } + { + free_return_query((PLtsql_stmt_return_query *) stmt); + break; + } case PLTSQL_STMT_DEALLOCATE: - { - /* Nothing to free */ - break; - } + { + /* Nothing to free */ + break; + } case PLTSQL_STMT_DECL_CURSOR: - { - PLtsql_stmt_decl_cursor *decl = (PLtsql_stmt_decl_cursor *) stmt; - free_expr(decl->cursor_explicit_expr); - break; - } - case PLTSQL_STMT_LABEL: + { + PLtsql_stmt_decl_cursor *decl = (PLtsql_stmt_decl_cursor *) stmt; + + free_expr(decl->cursor_explicit_expr); + break; + } + case PLTSQL_STMT_LABEL: case PLTSQL_STMT_USEDB: - case PLTSQL_STMT_INSERT_BULK: + case PLTSQL_STMT_INSERT_BULK: case PLTSQL_STMT_GRANTDB: case PLTSQL_STMT_SET_EXPLAIN_MODE: - { - /* Nothing to free */ - break; - } + { + /* Nothing to free */ + break; + } case PLTSQL_STMT_RAISERROR: - { - PLtsql_stmt_raiserror *raiserror = (PLtsql_stmt_raiserror *) stmt; - ListCell *l; + { + PLtsql_stmt_raiserror *raiserror = (PLtsql_stmt_raiserror *) stmt; + ListCell *l; - foreach(l, raiserror->params) - free_expr((PLtsql_expr *) lfirst(l)); - break; - } + foreach(l, raiserror->params) + free_expr((PLtsql_expr *) lfirst(l)); + break; + } case PLTSQL_STMT_THROW: - { - PLtsql_stmt_throw *throw = (PLtsql_stmt_throw *) stmt; - ListCell *l; + { + PLtsql_stmt_throw *throw = (PLtsql_stmt_throw *) stmt; + ListCell *l; - foreach(l, throw->params) - free_expr((PLtsql_expr *) lfirst(l)); - break; - } - case PLTSQL_STMT_SAVE_CTX: - case PLTSQL_STMT_RESTORE_CTX_FULL: - case PLTSQL_STMT_RESTORE_CTX_PARTIAL: - { - break; - } - default: + foreach(l, throw->params) + free_expr((PLtsql_expr *) lfirst(l)); + break; + } + case PLTSQL_STMT_SAVE_CTX: + case PLTSQL_STMT_RESTORE_CTX_FULL: + case PLTSQL_STMT_RESTORE_CTX_PARTIAL: + { + break; + } + default: elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type); break; } @@ -542,85 +568,86 @@ free_stmt2(PLtsql_stmt *stmt) * DUMP FUNCTIONS **********************************************************************************/ -void dump_stmt2(PLtsql_stmt *stmt); - -void dump_stmt_print(PLtsql_stmt_print *stmt_print); -void dump_stmt_init(PLtsql_stmt_init *stmt_init); -void dump_stmt_push_result(PLtsql_stmt_push_result *stmt_push_result); -void dump_stmt_exec(PLtsql_stmt_exec *stmt_exec); -void dump_stmt_goto(PLtsql_stmt_goto *stmt_goto); -void dump_stmt_label(PLtsql_stmt_label *stmt_label); -void dump_stmt_raiserror(PLtsql_stmt_raiserror *stmt_raiserror); -void dump_stmt_throw(PLtsql_stmt_throw *stmt_throw); -void dump_stmt_usedb(PLtsql_stmt_usedb *stmt_usedb); -void dump_stmt_grantdb(PLtsql_stmt_grantdb *stmt_grantdb); -void dump_stmt_insert_bulk(PLtsql_stmt_insert_bulk *stmt_insert_bulk); -void dump_stmt_try_catch(PLtsql_stmt_try_catch *stmt_try_catch); -void dump_stmt_query_set(PLtsql_stmt_query_set *query_set); -void dump_stmt_exec_batch(PLtsql_stmt_exec_batch *exec_batch); -void get_grantees_names(List *grantees, StringInfo grantees_names); +void dump_stmt2(PLtsql_stmt *stmt); + +void dump_stmt_print(PLtsql_stmt_print *stmt_print); +void dump_stmt_init(PLtsql_stmt_init *stmt_init); +void dump_stmt_push_result(PLtsql_stmt_push_result *stmt_push_result); +void dump_stmt_exec(PLtsql_stmt_exec *stmt_exec); +void dump_stmt_goto(PLtsql_stmt_goto *stmt_goto); +void dump_stmt_label(PLtsql_stmt_label *stmt_label); +void dump_stmt_raiserror(PLtsql_stmt_raiserror *stmt_raiserror); +void dump_stmt_throw(PLtsql_stmt_throw *stmt_throw); +void dump_stmt_usedb(PLtsql_stmt_usedb *stmt_usedb); +void dump_stmt_grantdb(PLtsql_stmt_grantdb *stmt_grantdb); +void dump_stmt_insert_bulk(PLtsql_stmt_insert_bulk *stmt_insert_bulk); +void dump_stmt_try_catch(PLtsql_stmt_try_catch *stmt_try_catch); +void dump_stmt_query_set(PLtsql_stmt_query_set *query_set); +void dump_stmt_exec_batch(PLtsql_stmt_exec_batch *exec_batch); +void get_grantees_names(List *grantees, StringInfo grantees_names); void dump_stmt_print(PLtsql_stmt_print *stmt_print) { - ListCell *l; - - printf("PRINT "); - foreach(l, stmt_print->exprs) - { - dump_expr((PLtsql_expr *) lfirst(l)); - printf(" ,"); - } - printf("\n"); + ListCell *l; + + printf("PRINT "); + foreach(l, stmt_print->exprs) + { + dump_expr((PLtsql_expr *) lfirst(l)); + printf(" ,"); + } + printf("\n"); } void dump_stmt_init(PLtsql_stmt_init *stmt_init) { - ListCell *l; - printf("DECLARE "); - foreach(l, stmt_init->inits) - { - if (l) - dump_assign((PLtsql_stmt_assign *)lfirst(l)); - - printf(" ,"); /* could not print some variables */ - } - printf("\n"); + ListCell *l; + + printf("DECLARE "); + foreach(l, stmt_init->inits) + { + if (l) + dump_assign((PLtsql_stmt_assign *) lfirst(l)); + + printf(" ,"); /* could not print some variables */ + } + printf("\n"); } void dump_stmt_push_result(PLtsql_stmt_push_result *stmt_push_result) { - printf("PUSH RESULT: "); - dump_expr(stmt_push_result->query); - printf("\n"); + printf("PUSH RESULT: "); + dump_expr(stmt_push_result->query); + printf("\n"); } void dump_stmt_exec(PLtsql_stmt_exec *stmt_exec) { - printf("EXEC "); - dump_expr(stmt_exec->expr); - printf("\n"); + printf("EXEC "); + dump_expr(stmt_exec->expr); + printf("\n"); } void dump_stmt_goto(PLtsql_stmt_goto *stmt_goto) { - printf("GOTO %s\n", stmt_goto->target_label); + printf("GOTO %s\n", stmt_goto->target_label); } void dump_stmt_label(PLtsql_stmt_label *stmt_label) { - printf("%s:\n", stmt_label->label); + printf("%s:\n", stmt_label->label); } void dump_stmt_raiserror(PLtsql_stmt_raiserror *stmt_raiserror) { - ListCell *l; + ListCell *l; printf("RAISERROR "); foreach(l, stmt_raiserror->params) @@ -634,7 +661,7 @@ dump_stmt_raiserror(PLtsql_stmt_raiserror *stmt_raiserror) void dump_stmt_throw(PLtsql_stmt_throw *stmt_throw) { - ListCell *l; + ListCell *l; if (stmt_throw->params == NIL) printf("THROW\n"); @@ -656,12 +683,14 @@ dump_stmt_usedb(PLtsql_stmt_usedb *stmt_usedb) printf("USE %s\n", stmt_usedb->db_name); } -void get_grantees_names(List *grantees, StringInfo grantees_names) -{ - for(int i = 0; i < list_length(grantees); i++) +void +get_grantees_names(List *grantees, StringInfo grantees_names) +{ + for (int i = 0; i < list_length(grantees); i++) { - char *grantee_name = (char *) list_nth(grantees, i); - if(i < list_length(grantees) - 1) + char *grantee_name = (char *) list_nth(grantees, i); + + if (i < list_length(grantees) - 1) appendStringInfo(grantees_names, "%s, ", grantee_name); else appendStringInfo(grantees_names, "%s", grantee_name); @@ -670,11 +699,12 @@ void get_grantees_names(List *grantees, StringInfo grantees_names) void dump_stmt_grantdb(PLtsql_stmt_grantdb *stmt_grantdb) -{ +{ StringInfoData grantees_names; + initStringInfo(&grantees_names); get_grantees_names(stmt_grantdb->grantees, &grantees_names); - if(stmt_grantdb->is_grant) + if (stmt_grantdb->is_grant) printf("GRANT CONNECT TO %s\n", grantees_names.data); else printf("REVOKE CONNECT FROM %s\n", grantees_names.data); @@ -684,25 +714,25 @@ dump_stmt_grantdb(PLtsql_stmt_grantdb *stmt_grantdb) void dump_stmt_insert_bulk(PLtsql_stmt_insert_bulk *stmt_insert_bulk) { - printf("INSERT BULK %s\n", stmt_insert_bulk->table_name); + printf("INSERT BULK %s\n", stmt_insert_bulk->table_name); } void dump_stmt_try_catch(PLtsql_stmt_try_catch *stmt_try_catch) { - printf("TRY BEGIN\n"); - dump_indent +=2; + printf("TRY BEGIN\n"); + dump_indent += 2; dump_stmt(stmt_try_catch->body); - dump_indent -=2; - dump_ind(); - printf("TRY END\n"); - dump_ind(); - printf("CATCH BEGIN\n"); - dump_indent +=2; + dump_indent -= 2; + dump_ind(); + printf("TRY END\n"); + dump_ind(); + printf("CATCH BEGIN\n"); + dump_indent += 2; dump_stmt(stmt_try_catch->handler); - dump_indent -=2; - dump_ind(); - printf("CATCH END\n"); + dump_indent -= 2; + dump_ind(); + printf("CATCH END\n"); } void @@ -727,95 +757,95 @@ dump_stmt_exec_batch(PLtsql_stmt_exec_batch *exec_batch) static void dump_stmt2(PLtsql_stmt *stmt) { - switch (stmt->cmd_type) - { - case PLTSQL_STMT_GOTO: - { - dump_stmt_goto((PLtsql_stmt_goto *) stmt); - break; - } - case PLTSQL_STMT_PRINT: - { - dump_stmt_print((PLtsql_stmt_print *) stmt); - break; - } - case PLTSQL_STMT_INIT: - { - dump_stmt_init((PLtsql_stmt_init *) stmt); - break; - } - case PLTSQL_STMT_QUERY_SET: - { - dump_stmt_query_set((PLtsql_stmt_query_set *) stmt); - break; - } - case PLTSQL_STMT_TRY_CATCH: - { - dump_stmt_try_catch((PLtsql_stmt_try_catch *) stmt); - break; - } - case PLTSQL_STMT_PUSH_RESULT: - { - dump_stmt_push_result((PLtsql_stmt_push_result *) stmt); - break; - } - case PLTSQL_STMT_EXEC: - { - dump_stmt_exec((PLtsql_stmt_exec *) stmt); - break; - } + switch (stmt->cmd_type) + { + case PLTSQL_STMT_GOTO: + { + dump_stmt_goto((PLtsql_stmt_goto *) stmt); + break; + } + case PLTSQL_STMT_PRINT: + { + dump_stmt_print((PLtsql_stmt_print *) stmt); + break; + } + case PLTSQL_STMT_INIT: + { + dump_stmt_init((PLtsql_stmt_init *) stmt); + break; + } + case PLTSQL_STMT_QUERY_SET: + { + dump_stmt_query_set((PLtsql_stmt_query_set *) stmt); + break; + } + case PLTSQL_STMT_TRY_CATCH: + { + dump_stmt_try_catch((PLtsql_stmt_try_catch *) stmt); + break; + } + case PLTSQL_STMT_PUSH_RESULT: + { + dump_stmt_push_result((PLtsql_stmt_push_result *) stmt); + break; + } + case PLTSQL_STMT_EXEC: + { + dump_stmt_exec((PLtsql_stmt_exec *) stmt); + break; + } case PLTSQL_STMT_EXEC_BATCH: - { - dump_stmt_exec_batch((PLtsql_stmt_exec_batch *) stmt); - break; - } + { + dump_stmt_exec_batch((PLtsql_stmt_exec_batch *) stmt); + break; + } case PLTSQL_STMT_DECL_TABLE: - { - printf("DECLARE TABLE"); - break; - } + { + printf("DECLARE TABLE"); + break; + } case PLTSQL_STMT_RETURN_TABLE: - { - dump_return_query((PLtsql_stmt_return_query *) stmt); - break; - } + { + dump_return_query((PLtsql_stmt_return_query *) stmt); + break; + } case PLTSQL_STMT_DEALLOCATE: - { - printf("DEALLOCATE"); - break; - } - case PLTSQL_STMT_LABEL: - { - dump_stmt_label((PLtsql_stmt_label *) stmt); - break; - } + { + printf("DEALLOCATE"); + break; + } + case PLTSQL_STMT_LABEL: + { + dump_stmt_label((PLtsql_stmt_label *) stmt); + break; + } case PLTSQL_STMT_RAISERROR: - { - dump_stmt_raiserror((PLtsql_stmt_raiserror *) stmt); - break; - } + { + dump_stmt_raiserror((PLtsql_stmt_raiserror *) stmt); + break; + } case PLTSQL_STMT_THROW: - { - dump_stmt_throw((PLtsql_stmt_throw *) stmt); - break; - } + { + dump_stmt_throw((PLtsql_stmt_throw *) stmt); + break; + } case PLTSQL_STMT_USEDB: - { - dump_stmt_usedb((PLtsql_stmt_usedb *) stmt); - break; - } + { + dump_stmt_usedb((PLtsql_stmt_usedb *) stmt); + break; + } case PLTSQL_STMT_GRANTDB: - { - dump_stmt_grantdb((PLtsql_stmt_grantdb *) stmt); + { + dump_stmt_grantdb((PLtsql_stmt_grantdb *) stmt); + break; + } + case PLTSQL_STMT_INSERT_BULK: + { + dump_stmt_insert_bulk((PLtsql_stmt_insert_bulk *) stmt); + break; + } + default: + elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type); break; - } - case PLTSQL_STMT_INSERT_BULK: - { - dump_stmt_insert_bulk((PLtsql_stmt_insert_bulk *) stmt); - break; - } - default: - elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type); - break; - } + } } diff --git a/contrib/babelfishpg_tsql/src/pl_funcs-2.h b/contrib/babelfishpg_tsql/src/pl_funcs-2.h index ede79e0d57..3f109a81d5 100644 --- a/contrib/babelfishpg_tsql/src/pl_funcs-2.h +++ b/contrib/babelfishpg_tsql/src/pl_funcs-2.h @@ -4,4 +4,4 @@ static void free_stmt2(PLtsql_stmt *stmt); static void dump_stmt2(PLtsql_stmt *stmt); -#endif /* PLFUNCS_2_H */ +#endif /* PLFUNCS_2_H */ diff --git a/contrib/babelfishpg_tsql/src/pl_funcs.c b/contrib/babelfishpg_tsql/src/pl_funcs.c index 1e3be12a3a..658d0b7143 100644 --- a/contrib/babelfishpg_tsql/src/pl_funcs.c +++ b/contrib/babelfishpg_tsql/src/pl_funcs.c @@ -132,8 +132,8 @@ pltsql_ns_additem(PLtsql_nsitem_type itemtype, int itemno, const char *name) */ PLtsql_nsitem * pltsql_ns_lookup(PLtsql_nsitem *ns_cur, bool localmode, - const char *name1, const char *name2, const char *name3, - int *names_used) + const char *name1, const char *name2, const char *name3, + int *names_used) { /* Outer loop iterates once per block level in the namespace chain */ while (ns_cur != NULL) @@ -295,7 +295,7 @@ pltsql_stmt_typename(PLtsql_stmt *stmt) case PLTSQL_STMT_SET: return "SET"; - /* TSQL-only statement types follow */ + /* TSQL-only statement types follow */ case PLTSQL_STMT_GOTO: return "GOTO"; case PLTSQL_STMT_PRINT: @@ -304,8 +304,8 @@ pltsql_stmt_typename(PLtsql_stmt *stmt) return "(init)"; case PLTSQL_STMT_QUERY_SET: return "SELECT-SET"; - case PLTSQL_STMT_TRY_CATCH: - return "TRY_CATCH"; + case PLTSQL_STMT_TRY_CATCH: + return "TRY_CATCH"; case PLTSQL_STMT_PUSH_RESULT: return "PUSH_RESULT"; case PLTSQL_STMT_EXEC: @@ -322,29 +322,29 @@ pltsql_stmt_typename(PLtsql_stmt *stmt) return "DEALLOCATE"; case PLTSQL_STMT_DECL_CURSOR: return "DECLARE CURSOR"; - case PLTSQL_STMT_LABEL: - return "LABEL"; + case PLTSQL_STMT_LABEL: + return "LABEL"; case PLTSQL_STMT_RAISERROR: return "RAISERROR"; case PLTSQL_STMT_THROW: return "THROW"; case PLTSQL_STMT_USEDB: return "USE"; - case PLTSQL_STMT_INSERT_BULK: - return "INSERT BULK"; + case PLTSQL_STMT_INSERT_BULK: + return "INSERT BULK"; case PLTSQL_STMT_SET_EXPLAIN_MODE: return "SET EXPLAIN MODE"; case PLTSQL_STMT_GRANTDB: return ((PLtsql_stmt_grantdb *) stmt)->is_grant ? "GRANT CONNECT TO" : "REVOKE CONNECT FROM"; - /* TSQL-only executable node */ - case PLTSQL_STMT_SAVE_CTX: - return "SAVE_CONTEXT"; - case PLTSQL_STMT_RESTORE_CTX_FULL: - return "RESTORE_CONTEXT_FULL"; - case PLTSQL_STMT_RESTORE_CTX_PARTIAL: - return "RESTORE_CONTEXT_PARTIAL"; - default: + /* TSQL-only executable node */ + case PLTSQL_STMT_SAVE_CTX: + return "SAVE_CONTEXT"; + case PLTSQL_STMT_RESTORE_CTX_FULL: + return "RESTORE_CONTEXT_FULL"; + case PLTSQL_STMT_RESTORE_CTX_PARTIAL: + return "RESTORE_CONTEXT_PARTIAL"; + default: return "Add try catch"; } @@ -436,7 +436,7 @@ free_stmt(PLtsql_stmt *stmt) { if (stmt == NULL) return; - + switch (stmt->cmd_type) { case PLTSQL_STMT_BLOCK: @@ -577,8 +577,8 @@ free_if(PLtsql_stmt_if *stmt) free_expr(elif->cond); free_stmts(elif->stmts); } - if (stmt->else_body) - free_stmt(stmt->else_body); + if (stmt->else_body) + free_stmt(stmt->else_body); } static void @@ -841,16 +841,17 @@ pltsql_free_function_memory(PLtsql_function *func) } func->ndatums = 0; - /* free exec codes - * It is called before free_block because exec_code shares same nodes with the tree. - * Shared nodes will be skipped and only nodes generated by codegen will be freed. - */ + /* + * free exec codes It is called before free_block because exec_code shares + * same nodes with the tree. Shared nodes will be skipped and only nodes + * generated by codegen will be freed. + */ - if (func->exec_codes) - { - free_exec_codes(func->exec_codes); - func->exec_codes = NULL; - } + if (func->exec_codes) + { + free_exec_codes(func->exec_codes); + func->exec_codes = NULL; + } /* Release plans in statement tree */ if (func->action) @@ -1010,7 +1011,7 @@ dump_stmt(PLtsql_stmt *stmt) dump_set((PLtsql_stmt_set *) stmt); break; default: - dump_stmt2(stmt); + dump_stmt2(stmt); break; } } @@ -1800,7 +1801,7 @@ pltsql_dumptree(PLtsql_function *func) printf("\n"); break; case PLTSQL_DTYPE_TBL: - printf("TABLE VARIABLE %s\n", ((PLtsql_tbl *)d)->refname); + printf("TABLE VARIABLE %s\n", ((PLtsql_tbl *) d)->refname); if (((PLtsql_tbl *) d)->tblname) { printf(" UNDERLYING TABLE %s\n", diff --git a/contrib/babelfishpg_tsql/src/pl_handler.c b/contrib/babelfishpg_tsql/src/pl_handler.c index 018666a146..7bd9d6cb73 100644 --- a/contrib/babelfishpg_tsql/src/pl_handler.c +++ b/contrib/babelfishpg_tsql/src/pl_handler.c @@ -47,7 +47,7 @@ #include "parser/parse_type.h" #include "parser/parse_utilcmd.h" #include "parser/scansup.h" -#include "pgstat.h" /* for pgstat related activities */ +#include "pgstat.h" /* for pgstat related activities */ #include "tcop/pquery.h" #include "tcop/tcopprot.h" #include "tcop/utility.h" @@ -102,43 +102,43 @@ extern Datum init_tsql_cursor_hash_tab(PG_FUNCTION_ARGS); extern PLtsql_execstate *get_current_tsql_estate(void); extern PLtsql_execstate *get_outermost_tsql_estate(int *nestlevel); extern void pre_check_trigger_schema(List *object, bool missing_ok); -static void get_language_procs(const char *langname, Oid *compiler, Oid *validator); +static void get_language_procs(const char *langname, Oid *compiler, Oid *validator); static void get_func_language_oids(Oid *lang_handler, Oid *lang_validator); extern bool pltsql_suppress_string_truncation_error(); -static Oid bbf_table_var_lookup(const char *relname, Oid relnamespace); +static Oid bbf_table_var_lookup(const char *relname, Oid relnamespace); extern void assign_object_access_hook_drop_relation(void); extern void uninstall_object_access_hook_drop_relation(void); -static Oid pltsql_seq_type_map(Oid typid); -bool canCommitTransaction(void); +static Oid pltsql_seq_type_map(Oid typid); +bool canCommitTransaction(void); extern void assign_tablecmds_hook(void); static void bbf_ProcessUtility(PlannedStmt *pstmt, - const char *queryString, - bool readOnlyTree, - ProcessUtilityContext context, - ParamListInfo params, - QueryEnvironment *queryEnv, - DestReceiver *dest, - QueryCompletion *qc); + const char *queryString, + bool readOnlyTree, + ProcessUtilityContext context, + ParamListInfo params, + QueryEnvironment *queryEnv, + DestReceiver *dest, + QueryCompletion *qc); static void set_pgtype_byval(List *name, bool byval); static bool pltsql_truncate_identifier(char *ident, int len, bool warn); static Name pltsql_cstr_to_name(char *s, int len); extern void pltsql_add_guc_plan(CachedPlanSource *plansource); extern bool pltsql_check_guc_plan(CachedPlanSource *plansource); -bool pltsql_function_as_checker(const char *lang, List *as, char **prosrc_str_p, char **probin_str_p); -extern void pltsql_function_probin_writer(CreateFunctionStmt *stmt, Oid languageOid, char** probin_str_p); +bool pltsql_function_as_checker(const char *lang, List *as, char **prosrc_str_p, char **probin_str_p); +extern void pltsql_function_probin_writer(CreateFunctionStmt *stmt, Oid languageOid, char **probin_str_p); extern void pltsql_function_probin_reader(ParseState *pstate, List *fargs, Oid *actual_arg_types, Oid *declared_arg_types, Oid funcid); static void check_nullable_identity_constraint(RangeVar *relation, ColumnDef *column); static bool is_identity_constraint(ColumnDef *column); static bool has_unique_nullable_constraint(ColumnDef *column); static bool is_nullable_constraint(Constraint *cst, Oid rel_oid); static bool is_nullable_index(IndexStmt *stmt); -extern PLtsql_function * find_cached_batch(int handle); +extern PLtsql_function *find_cached_batch(int handle); extern void apply_post_compile_actions(PLtsql_function *func, InlineCodeBlockArgs *args); -Datum sp_prepare(PG_FUNCTION_ARGS); -Datum sp_unprepare(PG_FUNCTION_ARGS); +Datum sp_prepare(PG_FUNCTION_ARGS); +Datum sp_unprepare(PG_FUNCTION_ARGS); static List *transformReturningList(ParseState *pstate, List *returningList); -extern char * construct_unique_index_name(char *index_name, char *relation_name); -extern int CurrentLineNumber; +extern char *construct_unique_index_name(char *index_name, char *relation_name); +extern int CurrentLineNumber; static non_tsql_proc_entry_hook_type prev_non_tsql_proc_entry_hook = NULL; static void pltsql_non_tsql_proc_entry(int proc_count, int sys_func_count); static bool get_attnotnull(Oid relid, AttrNumber attnum); @@ -148,26 +148,28 @@ static void validate_rowversion_column_constraints(ColumnDef *column); static void validate_rowversion_table_constraint(Constraint *c, char *rowversion_column_name); static Constraint *get_rowversion_default_constraint(TypeName *typname); static void revoke_type_permission_from_public(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, - ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc, List *type_name); + ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc, List *type_name); static void set_current_query_is_create_tbl_check_constraint(Node *expr); -static void validateUserAndRole(char* name); - -extern bool pltsql_ansi_defaults; -extern bool pltsql_quoted_identifier; -extern bool pltsql_concat_null_yields_null; -extern bool pltsql_ansi_nulls; -extern bool pltsql_ansi_null_dflt_on; -extern bool pltsql_ansi_padding; -extern bool pltsql_ansi_warnings; -extern bool pltsql_arithabort; -extern int pltsql_datefirst; -extern char* pltsql_language; -extern int pltsql_lock_timeout; +static void validateUserAndRole(char *name); + +extern bool pltsql_ansi_defaults; +extern bool pltsql_quoted_identifier; +extern bool pltsql_concat_null_yields_null; +extern bool pltsql_ansi_nulls; +extern bool pltsql_ansi_null_dflt_on; +extern bool pltsql_ansi_padding; +extern bool pltsql_ansi_warnings; +extern bool pltsql_arithabort; +extern int pltsql_datefirst; +extern char *pltsql_language; +extern int pltsql_lock_timeout; PG_FUNCTION_INFO_V1(pltsql_inline_handler); -static Oid lang_handler_oid = InvalidOid; /* Oid of language handler function */ -static Oid lang_validator_oid = InvalidOid; /* Oid of language validator function */ +static Oid lang_handler_oid = InvalidOid; /* Oid of language handler + * function */ +static Oid lang_validator_oid = InvalidOid; /* Oid of language validator + * function */ PG_MODULE_MAGIC; @@ -190,37 +192,37 @@ static const struct config_enum_entry schema_mapping_options[] = { {NULL, 0, false} }; -Oid procid_var = InvalidOid; +Oid procid_var = InvalidOid; int pltsql_variable_conflict = PLTSQL_RESOLVE_ERROR; -int pltsql_schema_mapping; +int pltsql_schema_mapping; int pltsql_extra_errors; bool pltsql_debug_parser = false; -char *identity_insert_string; +char *identity_insert_string; bool output_update_transformation = false; bool output_into_insert_transformation = false; -char *update_delete_target_alias = NULL; +char *update_delete_target_alias = NULL; int pltsql_trigger_depth = 0; -PLExecStateCallStack *exec_state_call_stack = NULL; -int text_size; -Portal pltsql_snapshot_portal = NULL; -int pltsql_non_tsql_proc_entry_count = 0; -int pltsql_sys_func_entry_count = 0; -static int PltsqlGUCNestLevel = 0; -static bool pltsql_guc_dirty; +PLExecStateCallStack *exec_state_call_stack = NULL; +int text_size; +Portal pltsql_snapshot_portal = NULL; +int pltsql_non_tsql_proc_entry_count = 0; +int pltsql_sys_func_entry_count = 0; +static int PltsqlGUCNestLevel = 0; +static bool pltsql_guc_dirty; static guc_push_old_value_hook_type prev_guc_push_old_value_hook = NULL; static validate_set_config_function_hook_type prev_validate_set_config_function_hook = NULL; static void pltsql_guc_push_old_value(struct config_generic *gconf, GucAction action); -bool current_query_is_create_tbl_check_constraint = false; +bool current_query_is_create_tbl_check_constraint = false; /* Configurations */ -bool pltsql_trace_tree = false; -bool pltsql_trace_exec_codes = false; -bool pltsql_trace_exec_counts = false; -bool pltsql_trace_exec_time = false; +bool pltsql_trace_tree = false; +bool pltsql_trace_exec_codes = false; +bool pltsql_trace_exec_counts = false; +bool pltsql_trace_exec_time = false; tsql_identity_insert_fields tsql_identity_insert = {false, InvalidOid, InvalidOid}; @@ -258,245 +260,255 @@ set_procid(Oid oid) static void assign_identity_insert(const char *newval, void *extra) { - if (strcmp(newval, "") != 0) - { - List *elemlist; - Oid rel_oid; - Oid schema_oid; - char *option_flag; - char *rel_name; - char *schema_name = NULL; - char *input_string = pstrdup(newval); - char *id_insert_rel_name = NULL; - char *id_insert_schema_name = NULL; - char *cur_db_name; - - cur_db_name = get_cur_db_name(); - - /* Check if IDENTITY_INSERT is valid and get names. If not, reset it. */ - if (tsql_identity_insert.valid) - { - id_insert_rel_name = get_rel_name(tsql_identity_insert.rel_oid); - - if (!id_insert_rel_name) - tsql_identity_insert.valid = false; - else - id_insert_schema_name = get_namespace_name(tsql_identity_insert.schema_oid); - } - - /* Parse user input string into list of identifiers */ - if (!SplitGUCList(input_string, '.', &elemlist)) - { - /* syntax error in list */ - GUC_check_errdetail("List syntax is invalid."); - pfree(input_string); - list_free(elemlist); - return; - } - - option_flag = (char *) linitial(elemlist); - rel_name = (char *) lsecond(elemlist); - - /* Check the user provided schema value */ - if (list_length(elemlist) >= 3) - { - schema_name = (char *) lthird(elemlist); - - if (cur_db_name) - schema_name = get_physical_schema_name(cur_db_name, - schema_name); - - schema_oid = LookupExplicitNamespace(schema_name, true); - if (!OidIsValid(schema_oid)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_SCHEMA), - errmsg("schema \"%s\" does not exist", - schema_name))); - - rel_oid = get_relname_relid(rel_name, schema_oid); - if (!OidIsValid(rel_oid)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_TABLE), - errmsg("relation \"%s\" does not exist", - rel_name))); - } - - /* Check the catalog name then ignore it */ - if (list_length(elemlist) == 4) - { - char *catalog_name = (char *) lfourth(elemlist); - if (strcmp(catalog_name, get_database_name(MyDatabaseId)) != 0) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cross-database references are not implemented: \"%s.%s.%s\"", - catalog_name, schema_name, rel_name))); - } - - /* If schema is not provided, find it from the search path. */ - if (!schema_name) - { - /* If the relation exists, retrieve the relation Oid from the - * first schema that contains it. - */ - rel_oid = RelnameGetRelid(rel_name); - if (!OidIsValid(rel_oid)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_TABLE), - errmsg("relation \"%s\" does not exist", - rel_name))); - - schema_oid = get_rel_namespace(rel_oid); - schema_name = get_namespace_name(schema_oid); - } - - /* Process assignment logic */ - if (strcmp(option_flag, "on") == 0) - { - if (!tsql_identity_insert.valid) - { - /* Check if relation has identity property */ - Relation rel; - TupleDesc tupdesc; - int attnum; - bool has_ident = false; - - rel = RelationIdGetRelation(rel_oid); - tupdesc = RelationGetDescr(rel); - - for (attnum = 0; attnum < tupdesc->natts; attnum++) - { - Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum); - if (attr->attidentity) - { - has_ident = true; - break; - } - } - - RelationClose(rel); - - if (!has_ident) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_COLUMN), - errmsg("Table '%s.%s' does not have the identity property. Cannot perform SET operation.", - schema_name, rel_name))); - - /* Set IDENTITY_INSERT to the user value */ - tsql_identity_insert.rel_oid = rel_oid; - tsql_identity_insert.schema_oid = schema_oid; - tsql_identity_insert.valid = true; - } - else if (rel_oid != tsql_identity_insert.rel_oid) - { - /* IDENTITY_INSERT is already on and tables do not match */ - ereport(ERROR, - (errcode(ERRCODE_RESTRICT_VIOLATION), - errmsg("IDENTITY_INSERT is already ON for table \'%s.%s.%s\'", - get_database_name(MyDatabaseId), - id_insert_schema_name, - id_insert_rel_name))); - } - /* IDENTITY_INSERT is already set to the table. Keep the value */ - } - else if (strcmp(option_flag, "off") == 0) - { - if (rel_oid == tsql_identity_insert.rel_oid) - { - /* IDENTITY_INSERT is currently set and tables match. Set to off */ - tsql_identity_insert.valid = false; - } - /* User sets to off and already off or different table. Keep the value */ - } - else - { - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("unknown option value"))); - } + if (strcmp(newval, "") != 0) + { + List *elemlist; + Oid rel_oid; + Oid schema_oid; + char *option_flag; + char *rel_name; + char *schema_name = NULL; + char *input_string = pstrdup(newval); + char *id_insert_rel_name = NULL; + char *id_insert_schema_name = NULL; + char *cur_db_name; + + cur_db_name = get_cur_db_name(); + + /* Check if IDENTITY_INSERT is valid and get names. If not, reset it. */ + if (tsql_identity_insert.valid) + { + id_insert_rel_name = get_rel_name(tsql_identity_insert.rel_oid); + + if (!id_insert_rel_name) + tsql_identity_insert.valid = false; + else + id_insert_schema_name = get_namespace_name(tsql_identity_insert.schema_oid); + } + + /* Parse user input string into list of identifiers */ + if (!SplitGUCList(input_string, '.', &elemlist)) + { + /* syntax error in list */ + GUC_check_errdetail("List syntax is invalid."); + pfree(input_string); + list_free(elemlist); + return; + } + + option_flag = (char *) linitial(elemlist); + rel_name = (char *) lsecond(elemlist); + + /* Check the user provided schema value */ + if (list_length(elemlist) >= 3) + { + schema_name = (char *) lthird(elemlist); + + if (cur_db_name) + schema_name = get_physical_schema_name(cur_db_name, + schema_name); + + schema_oid = LookupExplicitNamespace(schema_name, true); + if (!OidIsValid(schema_oid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_SCHEMA), + errmsg("schema \"%s\" does not exist", + schema_name))); + + rel_oid = get_relname_relid(rel_name, schema_oid); + if (!OidIsValid(rel_oid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_TABLE), + errmsg("relation \"%s\" does not exist", + rel_name))); + } + + /* Check the catalog name then ignore it */ + if (list_length(elemlist) == 4) + { + char *catalog_name = (char *) lfourth(elemlist); + + if (strcmp(catalog_name, get_database_name(MyDatabaseId)) != 0) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cross-database references are not implemented: \"%s.%s.%s\"", + catalog_name, schema_name, rel_name))); + } + + /* If schema is not provided, find it from the search path. */ + if (!schema_name) + { + /* + * If the relation exists, retrieve the relation Oid from the + * first schema that contains it. + */ + rel_oid = RelnameGetRelid(rel_name); + if (!OidIsValid(rel_oid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_TABLE), + errmsg("relation \"%s\" does not exist", + rel_name))); + + schema_oid = get_rel_namespace(rel_oid); + schema_name = get_namespace_name(schema_oid); + } + + /* Process assignment logic */ + if (strcmp(option_flag, "on") == 0) + { + if (!tsql_identity_insert.valid) + { + /* Check if relation has identity property */ + Relation rel; + TupleDesc tupdesc; + int attnum; + bool has_ident = false; + + rel = RelationIdGetRelation(rel_oid); + tupdesc = RelationGetDescr(rel); + + for (attnum = 0; attnum < tupdesc->natts; attnum++) + { + Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum); + + if (attr->attidentity) + { + has_ident = true; + break; + } + } + + RelationClose(rel); + + if (!has_ident) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("Table '%s.%s' does not have the identity property. Cannot perform SET operation.", + schema_name, rel_name))); + + /* Set IDENTITY_INSERT to the user value */ + tsql_identity_insert.rel_oid = rel_oid; + tsql_identity_insert.schema_oid = schema_oid; + tsql_identity_insert.valid = true; + } + else if (rel_oid != tsql_identity_insert.rel_oid) + { + /* IDENTITY_INSERT is already on and tables do not match */ + ereport(ERROR, + (errcode(ERRCODE_RESTRICT_VIOLATION), + errmsg("IDENTITY_INSERT is already ON for table \'%s.%s.%s\'", + get_database_name(MyDatabaseId), + id_insert_schema_name, + id_insert_rel_name))); + } + /* IDENTITY_INSERT is already set to the table. Keep the value */ + } + else if (strcmp(option_flag, "off") == 0) + { + if (rel_oid == tsql_identity_insert.rel_oid) + { + /* + * IDENTITY_INSERT is currently set and tables match. Set to + * off + */ + tsql_identity_insert.valid = false; + } - /* Clean up */ - pfree(input_string); - list_free(elemlist); - } + /* + * User sets to off and already off or different table. Keep the + * value + */ + } + else + { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("unknown option value"))); + } + + /* Clean up */ + pfree(input_string); + list_free(elemlist); + } } static void assign_textsize(int newval, void *extra) { if (pltsql_protocol_plugin_ptr && *pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->set_guc_stat_var) - (*pltsql_protocol_plugin_ptr)->set_guc_stat_var("babelfishpg_tsql.textsize", false, NULL, newval); + (*pltsql_protocol_plugin_ptr)->set_guc_stat_var("babelfishpg_tsql.textsize", false, NULL, newval); } static void pltsql_pre_parse_analyze(ParseState *pstate, RawStmt *parseTree) { if (prev_pre_parse_analyze_hook) - prev_pre_parse_analyze_hook(pstate, parseTree); + prev_pre_parse_analyze_hook(pstate, parseTree); switch (parseTree->stmt->type) { case T_InsertStmt: - { - InsertStmt *stmt = (InsertStmt *) parseTree->stmt; - SelectStmt *selectStmt = (SelectStmt *) stmt->selectStmt; - A_Const *value; - Oid relid; - ListCell *lc; - - if (!babelfish_dump_restore || IsBinaryUpgrade) - break; + { + InsertStmt *stmt = (InsertStmt *) parseTree->stmt; + SelectStmt *selectStmt = (SelectStmt *) stmt->selectStmt; + A_Const *value; + Oid relid; + ListCell *lc; - relid = RangeVarGetRelid(stmt->relation, NoLock, false); + if (!babelfish_dump_restore || IsBinaryUpgrade) + break; - /* - * Insert new dbid column value in babelfish catalog if dump did - * not provide it. - */ - if (relid == sysdatabases_oid || - relid == namespace_ext_oid || - relid == bbf_view_def_oid) - { - int16 dbid = 0; - ResTarget *dbidCol; - bool found = false; + relid = RangeVarGetRelid(stmt->relation, NoLock, false); - /* Skip if dbid column already exists */ - foreach(lc, stmt->cols) + /* + * Insert new dbid column value in babelfish catalog if dump + * did not provide it. + */ + if (relid == sysdatabases_oid || + relid == namespace_ext_oid || + relid == bbf_view_def_oid) { - ResTarget *col = (ResTarget *) lfirst(lc); + int16 dbid = 0; + ResTarget *dbidCol; + bool found = false; - if (strcasecmp(col->name, "dbid") == 0) - found = true; - } - if (found) - break; + /* Skip if dbid column already exists */ + foreach(lc, stmt->cols) + { + ResTarget *col = (ResTarget *) lfirst(lc); + + if (strcasecmp(col->name, "dbid") == 0) + found = true; + } + if (found) + break; - dbid = getDbidForLogicalDbRestore(relid); + dbid = getDbidForLogicalDbRestore(relid); - /* const value node to store into values clause */ - value = makeNode(A_Const); - value->val.ival.type = T_Integer; - value->val.ival.ival = dbid; - value->location = -1; + /* const value node to store into values clause */ + value = makeNode(A_Const); + value->val.ival.type = T_Integer; + value->val.ival.ival = dbid; + value->location = -1; - /* dbid column to store into InsertStmt's target list */ - dbidCol = makeNode(ResTarget); - dbidCol->name = "dbid"; - dbidCol->name_location = -1; - dbidCol->indirection = NIL; - dbidCol->val = NULL; - dbidCol->location = -1; - stmt->cols = lappend(stmt->cols, dbidCol); + /* dbid column to store into InsertStmt's target list */ + dbidCol = makeNode(ResTarget); + dbidCol->name = "dbid"; + dbidCol->name_location = -1; + dbidCol->indirection = NIL; + dbidCol->val = NULL; + dbidCol->location = -1; + stmt->cols = lappend(stmt->cols, dbidCol); - foreach(lc, selectStmt->valuesLists) - { - List *sublist = (List *) lfirst(lc); + foreach(lc, selectStmt->valuesLists) + { + List *sublist = (List *) lfirst(lc); - sublist = lappend(sublist, value); + sublist = lappend(sublist, value); + } } + break; } - break; - } default: break; } @@ -504,30 +516,37 @@ pltsql_pre_parse_analyze(ParseState *pstate, RawStmt *parseTree) if (sql_dialect != SQL_DIALECT_TSQL) return; - if (parseTree->stmt->type == T_CreateFunctionStmt ){ - ListCell *option; + if (parseTree->stmt->type == T_CreateFunctionStmt) + { + ListCell *option; CreateTrigStmt *trigStmt; CreateFunctionStmt *funcStmt = (CreateFunctionStmt *) parseTree->stmt; - char* trig_schema; - foreach (option, ((CreateFunctionStmt *) parseTree->stmt)->options){ - DefElem *defel = (DefElem *) lfirst(option); + char *trig_schema; + + foreach(option, ((CreateFunctionStmt *) parseTree->stmt)->options) + { + DefElem *defel = (DefElem *) lfirst(option); + if (strcmp(defel->defname, "trigStmt") == 0) { trigStmt = (CreateTrigStmt *) defel->arg; - if (trigStmt->args != NIL){ - trig_schema = ((String *)list_nth(((CreateTrigStmt *) trigStmt)->args,0))->sval; - if ((trigStmt->relation->schemaname != NULL && strcasecmp(trig_schema, trigStmt->relation->schemaname)!=0) - || trigStmt->relation->schemaname == NULL){ - ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("Cannot create trigger '%s.%s' because its schema is different from the schema of the target table or view.", - trig_schema , trigStmt->trigname))); + if (trigStmt->args != NIL) + { + trig_schema = ((String *) list_nth(((CreateTrigStmt *) trigStmt)->args, 0))->sval; + if ((trigStmt->relation->schemaname != NULL && strcasecmp(trig_schema, trigStmt->relation->schemaname) != 0) + || trigStmt->relation->schemaname == NULL) + { + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("Cannot create trigger '%s.%s' because its schema is different from the schema of the target table or view.", + trig_schema, trigStmt->trigname))); } trigStmt->args = NIL; } else { Assert(list_length(funcStmt->funcname) == 1); + /* * Add schemaname to trigger's function name. */ @@ -540,15 +559,20 @@ pltsql_pre_parse_analyze(ParseState *pstate, RawStmt *parseTree) } } - if(parseTree->stmt->type == T_DropStmt){ - DropStmt *dropStmt; + if (parseTree->stmt->type == T_DropStmt) + { + DropStmt *dropStmt; + dropStmt = (DropStmt *) parseTree->stmt; - if (dropStmt->removeType == OBJECT_TRIGGER){ + if (dropStmt->removeType == OBJECT_TRIGGER) + { ListCell *cell1; - // in case we have multi triggers in one stmt + + /* in case we have multi triggers in one stmt */ foreach(cell1, dropStmt->objects) { - Node *object = lfirst(cell1); + Node *object = lfirst(cell1); + pre_check_trigger_schema(castNode(List, object), dropStmt->missing_ok); } } @@ -560,155 +584,160 @@ pltsql_pre_parse_analyze(ParseState *pstate, RawStmt *parseTree) switch (parseTree->stmt->type) { case T_CreateStmt: - { - CreateStmt *create_stmt = (CreateStmt *)parseTree->stmt; - ListCell *elements; + { + CreateStmt *create_stmt = (CreateStmt *) parseTree->stmt; + ListCell *elements; - /* We should not allow "create if not exists" in TSQL semantics. - * The only reason for allowing temp tables for now is that they are - * used internally to declare table type. Please see - * exec_stmt_decl_table(). - */ - if (create_stmt->if_not_exists && - create_stmt->relation->relpersistence != RELPERSISTENCE_TEMP) { - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("Incorrect syntax near '%s'", create_stmt->relation->relname))); + /* + * We should not allow "create if not exists" in TSQL + * semantics. The only reason for allowing temp tables for now + * is that they are used internally to declare table type. + * Please see exec_stmt_decl_table(). + */ + if (create_stmt->if_not_exists && + create_stmt->relation->relpersistence != RELPERSISTENCE_TEMP) + { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Incorrect syntax near '%s'", create_stmt->relation->relname))); - } + } - /* SYSNAME datatype is default not null */ - foreach(elements, create_stmt->tableElts) - { - Node *element = lfirst(elements); - ColumnDef *coldef; + /* SYSNAME datatype is default not null */ + foreach(elements, create_stmt->tableElts) + { + Node *element = lfirst(elements); + ColumnDef *coldef; - if (nodeTag(element) != T_ColumnDef) - continue; + if (nodeTag(element) != T_ColumnDef) + continue; - coldef = castNode(ColumnDef, element); + coldef = castNode(ColumnDef, element); - if (!is_sysname_column(coldef)) - continue; + if (!is_sysname_column(coldef)) + continue; - /* - * If the SYSNAME column is not explicitly defined as NULL, - * take it as not NULL - */ - if (!have_null_constr(coldef->constraints)) - { - Constraint *c = makeNode(Constraint); - c->contype = CONSTR_NOTNULL; - c->location = -1; - coldef->constraints = lappend(coldef->constraints, c); + /* + * If the SYSNAME column is not explicitly defined as + * NULL, take it as not NULL + */ + if (!have_null_constr(coldef->constraints)) + { + Constraint *c = makeNode(Constraint); + + c->contype = CONSTR_NOTNULL; + c->location = -1; + coldef->constraints = lappend(coldef->constraints, c); + } } + break; } - break; - } case T_AlterTableStmt: - { - AlterTableStmt *atstmt = (AlterTableStmt *) parseTree->stmt; - ListCell *lc; - - foreach (lc, atstmt->cmds) { - AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lc); + AlterTableStmt *atstmt = (AlterTableStmt *) parseTree->stmt; + ListCell *lc; - switch (cmd->subtype) + foreach(lc, atstmt->cmds) { - case AT_AddColumn: + AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lc); + + switch (cmd->subtype) { - /* SYSNAME datatype is default not null */ - ColumnDef *coldef = castNode(ColumnDef, cmd->def); + case AT_AddColumn: + { + /* SYSNAME datatype is default not null */ + ColumnDef *coldef = castNode(ColumnDef, cmd->def); - if (!is_sysname_column(coldef)) - continue; + if (!is_sysname_column(coldef)) + continue; - /* - * If the SYSNAME column is not explicitly defined as NULL, - * take it as not NULL - */ - if (!have_null_constr(coldef->constraints)) - { - Constraint *c = makeNode(Constraint); - c->contype = CONSTR_NOTNULL; - c->location = -1; - coldef->constraints = lappend(coldef->constraints, c); - } - break; + /* + * If the SYSNAME column is not explicitly + * defined as NULL, take it as not NULL + */ + if (!have_null_constr(coldef->constraints)) + { + Constraint *c = makeNode(Constraint); + + c->contype = CONSTR_NOTNULL; + c->location = -1; + coldef->constraints = lappend(coldef->constraints, c); + } + break; + } + + /* + * TODO: After ALTER TABLE ALTER COLUMN [NOT] NULL + * is supported, we should add same SYSNAME check + * code for ALTER TABLE ALTER COLUMN + */ + default: + break; } - /* - * TODO: After ALTER TABLE ALTER COLUMN [NOT] NULL is - * supported, we should add same SYSNAME check code for - * ALTER TABLE ALTER COLUMN - */ - default: - break; } + break; } - break; - } case T_GrantStmt: - { - /* detect object type */ - GrantStmt *grant = (GrantStmt *) parseTree->stmt; - ListCell *cell; - List *plan_name = NIL; - ObjectWithArgs *func = NULL; - - Assert(list_length(grant->objects) == 1); - foreach(cell, grant->objects) { - RangeVar *rv = (RangeVar *) lfirst(cell); - char *schema = rv->schemaname; /* this is physical name */ - char *obj = rv->relname; - Oid func_oid; + /* detect object type */ + GrantStmt *grant = (GrantStmt *) parseTree->stmt; + ListCell *cell; + List *plan_name = NIL; + ObjectWithArgs *func = NULL; + + Assert(list_length(grant->objects) == 1); + foreach(cell, grant->objects) + { + RangeVar *rv = (RangeVar *) lfirst(cell); + char *schema = rv->schemaname; /* this is physical name */ + char *obj = rv->relname; + Oid func_oid; - /* table, sequence, view, materialized view */ - /* don't distinguish table sequence here */ - if (RangeVarGetRelid(rv, NoLock, true) != InvalidOid) - break; /* do nothing */ + /* table, sequence, view, materialized view */ + /* don't distinguish table sequence here */ + if (RangeVarGetRelid(rv, NoLock, true) != InvalidOid) + break; /* do nothing */ - if (schema) - plan_name = list_make2(makeString(schema), makeString(obj)); - else - plan_name = list_make1(makeString(obj)); + if (schema) + plan_name = list_make2(makeString(schema), makeString(obj)); + else + plan_name = list_make1(makeString(obj)); - func = makeNode(ObjectWithArgs); - func->objname = plan_name; - func->args_unspecified = true; + func = makeNode(ObjectWithArgs); + func->objname = plan_name; + func->args_unspecified = true; - /* function, procedure */ - func_oid = LookupFuncWithArgs(OBJECT_ROUTINE, func, true); - if (func_oid != InvalidOid) - { - char kind = get_func_prokind(func_oid); + /* function, procedure */ + func_oid = LookupFuncWithArgs(OBJECT_ROUTINE, func, true); + if (func_oid != InvalidOid) + { + char kind = get_func_prokind(func_oid); - if (kind == PROKIND_PROCEDURE) - grant->objtype = OBJECT_PROCEDURE; - else - grant->objtype = OBJECT_FUNCTION; + if (kind == PROKIND_PROCEDURE) + grant->objtype = OBJECT_PROCEDURE; + else + grant->objtype = OBJECT_FUNCTION; - break; - } + break; + } - /* type */ - if (LookupTypeNameOid(NULL, makeTypeNameFromNameList(plan_name), true) != InvalidOid) - { - grant->objtype = OBJECT_TYPE; - break; + /* type */ + if (LookupTypeNameOid(NULL, makeTypeNameFromNameList(plan_name), true) != InvalidOid) + { + grant->objtype = OBJECT_TYPE; + break; + } } - } - /* Adjust datatype structre if needed */ - if (grant->objtype == OBJECT_PROCEDURE || grant->objtype == OBJECT_FUNCTION) - grant->objects = list_make1(func); - else if (grant->objtype == OBJECT_TYPE) - grant->objects = list_make1(plan_name); + /* Adjust datatype structre if needed */ + if (grant->objtype == OBJECT_PROCEDURE || grant->objtype == OBJECT_FUNCTION) + grant->objects = list_make1(func); + else if (grant->objtype == OBJECT_TYPE) + grant->objects = list_make1(plan_name); - break; - } + break; + } default: break; } @@ -720,13 +749,13 @@ pltsql_pre_parse_analyze(ParseState *pstate, RawStmt *parseTree) static inline void pltsql_set_nulls_first(Query *query) { - ListCell *lc = NULL; - Node *node = NULL; + ListCell *lc = NULL; + Node *node = NULL; SortGroupClause *sgc = NULL; - char *opname = NULL; + char *opname = NULL; RangeTblEntry *rte = NULL; - // check subqueries + /* check subqueries */ foreach(lc, query->rtable) { node = lfirst(lc); @@ -763,24 +792,24 @@ static void pltsql_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate) { if (prev_post_parse_analyze_hook) - prev_post_parse_analyze_hook(pstate, query, jstate); + prev_post_parse_analyze_hook(pstate, query, jstate); - if (query->commandType == CMD_UTILITY && nodeTag((Node*)(query->utilityStmt)) == T_CreateStmt) + if (query->commandType == CMD_UTILITY && nodeTag((Node *) (query->utilityStmt)) == T_CreateStmt) set_current_query_is_create_tbl_check_constraint(query->utilityStmt); if (sql_dialect != SQL_DIALECT_TSQL) return; if (query->commandType == CMD_INSERT) { - ListCell *lc; - bool has_ident = false; + ListCell *lc; + bool has_ident = false; /* Loop through column attribute list */ - foreach (lc, query->targetList) + foreach(lc, query->targetList) { TargetEntry *tle = (TargetEntry *) lfirst(lc); - TupleDesc tupdesc = RelationGetDescr(pstate->p_target_relation); - int attr_num = tle->resno - 1; + TupleDesc tupdesc = RelationGetDescr(pstate->p_target_relation); + int attr_num = tle->resno - 1; Form_pg_attribute attr; attr = TupleDescAttr(tupdesc, attr_num); @@ -791,8 +820,8 @@ pltsql_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate) has_ident = true; } - /*Disallow insert into a ROWVERSION column */ - if ((*common_utility_plugin_ptr->is_tsql_rowversion_or_timestamp_datatype)(attr->atttypid)) + /* Disallow insert into a ROWVERSION column */ + if ((*common_utility_plugin_ptr->is_tsql_rowversion_or_timestamp_datatype) (attr->atttypid)) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), @@ -803,15 +832,15 @@ pltsql_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate) /* Set to override value if IDENTITY_INSERT */ if (tsql_identity_insert.valid) { - Oid schema_oid = RelationGetNamespace(pstate->p_target_relation); - char *rel_name = RelationGetRelationName(pstate->p_target_relation); - Oid rel_oid = get_relname_relid(rel_name, schema_oid); + Oid schema_oid = RelationGetNamespace(pstate->p_target_relation); + char *rel_name = RelationGetRelationName(pstate->p_target_relation); + Oid rel_oid = get_relname_relid(rel_name, schema_oid); if (rel_oid == tsql_identity_insert.rel_oid) { - ColumnRef *n; - ResTarget *rt; - List *returningList; + ColumnRef *n; + ResTarget *rt; + List *returningList; if (!has_ident) ereport(ERROR, @@ -835,7 +864,7 @@ pltsql_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate) pstate->p_namespace = NIL; addNSItemToQuery(pstate, pstate->p_target_nsitem, false, true, true); query->returningList = transformReturningList(pstate, - returningList); + returningList); } else { @@ -847,7 +876,7 @@ pltsql_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate) } else if (query->commandType == CMD_UTILITY) { - Node *parsetree = query->utilityStmt; + Node *parsetree = query->utilityStmt; switch (nodeTag(parsetree)) { @@ -857,7 +886,7 @@ pltsql_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate) ListCell *elements; bool seen_identity = false; bool seen_rowversion = false; - char *rowversion_column_name = NULL; + char *rowversion_column_name = NULL; foreach(elements, stmt->tableElts) { @@ -881,12 +910,12 @@ pltsql_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Nullable UNIQUE constraint is not supported. Please use babelfishpg_tsql.escape_hatch_unique_constraint to ignore " - "or add a NOT NULL constraint"))); + errmsg("Nullable UNIQUE constraint is not supported. Please use babelfishpg_tsql.escape_hatch_unique_constraint to ignore " + "or add a NOT NULL constraint"))); } if (is_rowversion_column(pstate, (ColumnDef *) element)) { - ColumnDef *def = (ColumnDef *) element; + ColumnDef *def = (ColumnDef *) element; if (seen_rowversion) ereport(ERROR, @@ -898,14 +927,15 @@ pltsql_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate) def->constraints = lappend(def->constraints, get_rowversion_default_constraint(def->typeName)); } break; - case T_Constraint: - { - Constraint *c = (Constraint *) element; - c->conname = construct_unique_index_name(c->conname, stmt->relation->relname); + case T_Constraint: + { + Constraint *c = (Constraint *) element; - if (rowversion_column_name) - validate_rowversion_table_constraint(c, rowversion_column_name); - } + c->conname = construct_unique_index_name(c->conname, stmt->relation->relname); + + if (rowversion_column_name) + validate_rowversion_table_constraint(c, rowversion_column_name); + } break; default: break; @@ -916,15 +946,15 @@ pltsql_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate) case T_AlterTableStmt: { - AlterTableStmt *atstmt = (AlterTableStmt *) parsetree; - ListCell *lcmd; - bool seen_identity = false; - bool seen_rowversion = false; - Oid relid; - Relation rel; - TupleDesc tupdesc; - AttrNumber attr_num; - char *rowversion_column_name = NULL; + AlterTableStmt *atstmt = (AlterTableStmt *) parsetree; + ListCell *lcmd; + bool seen_identity = false; + bool seen_rowversion = false; + Oid relid; + Relation rel; + TupleDesc tupdesc; + AttrNumber attr_num; + char *rowversion_column_name = NULL; /* Search through existing relation attributes */ relid = RangeVarGetRelid(atstmt->relation, NoLock, false); @@ -944,9 +974,9 @@ pltsql_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate) /* Check for identity attribute */ if (attr->attidentity) seen_identity = true; - + /* Check for rowversion attribute */ - if ((*common_utility_plugin_ptr->is_tsql_rowversion_or_timestamp_datatype)(attr->atttypid)) + if ((*common_utility_plugin_ptr->is_tsql_rowversion_or_timestamp_datatype) (attr->atttypid)) { seen_rowversion = true; rowversion_column_name = NameStr(attr->attname); @@ -974,7 +1004,8 @@ pltsql_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate) } if (is_rowversion_column(pstate, castNode(ColumnDef, cmd->def))) { - ColumnDef *def = castNode(ColumnDef, cmd->def); + ColumnDef *def = castNode(ColumnDef, cmd->def); + if (seen_rowversion) ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), @@ -985,88 +1016,100 @@ pltsql_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate) def->constraints = lappend(def->constraints, get_rowversion_default_constraint(def->typeName)); } break; - case AT_AddConstraint: - { - Constraint * c = castNode(Constraint, cmd->def); - c->conname = construct_unique_index_name(c->conname, atstmt->relation->relname); - - if (escape_hatch_unique_constraint != EH_IGNORE && - c->contype == CONSTR_UNIQUE && - is_nullable_constraint(c, relid)) + case AT_AddConstraint: { - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Nullable UNIQUE constraint is not supported. Please use babelfishpg_tsql.escape_hatch_unique_constraint to ignore " - "or add a NOT NULL constraint"))); - } + Constraint *c = castNode(Constraint, cmd->def); - if (rowversion_column_name) - validate_rowversion_table_constraint(c, rowversion_column_name); - } + c->conname = construct_unique_index_name(c->conname, atstmt->relation->relname); + + if (escape_hatch_unique_constraint != EH_IGNORE && + c->contype == CONSTR_UNIQUE && + is_nullable_constraint(c, relid)) + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Nullable UNIQUE constraint is not supported. Please use babelfishpg_tsql.escape_hatch_unique_constraint to ignore " + "or add a NOT NULL constraint"))); + } + + if (rowversion_column_name) + validate_rowversion_table_constraint(c, rowversion_column_name); + } break; case AT_AlterColumnType: - { - int colnamelen = strlen(cmd->name); - - /* Check if rowversion column type is being changed. */ - if (rowversion_column_name != NULL && - strlen(rowversion_column_name) == colnamelen) { - bool found = false; - if (pltsql_case_insensitive_identifiers) - { - char *colname = downcase_identifier(cmd->name, colnamelen, false, false); - char *dc_rv_name = downcase_identifier(rowversion_column_name, colnamelen, false, false); + int colnamelen = strlen(cmd->name); - if (strncmp(dc_rv_name, colname, colnamelen) == 0) - found = true; - } - else if (strncmp(rowversion_column_name, cmd->name, colnamelen) == 0) + /* + * Check if rowversion column type is + * being changed. + */ + if (rowversion_column_name != NULL && + strlen(rowversion_column_name) == colnamelen) { + bool found = false; + + if (pltsql_case_insensitive_identifiers) + { + char *colname = downcase_identifier(cmd->name, colnamelen, false, false); + char *dc_rv_name = downcase_identifier(rowversion_column_name, colnamelen, false, false); + + if (strncmp(dc_rv_name, colname, colnamelen) == 0) + found = true; + } + else if (strncmp(rowversion_column_name, cmd->name, colnamelen) == 0) + { found = true; + } + + if (found) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Cannot alter column \"%s\" because it is timestamp.", cmd->name))); } - if (found) + /* + * Check if a column type is being changed + * to rowversion. + */ + if (is_rowversion_column(pstate, castNode(ColumnDef, cmd->def))) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Cannot alter column \"%s\" because it is timestamp.", cmd->name))); + errmsg("Cannot alter column \"%s\" to be data type timestamp.", cmd->name))); } - - /* Check if a column type is being changed to rowversion. */ - if (is_rowversion_column(pstate, castNode(ColumnDef, cmd->def))) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Cannot alter column \"%s\" to be data type timestamp.", cmd->name))); - } break; case AT_ColumnDefault: - { - int colnamelen = strlen(cmd->name); - - /* Disallow defaults on a rowversion column. */ - if (rowversion_column_name != NULL && - strlen(rowversion_column_name) == colnamelen) { - bool found = false; - if (pltsql_case_insensitive_identifiers) - { - char *colname = downcase_identifier(cmd->name, colnamelen, false, false); - char *dc_rv_name = downcase_identifier(rowversion_column_name, colnamelen, false, false); + int colnamelen = strlen(cmd->name); - if (strncmp(dc_rv_name, colname, colnamelen) == 0) - found = true; - } - else if (strncmp(rowversion_column_name, cmd->name, colnamelen) == 0) + /* + * Disallow defaults on a rowversion + * column. + */ + if (rowversion_column_name != NULL && + strlen(rowversion_column_name) == colnamelen) { + bool found = false; + + if (pltsql_case_insensitive_identifiers) + { + char *colname = downcase_identifier(cmd->name, colnamelen, false, false); + char *dc_rv_name = downcase_identifier(rowversion_column_name, colnamelen, false, false); + + if (strncmp(dc_rv_name, colname, colnamelen) == 0) + found = true; + } + else if (strncmp(rowversion_column_name, cmd->name, colnamelen) == 0) + { found = true; - } + } - if (found) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Defaults cannot be created on columns of data type timestamp."))); + if (found) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Defaults cannot be created on columns of data type timestamp."))); + } } - } break; case AT_DropConstraint: cmd->name = construct_unique_index_name(cmd->name, atstmt->relation->relname); @@ -1078,57 +1121,62 @@ pltsql_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate) } break; case T_IndexStmt: - { - IndexStmt * stmt = (IndexStmt *) parsetree; - stmt->idxname = construct_unique_index_name(stmt->idxname, stmt->relation->relname); - - if (escape_hatch_unique_constraint != EH_IGNORE && - stmt->unique && - is_nullable_index(stmt)) { - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Nullable UNIQUE index is not supported. Please use babelfishpg_tsql.escape_hatch_unique_constraint to ignore " - "or add a NOT NULL constraint"))); + IndexStmt *stmt = (IndexStmt *) parsetree; + + stmt->idxname = construct_unique_index_name(stmt->idxname, stmt->relation->relname); + + if (escape_hatch_unique_constraint != EH_IGNORE && + stmt->unique && + is_nullable_index(stmt)) + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Nullable UNIQUE index is not supported. Please use babelfishpg_tsql.escape_hatch_unique_constraint to ignore " + "or add a NOT NULL constraint"))); + } } - } break; case T_CreateTableAsStmt: - { - CreateTableAsStmt *stmt = (CreateTableAsStmt *) parsetree; - Node *n = stmt->query; - - if (n && n->type == T_Query) { - Query *q = (Query *) n; - if (q->commandType == CMD_SELECT) + CreateTableAsStmt *stmt = (CreateTableAsStmt *) parsetree; + Node *n = stmt->query; + + if (n && n->type == T_Query) { - ListCell *t; - bool seen_rowversion = false; + Query *q = (Query *) n; - /* Varify if SELECT INTO ... statement not inserting multiple rowversion columns. */ - foreach(t, q->targetList) + if (q->commandType == CMD_SELECT) { - TargetEntry *tle = (TargetEntry *) lfirst(t); - Oid typeid = InvalidOid; + ListCell *t; + bool seen_rowversion = false; - if (!tle->resjunk) - typeid = exprType((Node *) tle->expr); - - if (OidIsValid(typeid) && (*common_utility_plugin_ptr->is_tsql_rowversion_or_timestamp_datatype)(typeid)) + /* + * Varify if SELECT INTO ... statement not + * inserting multiple rowversion columns. + */ + foreach(t, q->targetList) { - if (seen_rowversion) - ereport(ERROR, - (errcode(ERRCODE_INVALID_TABLE_DEFINITION), - errmsg("Only one timestamp column is allowed in a table."))); - seen_rowversion = true; - } - } + TargetEntry *tle = (TargetEntry *) lfirst(t); + Oid typeid = InvalidOid; - pltsql_set_nulls_first(q); + if (!tle->resjunk) + typeid = exprType((Node *) tle->expr); + + if (OidIsValid(typeid) && (*common_utility_plugin_ptr->is_tsql_rowversion_or_timestamp_datatype) (typeid)) + { + if (seen_rowversion) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("Only one timestamp column is allowed in a table."))); + seen_rowversion = true; + } + } + + pltsql_set_nulls_first(q); + } } } - } break; default: break; @@ -1136,23 +1184,23 @@ pltsql_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate) } else if (query->commandType == CMD_UPDATE) { - ListCell *lc; + ListCell *lc; /* Disallow updating a ROWVERSION column */ - foreach (lc, query->targetList) + foreach(lc, query->targetList) { TargetEntry *tle = (TargetEntry *) lfirst(lc); - TupleDesc tupdesc = RelationGetDescr(pstate->p_target_relation); - int attr_num = tle->resno - 1; + TupleDesc tupdesc = RelationGetDescr(pstate->p_target_relation); + int attr_num = tle->resno - 1; Form_pg_attribute attr; attr = TupleDescAttr(tupdesc, attr_num); - if((*common_utility_plugin_ptr->is_tsql_rowversion_or_timestamp_datatype)(attr->atttypid) && !IsA(tle->expr, SetToDefault)) + if ((*common_utility_plugin_ptr->is_tsql_rowversion_or_timestamp_datatype) (attr->atttypid) && !IsA(tle->expr, SetToDefault)) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Cannot update a timestamp column."))); + errmsg("Cannot update a timestamp column."))); } } } @@ -1241,8 +1289,8 @@ is_identity_constraint(ColumnDef *column) static bool is_rowversion_column(ParseState *pstate, ColumnDef *column) { - Type ctype; - Oid typeOid; + Type ctype; + Oid typeOid; ctype = LookupTypeName(pstate, column->typeName, NULL, true); @@ -1252,7 +1300,7 @@ is_rowversion_column(ParseState *pstate, ColumnDef *column) typeOid = ((Form_pg_type) GETSTRUCT(ctype))->oid; ReleaseSysCache(ctype); - if ((*common_utility_plugin_ptr->is_tsql_rowversion_or_timestamp_datatype)(typeOid)) + if ((*common_utility_plugin_ptr->is_tsql_rowversion_or_timestamp_datatype) (typeOid)) return true; return false; @@ -1269,43 +1317,44 @@ is_rowversion_column(ParseState *pstate, ColumnDef *column) static void validate_rowversion_column_constraints(ColumnDef *column) { - ListCell *lc; + ListCell *lc; foreach(lc, column->constraints) { Constraint *c = lfirst_node(Constraint, lc); + switch (c->contype) { - case CONSTR_UNIQUE: - { - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Unique constraint is not supported on a timestamp column."))); - break; - } - case CONSTR_PRIMARY: - { - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Primary key constraint is not supported on a timestamp column."))); - break; - } - case CONSTR_FOREIGN: - { - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Foreign key constraint is not supported on a timestamp column."))); - break; - } + case CONSTR_UNIQUE: + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Unique constraint is not supported on a timestamp column."))); + break; + } + case CONSTR_PRIMARY: + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Primary key constraint is not supported on a timestamp column."))); + break; + } + case CONSTR_FOREIGN: + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Foreign key constraint is not supported on a timestamp column."))); + break; + } case CONSTR_DEFAULT: - { - ereport(ERROR, - (errcode(ERRCODE_INVALID_COLUMN_DEFINITION), - errmsg("Defaults cannot be created on columns of data type timestamp."))); - break; - } - default: - break; + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_COLUMN_DEFINITION), + errmsg("Defaults cannot be created on columns of data type timestamp."))); + break; + } + default: + break; } } } @@ -1313,49 +1362,49 @@ validate_rowversion_column_constraints(ColumnDef *column) static void validate_rowversion_table_constraint(Constraint *c, char *rowversion_column_name) { - List *colnames = NIL; - ListCell *lc; - char *conname = NULL; - int rv_colname_len = strlen(rowversion_column_name); - char *dc_rv_name = downcase_identifier(rowversion_column_name, rv_colname_len, false, false); + List *colnames = NIL; + ListCell *lc; + char *conname = NULL; + int rv_colname_len = strlen(rowversion_column_name); + char *dc_rv_name = downcase_identifier(rowversion_column_name, rv_colname_len, false, false); - switch(c->contype) + switch (c->contype) { case CONSTR_UNIQUE: - { - conname = "Unique"; - colnames = c->keys; - break; - } + { + conname = "Unique"; + colnames = c->keys; + break; + } case CONSTR_PRIMARY: - { - conname = "Primary key"; - colnames = c->keys; - break; - } + { + conname = "Primary key"; + colnames = c->keys; + break; + } case CONSTR_FOREIGN: - { - conname = "Foreign key"; - colnames = c->fk_attrs; - break; - } + { + conname = "Foreign key"; + colnames = c->fk_attrs; + break; + } default: break; } if (colnames == NIL) return; - + foreach(lc, colnames) { - char *colname = strVal(lfirst(lc)); - bool found = false; + char *colname = strVal(lfirst(lc)); + bool found = false; if (strlen(colname) == rv_colname_len) { if (pltsql_case_insensitive_identifiers) { - char *dc_colname = downcase_identifier(colname, strlen(colname), false, false); + char *dc_colname = downcase_identifier(colname, strlen(colname), false, false); if (strncmp(dc_rv_name, dc_colname, rv_colname_len) == 0) found = true; @@ -1381,8 +1430,8 @@ validate_rowversion_table_constraint(Constraint *c, char *rowversion_column_name static Constraint * get_rowversion_default_constraint(TypeName *typname) { - TypeCast *castnode; - FuncCall *funccallnode; + TypeCast *castnode; + FuncCall *funccallnode; Constraint *constraint; funccallnode = makeFuncCall(list_make2(makeString("sys"), makeString("get_current_full_xact_id")), NIL, COERCE_EXPLICIT_CALL, -1); @@ -1401,11 +1450,11 @@ get_rowversion_default_constraint(TypeName *typname) static void revoke_type_permission_from_public(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, - ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc, List *type_name) + ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc, List *type_name) { - const char *template = "REVOKE ALL ON TYPE dummy FROM PUBLIC"; - List *res; - GrantStmt *revoke; + const char *template = "REVOKE ALL ON TYPE dummy FROM PUBLIC"; + List *res; + GrantStmt *revoke; PlannedStmt *wrapper; /* TSQL specific behavior */ @@ -1452,8 +1501,8 @@ static void check_nullable_identity_constraint(RangeVar *relation, ColumnDef *column) { ListCell *clist; - bool is_null = false; - bool is_identity = false; + bool is_null = false; + bool is_identity = false; foreach(clist, column->constraints) { @@ -1499,7 +1548,7 @@ has_unique_nullable_constraint(ColumnDef *column) is_unique = true; break; case CONSTR_NOTNULL: - is_notnull =true; + is_notnull = true; break; default: break; @@ -1509,16 +1558,17 @@ has_unique_nullable_constraint(ColumnDef *column) return is_unique & !is_notnull; } -static bool is_nullable_constraint(Constraint *cst, Oid rel_oid) +static bool +is_nullable_constraint(Constraint *cst, Oid rel_oid) { - ListCell *lc; + ListCell *lc; bool is_notnull = false; /* Loop through the constraint keys */ foreach(lc, cst->keys) { - String *strval = (String *) lfirst(lc); - const char *col_name = NULL; + String *strval = (String *) lfirst(lc); + const char *col_name = NULL; AttrNumber attnum = InvalidAttrNumber; col_name = strVal(strval); @@ -1543,12 +1593,12 @@ static bool is_nullable_constraint(Constraint *cst, Oid rel_oid) static bool get_attnotnull(Oid relid, AttrNumber attnum) { - HeapTuple tp; + HeapTuple tp; Form_pg_attribute att_tup; tp = SearchSysCache2(ATTNUM, - ObjectIdGetDatum(relid), - Int16GetDatum(attnum)); + ObjectIdGetDatum(relid), + Int16GetDatum(attnum)); if (HeapTupleIsValid(tp)) { @@ -1556,6 +1606,7 @@ get_attnotnull(Oid relid, AttrNumber attnum) att_tup = (Form_pg_attribute) GETSTRUCT(tp); result = att_tup->attnotnull; + ReleaseSysCache(tp); return result; @@ -1567,15 +1618,15 @@ get_attnotnull(Oid relid, AttrNumber attnum) static bool is_nullable_index(IndexStmt *stmt) { - ListCell *lc; + ListCell *lc; bool is_notnull = false; Oid rel_oid = RangeVarGetRelid(stmt->relation, NoLock, false); /* Loop through the index columns */ foreach(lc, stmt->indexParams) { - IndexElem *elem = lfirst_node(IndexElem, lc); - const char *col_name = elem->name; + IndexElem *elem = lfirst_node(IndexElem, lc); + const char *col_name = elem->name; AttrNumber attnum = get_attnum(rel_oid, col_name); if (get_attnotnull(rel_oid, attnum)) @@ -1590,28 +1641,28 @@ is_nullable_index(IndexStmt *stmt) static void pltsql_sequence_validate_increment(int64 increment_by, - int64 max_value, - int64 min_value) + int64 max_value, + int64 min_value) { unsigned long inc; unsigned long min_max_diff; - inc = increment_by >= 0 ? (unsigned long)increment_by : (unsigned long) (-1L * increment_by); + inc = increment_by >= 0 ? (unsigned long) increment_by : (unsigned long) (-1L * increment_by); min_max_diff = (unsigned long) (max_value - min_value); - if(inc > min_max_diff) + if (inc > min_max_diff) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("The absolute value of the increment must be less than or equal to the " - "difference between the minimum and maximum value of the sequence object."))); + "difference between the minimum and maximum value of the sequence object."))); } static void -pltsql_identity_datatype_map(ParseState *pstate, ColumnDef* column) +pltsql_identity_datatype_map(ParseState *pstate, ColumnDef *column) { - Type ctype; - Oid typeOid; - Oid tsqlSeqTypOid; + Type ctype; + Oid typeOid; + Oid tsqlSeqTypOid; if (prev_pltsql_identity_datatype_hook) prev_pltsql_identity_datatype_hook(pstate, column); @@ -1633,11 +1684,11 @@ pltsql_identity_datatype_map(ParseState *pstate, ColumnDef* column) } else if (typeOid == NUMERICOID || getBaseType(typeOid) == NUMERICOID) { - int32 typmod_p; - uint8_t scale; - uint8_t precision; + int32 typmod_p; + uint8_t scale; + uint8_t precision; - Type typ = typenameType(pstate, column->typeName, &typmod_p); + Type typ = typenameType(pstate, column->typeName, &typmod_p); if (typeOid != NUMERICOID) { @@ -1645,7 +1696,7 @@ pltsql_identity_datatype_map(ParseState *pstate, ColumnDef* column) typmod_p = column->typeName->typemod; if (typmod_p == -1) - typmod_p = 1179652; /* decimal(18,0) */ + typmod_p = 1179652; /* decimal(18,0) */ } scale = (typmod_p - VARHDRSZ) & 0xffff; @@ -1677,16 +1728,17 @@ pltsql_sequence_datatype_map(ParseState *pstate, DefElem **max_value, DefElem **min_value) { - int32 typmod_p; - Type typ; - char *typname; - Oid tsqlSeqTypOid; - TypeName *type_def; - List* type_names; - List* new_type_names; - AclResult aclresult; - Oid base_type; - int list_len; + int32 typmod_p; + Type typ; + char *typname; + Oid tsqlSeqTypOid; + TypeName *type_def; + List *type_names; + List *new_type_names; + AclResult aclresult; + Oid base_type; + int list_len; + if (prev_pltsql_sequence_datatype_hook) prev_pltsql_sequence_datatype_hook(pstate, newtypid, @@ -1715,7 +1767,7 @@ pltsql_sequence_datatype_map(ParseState *pstate, break; } - if(list_len > 1) + if (list_len > 1) type_def->names = new_type_names; *newtypid = typenameTypeId(pstate, type_def); @@ -1723,7 +1775,7 @@ pltsql_sequence_datatype_map(ParseState *pstate, typname = typeTypeName(typ); type_def->names = type_names; - if(list_len > 1) + if (list_len > 1) list_free(new_type_names); aclresult = pg_type_aclcheck(*newtypid, GetUserId(), ACL_USAGE); @@ -1745,8 +1797,8 @@ pltsql_sequence_datatype_map(ParseState *pstate, /* Verified sys type. Set tinyint constraint 0 to 255 */ if (strcmp(typname, "tinyint") == 0) { - int64 tinyint_max; - int64 tinyint_min; + int64 tinyint_max; + int64 tinyint_min; /* NULL arg means no value so check max_value then the arg */ if (*max_value == NULL) @@ -1786,21 +1838,23 @@ pltsql_sequence_datatype_map(ParseState *pstate, else if ((*newtypid == NUMERICOID) || (base_type == NUMERICOID)) { /* - * Identity column drops the typmod upon sequence creation - * so it gets its own check + * Identity column drops the typmod upon sequence creation so it gets + * its own check */ - /* When sequence is created using user-defined data type, !for_identity == true and - * typmod_p == -1, which results in calculating incorrect scale and precision - * therefore we update typmod_p to that of numeric(18,0) + /* + * When sequence is created using user-defined data type, + * !for_identity == true and typmod_p == -1, which results in + * calculating incorrect scale and precision therefore we update + * typmod_p to that of numeric(18,0) */ if (typmod_p == -1) typmod_p = 1179652; if (!for_identity || typmod_p != -1) { - uint8_t scale = (typmod_p - VARHDRSZ) & 0xffff; - uint8_t precision = ((typmod_p - VARHDRSZ) >> 16) & 0xffff; + uint8_t scale = (typmod_p - VARHDRSZ) & 0xffff; + uint8_t precision = ((typmod_p - VARHDRSZ) >> 16) & 0xffff; if (scale > 0) ereport(ERROR, @@ -1819,18 +1873,18 @@ pltsql_sequence_datatype_map(ParseState *pstate, } /* - * To add support for User-Defined Data types for sequences, data type - * of sequence is changed to its basetype - */ + * To add support for User-Defined Data types for sequences, data type of + * sequence is changed to its basetype + */ *newtypid = base_type; } static Oid bbf_table_var_lookup(const char *relname, Oid relnamespace) { - Oid relid; - ListCell *lc; - int n; + Oid relid; + ListCell *lc; + int n; PLtsql_tbl *tbl; PLtsql_execstate *estate = get_current_tsql_estate(); @@ -1847,7 +1901,7 @@ bbf_table_var_lookup(const char *relname, Oid relnamespace) * If we find a table variable whose name matches relname, return its * underlying table's relid. Otherwise, just return relname's relid. */ - foreach (lc, estate->func->table_varnos) + foreach(lc, estate->func->table_varnos) { n = lfirst_int(lc); if (estate->datums[n]->dtype != PLTSQL_DTYPE_TBL) @@ -1856,9 +1910,11 @@ bbf_table_var_lookup(const char *relname, Oid relnamespace) tbl = (PLtsql_tbl *) estate->datums[n]; if (strcmp(relname, tbl->refname) == 0) { - if (!tbl->tblname) /* FIXME: throwing an error instead of a crash until table-type is supported in ANTLR parser */ - ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("table variable underlying typename is NULL. refname: %s", tbl->refname))); + if (!tbl->tblname) /* FIXME: throwing an error instead of a crash + * until table-type is supported in ANTLR + * parser */ + ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("table variable underlying typename is NULL. refname: %s", tbl->refname))); return get_relname_relid(tbl->tblname, relnamespace); } } @@ -1871,11 +1927,12 @@ bbf_table_var_lookup(const char *relname, Oid relnamespace) */ static void PLTsqlProcessTransaction(Node *parsetree, - ParamListInfo params, - QueryCompletion *qc) + ParamListInfo params, + QueryCompletion *qc) { - char *txnName = NULL; + char *txnName = NULL; TransactionStmt *stmt = (TransactionStmt *) parsetree; + if (params != NULL && params->numParams > 0 && !params->params[0].isnull) { Oid typOutput; @@ -1901,7 +1958,7 @@ PLTsqlProcessTransaction(Node *parsetree, if (stmt->kind == TRANS_STMT_BEGIN || stmt->kind == TRANS_STMT_COMMIT || stmt->kind == TRANS_STMT_SAVEPOINT) - ereport(ERROR, + ereport(ERROR, (errcode(ERRCODE_TRANSACTION_ROLLBACK), errmsg("The current transaction cannot be committed and cannot support operations that write to the log file. Roll back the transaction."))); } @@ -1936,10 +1993,11 @@ PLTsqlProcessTransaction(Node *parsetree, ereport(ERROR, (errcode(ERRCODE_TRANSACTION_ROLLBACK), errmsg("Cannot use the ROLLBACK statement within an INSERT-EXEC statement."))); + /* - * Table variables should be immune to ROLLBACK, but we haven't - * implemented this yet so we throw an error if ROLLBACK is used - * with table variables. + * Table variables should be immune to ROLLBACK, but we + * haven't implemented this yet so we throw an error if + * ROLLBACK is used with table variables. */ if (exec_state_call_stack && exec_state_call_stack->estate && @@ -1973,13 +2031,14 @@ PLTsqlProcessTransaction(Node *parsetree, * even in EXPLAIN ONLY MODE. In that case, EXPLAIN ONLY MODE should be considered * for individual statements inside the procedure. */ -static inline bool process_utility_stmt_explain_only_mode(const char *queryString, Node *parsetree) +static inline bool +process_utility_stmt_explain_only_mode(const char *queryString, Node *parsetree) { - CallStmt *callstmt; - HeapTuple proctuple; - Oid procid; - Oid langoid; - char *langname; + CallStmt *callstmt; + HeapTuple proctuple; + Oid procid; + Oid langoid; + char *langname; if (!pltsql_explain_only) return false; @@ -2002,8 +2061,10 @@ static inline bool process_utility_stmt_explain_only_mode(const char *queryStrin if (!langname) return true; - /* If a procedure language is pltsql, it is safe to execute the procedure. - * EXPLAIN ONLY MODE will be considered for each statements inside the procedure. + /* + * If a procedure language is pltsql, it is safe to execute the procedure. + * EXPLAIN ONLY MODE will be considered for each statements inside the + * procedure. */ if (pg_strcasecmp("pltsql", langname) == 0) return false; @@ -2015,11 +2076,12 @@ static inline bool process_utility_stmt_explain_only_mode(const char *queryStrin * check whether role contains '\' or not and SQL_USER contains '\' or not * If yes, throw error. */ -static void validateUserAndRole(char* name) +static void +validateUserAndRole(char *name) { if (strchr(name, '\\') != NULL) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("'%s' is not a valid name because it contains invalid characters.", name))); + errmsg("'%s' is not a valid name because it contains invalid characters.", name))); } @@ -2029,27 +2091,29 @@ static void validateUserAndRole(char* name) * CreateFunctionStmt could have elements in the options list that are specific * to tsql, like trigStmt and tbltypStmt. */ -static void bbf_ProcessUtility(PlannedStmt *pstmt, - const char *queryString, - bool readOnlyTree, - ProcessUtilityContext context, - ParamListInfo params, - QueryEnvironment *queryEnv, - DestReceiver *dest, - QueryCompletion *qc) +static void +bbf_ProcessUtility(PlannedStmt *pstmt, + const char *queryString, + bool readOnlyTree, + ProcessUtilityContext context, + ParamListInfo params, + QueryEnvironment *queryEnv, + DestReceiver *dest, + QueryCompletion *qc) { - Node *parsetree = pstmt->utilityStmt; - ParseState *pstate = make_parsestate(NULL); - pstate->p_sourcetext = queryString; + Node *parsetree = pstmt->utilityStmt; + ParseState *pstate = make_parsestate(NULL); + + pstate->p_sourcetext = queryString; if (process_utility_stmt_explain_only_mode(queryString, parsetree)) - return; /* Don't execute anything */ + return; /* Don't execute anything */ /* * Block ALTER VIEW and CREATE OR REPLACE VIEW statements from PG dialect - * executed on TSQL views which has entries in view_def catalog - * Note: Changes made by ALTER VIEW or CREATE [OR REPLACE] VIEW statements - * in TSQL dialect from PG client won't be reflected in babelfish_view_def + * executed on TSQL views which has entries in view_def catalog Note: + * Changes made by ALTER VIEW or CREATE [OR REPLACE] VIEW statements in + * TSQL dialect from PG client won't be reflected in babelfish_view_def * catalog. */ if (sql_dialect == SQL_DIALECT_PG && !babelfish_dump_restore && !pltsql_enable_create_alter_view_from_pg) @@ -2057,64 +2121,71 @@ static void bbf_ProcessUtility(PlannedStmt *pstmt, switch (nodeTag(parsetree)) { case T_ViewStmt: - { - ViewStmt *vstmt = (ViewStmt *) parsetree; - Oid relid = RangeVarGetRelid(vstmt->view, NoLock, true); - if (vstmt->replace && check_is_tsql_view(relid)) { - ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("REPLACE VIEW is blocked in PG dialect on TSQL view present in babelfish_view_def catalog. Please set babelfishpg_tsql.enable_create_alter_view_from_pg to true to enable."))); + ViewStmt *vstmt = (ViewStmt *) parsetree; + Oid relid = RangeVarGetRelid(vstmt->view, NoLock, true); + + if (vstmt->replace && check_is_tsql_view(relid)) + { + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("REPLACE VIEW is blocked in PG dialect on TSQL view present in babelfish_view_def catalog. Please set babelfishpg_tsql.enable_create_alter_view_from_pg to true to enable."))); + } + break; } - break; - } case T_AlterTableStmt: - { - AlterTableStmt *atstmt = (AlterTableStmt *) parsetree; - if (atstmt->objtype == OBJECT_VIEW) { - Oid relid = RangeVarGetRelid(atstmt->relation, NoLock, true); - if(check_is_tsql_view(relid)) + AlterTableStmt *atstmt = (AlterTableStmt *) parsetree; + + if (atstmt->objtype == OBJECT_VIEW) { - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("ALTER VIEW is blocked in PG dialect on TSQL view present in babelfish_view_def catalog. Please set babelfishpg_tsql.enable_create_alter_view_from_pg to true to enable."))); + Oid relid = RangeVarGetRelid(atstmt->relation, NoLock, true); + + if (check_is_tsql_view(relid)) + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("ALTER VIEW is blocked in PG dialect on TSQL view present in babelfish_view_def catalog. Please set babelfishpg_tsql.enable_create_alter_view_from_pg to true to enable."))); + } } + break; } - break; - } case T_RenameStmt: - { - RenameStmt *rnstmt = (RenameStmt *) parsetree; - if (rnstmt->renameType == OBJECT_VIEW || - (rnstmt->renameType == OBJECT_COLUMN && - rnstmt->relationType == OBJECT_VIEW)) { - Oid relid = RangeVarGetRelid(rnstmt->relation, NoLock, true); - if(check_is_tsql_view(relid)) + RenameStmt *rnstmt = (RenameStmt *) parsetree; + + if (rnstmt->renameType == OBJECT_VIEW || + (rnstmt->renameType == OBJECT_COLUMN && + rnstmt->relationType == OBJECT_VIEW)) { - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("ALTER VIEW is blocked in PG dialect on TSQL view present in babelfish_view_def catalog. Please set babelfishpg_tsql.enable_create_alter_view_from_pg to true to enable."))); + Oid relid = RangeVarGetRelid(rnstmt->relation, NoLock, true); + + if (check_is_tsql_view(relid)) + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("ALTER VIEW is blocked in PG dialect on TSQL view present in babelfish_view_def catalog. Please set babelfishpg_tsql.enable_create_alter_view_from_pg to true to enable."))); + } } + break; } - break; - } case T_AlterObjectSchemaStmt: - { - AlterObjectSchemaStmt *altschstmt = (AlterObjectSchemaStmt *) parsetree; - if (altschstmt->objectType == OBJECT_VIEW) { - Oid relid = RangeVarGetRelid(altschstmt->relation, NoLock, true); - if(check_is_tsql_view(relid)) + AlterObjectSchemaStmt *altschstmt = (AlterObjectSchemaStmt *) parsetree; + + if (altschstmt->objectType == OBJECT_VIEW) { - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("ALTER VIEW is blocked in PG dialect on TSQL view present in babelfish_view_def catalog. Please set babelfishpg_tsql.enable_create_alter_view_from_pg to true to enable."))); + Oid relid = RangeVarGetRelid(altschstmt->relation, NoLock, true); + + if (check_is_tsql_view(relid)) + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("ALTER VIEW is blocked in PG dialect on TSQL view present in babelfish_view_def catalog. Please set babelfishpg_tsql.enable_create_alter_view_from_pg to true to enable."))); + } } + break; } - break; - } default: break; } @@ -2125,34 +2196,42 @@ static void bbf_ProcessUtility(PlannedStmt *pstmt, case T_CreateFunctionStmt: { CreateFunctionStmt *stmt = (CreateFunctionStmt *) parsetree; - bool isCompleteQuery = (context != PROCESS_UTILITY_SUBCOMMAND); - bool needCleanup; - ListCell *option, *location_cell = NULL; - Node *tbltypStmt = NULL; - Node *trigStmt = NULL; - ObjectAddress tbltyp; - ObjectAddress address; - int origname_location = -1; - - /* All event trigger calls are done only when isCompleteQuery is true */ + bool isCompleteQuery = (context != PROCESS_UTILITY_SUBCOMMAND); + bool needCleanup; + ListCell *option, + *location_cell = NULL; + Node *tbltypStmt = NULL; + Node *trigStmt = NULL; + ObjectAddress tbltyp; + ObjectAddress address; + int origname_location = -1; + + /* + * All event trigger calls are done only when isCompleteQuery + * is true + */ needCleanup = isCompleteQuery && EventTriggerBeginCompleteQuery(); - /* PG_TRY block is to ensure we call EventTriggerEndCompleteQuery */ + /* + * PG_TRY block is to ensure we call + * EventTriggerEndCompleteQuery + */ PG_TRY(); { if (isCompleteQuery) EventTriggerDDLCommandStart(parsetree); - foreach (option, stmt->options) + foreach(option, stmt->options) { - DefElem *defel = (DefElem *) lfirst(option); + DefElem *defel = (DefElem *) lfirst(option); + if (strcmp(defel->defname, "tbltypStmt") == 0) { /* - * tbltypStmt is an implicit option in tsql dialect, - * we use this mechanism to create tsql style - * multi-statement table-valued function and its - * return (table) type in one statement. + * tbltypStmt is an implicit option in tsql + * dialect, we use this mechanism to create tsql + * style multi-statement table-valued function and + * its return (table) type in one statement. */ tbltypStmt = defel->arg; } @@ -2160,8 +2239,8 @@ static void bbf_ProcessUtility(PlannedStmt *pstmt, { /* * trigStmt is an implicit option in tsql dialect, - * we use this mechanism to create tsql style function - * and trigger in one statement. + * we use this mechanism to create tsql style + * function and trigger in one statement. */ trigStmt = defel->arg; } @@ -2169,9 +2248,9 @@ static void bbf_ProcessUtility(PlannedStmt *pstmt, { /* * location is an implicit option in tsql dialect, - * we use this mechanism to store location of function - * name so that we can extract original input function - * name from queryString. + * we use this mechanism to store location of + * function name so that we can extract original + * input function name from queryString. */ origname_location = intVal((Node *) defel->arg); location_cell = option; @@ -2179,7 +2258,10 @@ static void bbf_ProcessUtility(PlannedStmt *pstmt, } } - /* delete location cell if it exists as it is for internal use only */ + /* + * delete location cell if it exists as it is for internal + * use only + */ if (location_cell) stmt->options = list_delete_cell(stmt->options, location_cell); @@ -2216,7 +2298,10 @@ static void bbf_ProcessUtility(PlannedStmt *pstmt, address = CreateFunction(pstate, stmt); - /* Store function/procedure related metadata in babelfish catalog */ + /* + * Store function/procedure related metadata in babelfish + * catalog + */ pltsql_store_func_default_positions(address, stmt->parameters, queryString, origname_location); if (tbltypStmt || restore_tsql_tabletype) @@ -2227,29 +2312,29 @@ static void bbf_ProcessUtility(PlannedStmt *pstmt, */ tbltyp.classId = TypeRelationId; tbltyp.objectId = typenameTypeId(pstate, - stmt->returnType); + stmt->returnType); tbltyp.objectSubId = 0; recordDependencyOn(&tbltyp, &address, DEPENDENCY_INTERNAL); } /* - * For trigStmt, we need to process the CreateTrigStmt after - * the function is created, and record bidirectional + * For trigStmt, we need to process the CreateTrigStmt + * after the function is created, and record bidirectional * dependency so that Drop Trigger CASCADE will drop the - * implicit trigger function. - * Create trigger takes care of dependency addition. + * implicit trigger function. Create trigger takes care of + * dependency addition. */ - if(trigStmt) + if (trigStmt) { (void) CreateTrigger((CreateTrigStmt *) trigStmt, - pstate->p_sourcetext, InvalidOid, InvalidOid, - InvalidOid, InvalidOid, address.objectId, - InvalidOid, NULL, false, false); + pstate->p_sourcetext, InvalidOid, InvalidOid, + InvalidOid, InvalidOid, address.objectId, + InvalidOid, NULL, false, false); } /* - * Remember the object so that ddl_command_end event triggers have - * access to it. + * Remember the object so that ddl_command_end event + * triggers have access to it. */ EventTriggerCollectSimpleCommand(address, InvalidObjectAddress, parsetree); @@ -2273,950 +2358,1003 @@ static void bbf_ProcessUtility(PlannedStmt *pstmt, EventTriggerEndCompleteQuery(); return; } - case T_TransactionStmt: - { - if (NestedTranCount > 0 || (sql_dialect == SQL_DIALECT_TSQL && !IsTransactionBlockActive())) - { - PLTsqlProcessTransaction(parsetree, params, qc); - return; - } - break; - } + case T_TransactionStmt: + { + if (NestedTranCount > 0 || (sql_dialect == SQL_DIALECT_TSQL && !IsTransactionBlockActive())) + { + PLTsqlProcessTransaction(parsetree, params, qc); + return; + } + break; + } case T_TruncateStmt: - { - if (sql_dialect == SQL_DIALECT_TSQL) { - TruncateStmt *stmt = (TruncateStmt *) parsetree; + if (sql_dialect == SQL_DIALECT_TSQL) + { + TruncateStmt *stmt = (TruncateStmt *) parsetree; - stmt->restart_seqs = true; /* Always restart owned sequences */ + stmt->restart_seqs = true; /* Always restart owned + * sequences */ + } + break; } - break; - } case T_CreateRoleStmt: - { - if (sql_dialect == SQL_DIALECT_TSQL) { - const char *prev_current_user; - CreateRoleStmt *stmt = (CreateRoleStmt *) parsetree; - List *login_options = NIL; - List *user_options = NIL; - ListCell *option; - bool islogin = false; - bool isuser = false; - bool isrole = false; - bool from_windows = false; - - /* Check if creating login or role. Expect islogin first */ - if (stmt->options != NIL) + if (sql_dialect == SQL_DIALECT_TSQL) { - DefElem *headel = (DefElem *) linitial(stmt->options); - - /* - * If islogin set the options list to after the head. - * Save the list of login specific options. - */ - if (strcmp(headel->defname, "islogin") == 0) + const char *prev_current_user; + CreateRoleStmt *stmt = (CreateRoleStmt *) parsetree; + List *login_options = NIL; + List *user_options = NIL; + ListCell *option; + bool islogin = false; + bool isuser = false; + bool isrole = false; + bool from_windows = false; + + /* Check if creating login or role. Expect islogin first */ + if (stmt->options != NIL) { - char *orig_loginname = NULL; - - islogin = true; - stmt->options = list_delete_cell(stmt->options, - list_head(stmt->options)); - pfree(headel); + DefElem *headel = (DefElem *) linitial(stmt->options); - /* Filter login options from default role options */ - foreach(option, stmt->options) + /* + * If islogin set the options list to after the head. + * Save the list of login specific options. + */ + if (strcmp(headel->defname, "islogin") == 0) { - DefElem *defel = (DefElem *) lfirst(option); + char *orig_loginname = NULL; + + islogin = true; + stmt->options = list_delete_cell(stmt->options, + list_head(stmt->options)); + pfree(headel); + + /* Filter login options from default role options */ + foreach(option, stmt->options) + { + DefElem *defel = (DefElem *) lfirst(option); + + if (strcmp(defel->defname, "default_database") == 0) + login_options = lappend(login_options, defel); + else if (strcmp(defel->defname, "name_location") == 0) + { + int location = defel->location; + + orig_loginname = extract_identifier(queryString + location); + login_options = lappend(login_options, defel); + } + else if (strcmp(defel->defname, "from_windows") == 0) + { + if (!pltsql_allow_windows_login) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Windows login is not supported in babelfish"))); + from_windows = true; + login_options = lappend(login_options, defel); + } + } - if (strcmp(defel->defname, "default_database") == 0) - login_options = lappend(login_options, defel); - else if (strcmp(defel->defname, "name_location") == 0) + foreach(option, login_options) { - int location = defel->location; - orig_loginname = extract_identifier(queryString + location); - login_options = lappend(login_options, defel); + stmt->options = list_delete_ptr(stmt->options, + lfirst(option)); } - else if (strcmp(defel->defname, "from_windows") == 0) + + if (orig_loginname) { - if (!pltsql_allow_windows_login) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Windows login is not supported in babelfish"))); - from_windows = true; - login_options = lappend(login_options, defel); + login_options = lappend(login_options, + makeDefElem("original_login_name", + (Node *) makeString(orig_loginname), + -1)); } - } - foreach(option, login_options) - { - stmt->options = list_delete_ptr(stmt->options, - lfirst(option)); - } + if (from_windows && orig_loginname) + { + /* + * The login name must contain '\' if it is + * windows login or else throw error. + */ + if ((strchr(orig_loginname, '\\')) == NULL) + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("'%s' is not a valid Windows NT name. Give the complete name: .", + orig_loginname))); - if (orig_loginname) - { - login_options = lappend(login_options, - makeDefElem("original_login_name", - (Node *) makeString(orig_loginname), - -1)); - } + /* + * Check whether domain name is empty. If the + * first character is '\', that ensures domain + * is empty. + */ + if (orig_loginname[0] == '\\') + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("The login name '%s' is invalid. The domain can not be empty.", + orig_loginname))); - if (from_windows && orig_loginname) - { - /* - * The login name must contain '\' if it is windows login or else throw error. - */ - if ((strchr(orig_loginname, '\\')) == NULL) - ereport(ERROR, - (errcode(ERRCODE_INVALID_NAME), - errmsg("'%s' is not a valid Windows NT name. Give the complete name: .", - orig_loginname))); + /* + * Check whether login_name has valid length + * or not. + */ + if (!check_windows_logon_length(orig_loginname)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("The login name '%s' has invalid length. Login name length should be between %d and %d for windows login.", + orig_loginname, (LOGON_NAME_MIN_LEN + 1), (LOGON_NAME_MAX_LEN - 1)))); - /* - * Check whether domain name is empty. If the first character is '\', that ensures domain is empty. - */ - if (orig_loginname[0] == '\\') - ereport(ERROR, - (errcode(ERRCODE_INVALID_NAME), - errmsg("The login name '%s' is invalid. The domain can not be empty.", - orig_loginname))); + /* + * Check whether the login_name contains + * invalid characters or not. + */ + if (windows_login_contains_invalid_chars(orig_loginname)) + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("'%s' is not a valid name because it contains invalid characters.", orig_loginname))); + + pfree(stmt->role); + stmt->role = convertToUPN(orig_loginname); + + /* + * Check for duplicate login + */ + if (get_role_oid(stmt->role, true) != InvalidOid) + ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("The Server principal '%s' already exists", stmt->role))); + } /* - * Check whether login_name has valid length or not. + * Length of login name should be less than 128. + * Throw an error here if it is not. XXX: Below + * check is to work around BABEL-3868. */ - if (!check_windows_logon_length(orig_loginname)) + if (strlen(stmt->role) >= NAMEDATALEN) + { ereport(ERROR, (errcode(ERRCODE_INVALID_NAME), - errmsg("The login name '%s' has invalid length. Login name length should be between %d and %d for windows login.", - orig_loginname, (LOGON_NAME_MIN_LEN + 1), (LOGON_NAME_MAX_LEN - 1)))); + errmsg("The login name '%s' is too long. Maximum length is %d.", + stmt->role, (NAMEDATALEN - 1)))); + } /* - * Check whether the login_name contains invalid characters or not. + * If the login name contains '\' and it is not a + * windows login then throw error. For windows + * login, all cases are handled beforehand, so if + * the below condition is hit that means it is + * password based authentication and login name + * contains '\', which is not allowed */ - if (windows_login_contains_invalid_chars(orig_loginname)) + if (!from_windows && strchr(stmt->role, '\\') != NULL) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("'%s' is not a valid name because it contains invalid characters.", orig_loginname))); - - pfree(stmt->role); - stmt->role = convertToUPN(orig_loginname); + errmsg("'%s' is not a valid name because it contains invalid characters.", stmt->role))); - /* - * Check for duplicate login - */ - if (get_role_oid(stmt->role, true) != InvalidOid) - ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("The Server principal '%s' already exists", stmt->role))); + from_windows = false; } - - /* - * Length of login name should be less than 128. Throw an error - * here if it is not. - * XXX: Below check is to work around BABEL-3868. - */ - if (strlen(stmt->role) >= NAMEDATALEN) + else if (strcmp(headel->defname, "isuser") == 0) { - ereport(ERROR, - (errcode(ERRCODE_INVALID_NAME), - errmsg("The login name '%s' is too long. Maximum length is %d.", - stmt->role, (NAMEDATALEN - 1)))); - } - - /* - * If the login name contains '\' and it is not a windows login then throw error. - * For windows login, all cases are handled beforehand, so if the below condition - * is hit that means it is password based authentication and login name contains - * '\', which is not allowed - */ - if (!from_windows && strchr(stmt->role, '\\') != NULL) - ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("'%s' is not a valid name because it contains invalid characters.", stmt->role))); - - from_windows = false; - } - else if (strcmp(headel->defname, "isuser") == 0) - { - int location = -1; - - isuser = true; - stmt->options = list_delete_cell(stmt->options, - list_head(stmt->options)); - pfree(headel); + int location = -1; - /* Filter user options from default role options */ - foreach(option, stmt->options) - { - DefElem *defel = (DefElem *) lfirst(option); + isuser = true; + stmt->options = list_delete_cell(stmt->options, + list_head(stmt->options)); + pfree(headel); - if (strcmp(defel->defname, "default_schema") == 0) - user_options = lappend(user_options, defel); - else if (strcmp(defel->defname, "name_location") == 0) - { - location = defel->location; - user_options = lappend(user_options, defel); - } - else if (strcmp(defel->defname, "rolemembers") == 0) + /* Filter user options from default role options */ + foreach(option, stmt->options) { - RoleSpec *login = (RoleSpec *) linitial((List *) defel->arg); - if (strchr(login->rolename, '\\') != NULL) + DefElem *defel = (DefElem *) lfirst(option); + + if (strcmp(defel->defname, "default_schema") == 0) + user_options = lappend(user_options, defel); + else if (strcmp(defel->defname, "name_location") == 0) { - /* - * If login->rolename contains '\' then treat it as windows login. - */ - char *upn_login = convertToUPN(login->rolename); - if (upn_login != login->rolename) + location = defel->location; + user_options = lappend(user_options, defel); + } + else if (strcmp(defel->defname, "rolemembers") == 0) + { + RoleSpec *login = (RoleSpec *) linitial((List *) defel->arg); + + if (strchr(login->rolename, '\\') != NULL) { - pfree(login->rolename); - login->rolename = upn_login; + /* + * If login->rolename contains '\' + * then treat it as windows login. + */ + char *upn_login = convertToUPN(login->rolename); + + if (upn_login != login->rolename) + { + pfree(login->rolename); + login->rolename = upn_login; + } + from_windows = true; + if (!pltsql_allow_windows_login) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Windows login is not supported in babelfish"))); } - from_windows = true; - if (!pltsql_allow_windows_login) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Windows login is not supported in babelfish"))); } } - } - foreach(option, user_options) - { - stmt->options = list_delete_ptr(stmt->options, - lfirst(option)); - } + foreach(option, user_options) + { + stmt->options = list_delete_ptr(stmt->options, + lfirst(option)); + } - if (location >= 0) - { - char *orig_user_name; + if (location >= 0) + { + char *orig_user_name; - orig_user_name = extract_identifier(queryString + location); - user_options = lappend(user_options, - makeDefElem("original_user_name", - (Node *) makeString(orig_user_name), - -1)); + orig_user_name = extract_identifier(queryString + location); + user_options = lappend(user_options, + makeDefElem("original_user_name", + (Node *) makeString(orig_user_name), + -1)); + } } - } - else if (strcmp(headel->defname, "isrole") == 0) - { - int location = -1; - bool orig_username_exists = false; - - isrole = true; - stmt->options = list_delete_cell(stmt->options, - list_head(stmt->options)); - pfree(headel); - - /* Filter TSQL role options from default role options */ - foreach(option, stmt->options) + else if (strcmp(headel->defname, "isrole") == 0) { - DefElem *defel = (DefElem *) lfirst(option); + int location = -1; + bool orig_username_exists = false; + + isrole = true; + stmt->options = list_delete_cell(stmt->options, + list_head(stmt->options)); + pfree(headel); - if (strcmp(defel->defname, "name_location") == 0) - { - location = defel->location; - user_options = lappend(user_options, defel); - } /* - * This condition is to handle create role when using sp_addrole procedure - * because there we add original_user_name before hand + * Filter TSQL role options from default role + * options */ - if(strcmp(defel->defname, "original_user_name") == 0) + foreach(option, stmt->options) { - user_options = lappend(user_options, defel); - orig_username_exists = true; - } + DefElem *defel = (DefElem *) lfirst(option); - } + if (strcmp(defel->defname, "name_location") == 0) + { + location = defel->location; + user_options = lappend(user_options, defel); + } + /* + * This condition is to handle create role + * when using sp_addrole procedure because + * there we add original_user_name before hand + */ + if (strcmp(defel->defname, "original_user_name") == 0) + { + user_options = lappend(user_options, defel); + orig_username_exists = true; + } - foreach(option, user_options) - { - stmt->options = list_delete_ptr(stmt->options, - lfirst(option)); - } + } - if (location >= 0 && !orig_username_exists) - { - char *orig_user_name; - orig_user_name = extract_identifier(queryString + location); - user_options = lappend(user_options, - makeDefElem("original_user_name", - (Node *) makeString(orig_user_name), - -1)); + foreach(option, user_options) + { + stmt->options = list_delete_ptr(stmt->options, + lfirst(option)); + } + + if (location >= 0 && !orig_username_exists) + { + char *orig_user_name; + + orig_user_name = extract_identifier(queryString + location); + user_options = lappend(user_options, + makeDefElem("original_user_name", + (Node *) makeString(orig_user_name), + -1)); + } } - } - } + } - if (islogin) - { - if (!has_privs_of_role(GetSessionUserId(), get_role_oid("sysadmin", false))) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("Current login %s does not have permission to create new login", - GetUserNameFromId(GetSessionUserId(), true)))); + if (islogin) + { + if (!has_privs_of_role(GetSessionUserId(), get_role_oid("sysadmin", false))) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("Current login %s does not have permission to create new login", + GetUserNameFromId(GetSessionUserId(), true)))); - if (get_role_oid(stmt->role, true) != InvalidOid) - ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("The Server principal '%s' already exists", stmt->role))); + if (get_role_oid(stmt->role, true) != InvalidOid) + ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("The Server principal '%s' already exists", stmt->role))); - /* Set current user to sysadmin for create permissions */ - prev_current_user = GetUserNameFromId(GetUserId(), false); + /* Set current user to sysadmin for create permissions */ + prev_current_user = GetUserNameFromId(GetUserId(), false); - bbf_set_current_user("sysadmin"); + bbf_set_current_user("sysadmin"); - PG_TRY(); - { - if (prev_ProcessUtility) - prev_ProcessUtility(pstmt, queryString,readOnlyTree, context, - params, queryEnv, dest, - qc); - else - standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, + PG_TRY(); + { + if (prev_ProcessUtility) + prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, queryEnv, dest, qc); + else + standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, + params, queryEnv, dest, + qc); - stmt->options = list_concat(stmt->options, - login_options); - create_bbf_authid_login_ext(stmt); - } - PG_CATCH(); - { - bbf_set_current_user(prev_current_user); - PG_RE_THROW(); - } - PG_END_TRY(); + stmt->options = list_concat(stmt->options, + login_options); + create_bbf_authid_login_ext(stmt); + } + PG_CATCH(); + { + bbf_set_current_user(prev_current_user); + PG_RE_THROW(); + } + PG_END_TRY(); - bbf_set_current_user(prev_current_user); + bbf_set_current_user(prev_current_user); - return; - } - else if (isuser || isrole) - { - /* check whether sql user name and role name contains '\' or not */ - if (isrole || !from_windows) - validateUserAndRole(stmt->role); + return; + } + else if (isuser || isrole) + { + /* + * check whether sql user name and role name contains + * '\' or not + */ + if (isrole || !from_windows) + validateUserAndRole(stmt->role); - /* Set current user to dbo user for create permissions */ - prev_current_user = GetUserNameFromId(GetUserId(), false); + /* Set current user to dbo user for create permissions */ + prev_current_user = GetUserNameFromId(GetUserId(), false); - bbf_set_current_user(get_dbo_role_name(get_cur_db_name())); + bbf_set_current_user(get_dbo_role_name(get_cur_db_name())); - PG_TRY(); - { - if (prev_ProcessUtility) - prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, - params, queryEnv, dest, - qc); - else - standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, + PG_TRY(); + { + if (prev_ProcessUtility) + prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, queryEnv, dest, qc); + else + standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, + params, queryEnv, dest, + qc); - stmt->options = list_concat(stmt->options, - user_options); - /* - * If the stmt is CREATE USER, it must have a - * corresponding login and a schema name - */ - create_bbf_authid_user_ext(stmt, isuser, isuser, from_windows); - } - PG_CATCH(); - { - bbf_set_current_user(prev_current_user); - PG_RE_THROW(); - } - PG_END_TRY(); + stmt->options = list_concat(stmt->options, + user_options); - bbf_set_current_user(prev_current_user); + /* + * If the stmt is CREATE USER, it must have a + * corresponding login and a schema name + */ + create_bbf_authid_user_ext(stmt, isuser, isuser, from_windows); + } + PG_CATCH(); + { + bbf_set_current_user(prev_current_user); + PG_RE_THROW(); + } + PG_END_TRY(); - return; + bbf_set_current_user(prev_current_user); + + return; + } } + break; } - break; - } case T_AlterRoleStmt: - { - if (sql_dialect == SQL_DIALECT_TSQL) { - AlterRoleStmt *stmt = (AlterRoleStmt *) parsetree; - List *login_options = NIL; - List *user_options = NIL; - ListCell *option; - bool islogin = false; - bool isuser = false; - bool isrole = false; - Oid prev_current_user; - - prev_current_user = GetUserId(); - - /* Check if creating login or role. Expect islogin first */ - if (stmt->options != NIL) + if (sql_dialect == SQL_DIALECT_TSQL) { - DefElem *headel = (DefElem *) linitial(stmt->options); - - /* - * Set the options list to after the head. - * Save the list of babelfish specific options. - */ - if (strcmp(headel->defname, "islogin") == 0) + AlterRoleStmt *stmt = (AlterRoleStmt *) parsetree; + List *login_options = NIL; + List *user_options = NIL; + ListCell *option; + bool islogin = false; + bool isuser = false; + bool isrole = false; + Oid prev_current_user; + + prev_current_user = GetUserId(); + + /* Check if creating login or role. Expect islogin first */ + if (stmt->options != NIL) { - islogin = true; - stmt->options = list_delete_cell(stmt->options, - list_head(stmt->options)); - pfree(headel); + DefElem *headel = (DefElem *) linitial(stmt->options); - /* Filter login options from default role options */ - foreach(option, stmt->options) + /* + * Set the options list to after the head. Save the + * list of babelfish specific options. + */ + if (strcmp(headel->defname, "islogin") == 0) { - DefElem *defel = (DefElem *) lfirst(option); + islogin = true; + stmt->options = list_delete_cell(stmt->options, + list_head(stmt->options)); + pfree(headel); - if (strcmp(defel->defname, "default_database") == 0) - login_options = lappend(login_options, defel); - } + /* Filter login options from default role options */ + foreach(option, stmt->options) + { + DefElem *defel = (DefElem *) lfirst(option); - foreach(option, login_options) - { - stmt->options = list_delete_ptr(stmt->options, - lfirst(option)); - } - } - else if (strcmp(headel->defname, "isuser") == 0) - { - isuser = true; - stmt->options = list_delete_cell(stmt->options, - list_head(stmt->options)); - pfree(headel); + if (strcmp(defel->defname, "default_database") == 0) + login_options = lappend(login_options, defel); + } - /* Filter user options from default role options */ - foreach(option, stmt->options) + foreach(option, login_options) + { + stmt->options = list_delete_ptr(stmt->options, + lfirst(option)); + } + } + else if (strcmp(headel->defname, "isuser") == 0) { - DefElem *defel = (DefElem *) lfirst(option); + isuser = true; + stmt->options = list_delete_cell(stmt->options, + list_head(stmt->options)); + pfree(headel); - if (strcmp(defel->defname, "default_schema") == 0) - user_options = lappend(user_options, defel); - if (strcmp(defel->defname, "rename") == 0) - user_options = lappend(user_options, defel); - } + /* Filter user options from default role options */ + foreach(option, stmt->options) + { + DefElem *defel = (DefElem *) lfirst(option); - foreach(option, user_options) + if (strcmp(defel->defname, "default_schema") == 0) + user_options = lappend(user_options, defel); + if (strcmp(defel->defname, "rename") == 0) + user_options = lappend(user_options, defel); + } + + foreach(option, user_options) + { + stmt->options = list_delete_ptr(stmt->options, + lfirst(option)); + } + } + else if (strcmp(headel->defname, "isrole") == 0) { - stmt->options = list_delete_ptr(stmt->options, - lfirst(option)); + isrole = true; + stmt->options = list_delete_cell(stmt->options, + list_head(stmt->options)); + pfree(headel); + + /* Filter user options from default role options */ + foreach(option, stmt->options) + { + DefElem *defel = (DefElem *) lfirst(option); + + if (strcmp(defel->defname, "rename") == 0) + user_options = lappend(user_options, defel); + } + + foreach(option, user_options) + { + stmt->options = list_delete_ptr(stmt->options, + lfirst(option)); + } } } - else if (strcmp(headel->defname, "isrole") == 0) + + if (islogin) { - isrole = true; - stmt->options = list_delete_cell(stmt->options, - list_head(stmt->options)); - pfree(headel); + Oid datdba; + bool has_password = false; + char *temp_login_name = NULL; - /* Filter user options from default role options */ + datdba = get_role_oid("sysadmin", false); + + /* + * Check if the current login has privileges to alter + * password. + */ foreach(option, stmt->options) { - DefElem *defel = (DefElem *) lfirst(option); + DefElem *defel = (DefElem *) lfirst(option); - if (strcmp(defel->defname, "rename") == 0) - user_options = lappend(user_options, defel); - } + if (strcmp(defel->defname, "password") == 0) + { + if (!is_member_of_role(GetSessionUserId(), datdba)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("Current login does not have privileges to alter password"))); - foreach(option, user_options) - { - stmt->options = list_delete_ptr(stmt->options, - lfirst(option)); + has_password = true; + } } - } - } - - if (islogin) - { - Oid datdba; - bool has_password = false; - char* temp_login_name = NULL; - - datdba = get_role_oid("sysadmin", false); - /* - * Check if the current login has privileges to - * alter password. - */ - foreach(option, stmt->options) - { - DefElem *defel = (DefElem *) lfirst(option); + /* + * Leveraging the fact that convertToUPN API returns + * the login name in UPN format if login name contains + * '\' i,e,. windows login. For windows login '\' must + * be present and for password based login '\' is not + * acceptable. So, combining these, if the login is of + * windows then it will be converted to UPN format or + * else it will be as it was + */ + temp_login_name = convertToUPN(stmt->role->rolename); - if (strcmp(defel->defname, "password") == 0) + /* + * If the previous rolname is same as current, then it + * is password based login else, it is windows based + * login. If, user is trying to alter password for + * windows login, throw error + */ + if (temp_login_name != stmt->role->rolename) { - if (!is_member_of_role(GetSessionUserId(), datdba)) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("Current login does not have privileges to alter password"))); + if (has_password) + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Cannot use parameter PASSWORD for a windows login"))); - has_password = true; + pfree(stmt->role->rolename); + stmt->role->rolename = temp_login_name; } - } - - /* - * Leveraging the fact that convertToUPN API returns the login name in UPN format - * if login name contains '\' i,e,. windows login. - * For windows login '\' must be present and for password based login '\' is not - * acceptable. So, combining these, if the login is of windows then it will be converted - * to UPN format or else it will be as it was - */ - temp_login_name = convertToUPN(stmt->role->rolename); - - /* If the previous rolname is same as current, then it is password based login - * else, it is windows based login. If, user is trying to alter password for - * windows login, throw error - */ - if (temp_login_name != stmt->role->rolename) - { - if (has_password) - ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("Cannot use parameter PASSWORD for a windows login"))); - - pfree(stmt->role->rolename); - stmt->role->rolename = temp_login_name; - } - if (get_role_oid(stmt->role->rolename, true) == InvalidOid) - ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("Cannot drop the login '%s', because it does not exist or you do not have permission.", stmt->role->rolename))); + if (get_role_oid(stmt->role->rolename, true) == InvalidOid) + ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("Cannot drop the login '%s', because it does not exist or you do not have permission.", stmt->role->rolename))); - /* Set current user to sysadmin for alter permissions */ - SetCurrentRoleId(datdba, false); + /* Set current user to sysadmin for alter permissions */ + SetCurrentRoleId(datdba, false); - PG_TRY(); - { - if (prev_ProcessUtility) - prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, - params, queryEnv, dest, - qc); - else - standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, + PG_TRY(); + { + if (prev_ProcessUtility) + prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, queryEnv, dest, qc); + else + standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, + params, queryEnv, dest, + qc); + + stmt->options = list_concat(stmt->options, + login_options); + alter_bbf_authid_login_ext(stmt); + } + PG_CATCH(); + { + SetCurrentRoleId(prev_current_user, false); + PG_RE_THROW(); + } + PG_END_TRY(); - stmt->options = list_concat(stmt->options, - login_options); - alter_bbf_authid_login_ext(stmt); - } - PG_CATCH(); - { SetCurrentRoleId(prev_current_user, false); - PG_RE_THROW(); + + return; } - PG_END_TRY(); + else if (isuser || isrole) + { + const char *db_name; + const char *dbo_name; + Oid dbo_id; - SetCurrentRoleId(prev_current_user, false); + db_name = get_cur_db_name(); + dbo_name = get_dbo_role_name(db_name); + dbo_id = get_role_oid(dbo_name, false); - return; - } - else if (isuser || isrole) - { - const char *db_name; - const char *dbo_name; - Oid dbo_id; + /* + * Check if the current user has privileges. + */ + foreach(option, user_options) + { + DefElem *defel = (DefElem *) lfirst(option); + char *user_name; + char *cur_user; - db_name = get_cur_db_name(); - dbo_name = get_dbo_role_name(db_name); - dbo_id = get_role_oid(dbo_name, false); + user_name = stmt->role->rolename; + cur_user = GetUserNameFromId(GetUserId(), false); + if (strcmp(defel->defname, "default_schema") == 0) + { + if (strcmp(cur_user, dbo_name) != 0 && + strcmp(cur_user, user_name) != 0) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("Current user does not have privileges to change schema"))); + } + if (strcmp(defel->defname, "rename") == 0) + { + if (strcmp(cur_user, dbo_name) != 0 && + strcmp(cur_user, user_name) != 0) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("Current user does not have privileges to change user name"))); + } + } - /* - * Check if the current user has privileges. - */ - foreach(option, user_options) - { - DefElem *defel = (DefElem *) lfirst(option); - char *user_name; - char *cur_user; + /* Set current user to dbo for alter permissions */ + SetCurrentRoleId(dbo_id, false); - user_name = stmt->role->rolename; - cur_user = GetUserNameFromId(GetUserId(), false); - if (strcmp(defel->defname, "default_schema") == 0) + PG_TRY(); { - if (strcmp(cur_user, dbo_name) != 0 && - strcmp(cur_user, user_name) != 0) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("Current user does not have privileges to change schema"))); + if (prev_ProcessUtility) + prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, + params, queryEnv, dest, + qc); + else + standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, + params, queryEnv, dest, + qc); + + stmt->options = list_concat(stmt->options, + user_options); + alter_bbf_authid_user_ext(stmt); } - if (strcmp(defel->defname, "rename") == 0) + PG_CATCH(); { - if (strcmp(cur_user, dbo_name) != 0 && - strcmp(cur_user, user_name) != 0) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("Current user does not have privileges to change user name"))); + SetCurrentRoleId(prev_current_user, false); + PG_RE_THROW(); } - } + PG_END_TRY(); - /* Set current user to dbo for alter permissions */ - SetCurrentRoleId(dbo_id, false); - - PG_TRY(); - { - if (prev_ProcessUtility) - prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, - params, queryEnv, dest, - qc); - else - standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, - params, queryEnv, dest, - qc); - - stmt->options = list_concat(stmt->options, - user_options); - alter_bbf_authid_user_ext(stmt); - } - PG_CATCH(); - { SetCurrentRoleId(prev_current_user, false); - PG_RE_THROW(); - } - PG_END_TRY(); + set_session_properties(db_name); - SetCurrentRoleId(prev_current_user, false); - set_session_properties(db_name); - - return; + return; + } } + break; } - break; - } case T_DropRoleStmt: - { - if (sql_dialect == SQL_DIALECT_TSQL) { - const char *prev_current_user; - DropRoleStmt *stmt = (DropRoleStmt *) parsetree; - bool drop_user = false; - bool drop_role = false; - bool all_logins = false; - bool all_users = false; - bool all_roles = false; - char *role_name = NULL; - bool other = false; - ListCell *item; - - /* Check if roles are users that need role name mapping */ - if (stmt->roles != NIL) + if (sql_dialect == SQL_DIALECT_TSQL) { - RoleSpec *headrol = linitial(stmt->roles); - - if (strcmp(headrol->rolename, "is_user") == 0) - drop_user = true; - else if (strcmp(headrol->rolename, "is_role") == 0) - drop_role = true; - - if (drop_user || drop_role) + const char *prev_current_user; + DropRoleStmt *stmt = (DropRoleStmt *) parsetree; + bool drop_user = false; + bool drop_role = false; + bool all_logins = false; + bool all_users = false; + bool all_roles = false; + char *role_name = NULL; + bool other = false; + ListCell *item; + + /* Check if roles are users that need role name mapping */ + if (stmt->roles != NIL) { - char *db_name = NULL; + RoleSpec *headrol = linitial(stmt->roles); - stmt->roles = list_delete_cell(stmt->roles, - list_head(stmt->roles)); - pfree(headrol); - headrol = NULL; - db_name = get_cur_db_name(); + if (strcmp(headrol->rolename, "is_user") == 0) + drop_user = true; + else if (strcmp(headrol->rolename, "is_role") == 0) + drop_role = true; - if (db_name != NULL && strcmp(db_name, "") != 0) + if (drop_user || drop_role) { - foreach (item, stmt->roles) + char *db_name = NULL; + + stmt->roles = list_delete_cell(stmt->roles, + list_head(stmt->roles)); + pfree(headrol); + headrol = NULL; + db_name = get_cur_db_name(); + + if (db_name != NULL && strcmp(db_name, "") != 0) { - RoleSpec *rolspec = lfirst(item); - char *user_name; + foreach(item, stmt->roles) + { + RoleSpec *rolspec = lfirst(item); + char *user_name; - user_name = get_physical_user_name(db_name, rolspec->rolename); + user_name = get_physical_user_name(db_name, rolspec->rolename); - /* - * If a role has members, do not drop it. - * Note that here we don't handle invalid roles. - */ - if (drop_role && !is_empty_role(get_role_oid(user_name, true))) - ereport(ERROR, - (errcode(ERRCODE_CHECK_VIOLATION), - errmsg("The role has members. It must be empty before it can be dropped."))); + /* + * If a role has members, do not drop it. + * Note that here we don't handle invalid + * roles. + */ + if (drop_role && !is_empty_role(get_role_oid(user_name, true))) + ereport(ERROR, + (errcode(ERRCODE_CHECK_VIOLATION), + errmsg("The role has members. It must be empty before it can be dropped."))); - /* - * If the statement is drop_user and the user is guest: - * 1. If the db is "master" or "tempdb", don't disable the guest user. - * 2. Else, disable the guest user if enabled. - * 3. Otherwise throw an error. - */ - if (drop_user && strcmp(rolspec->rolename, "guest") == 0) - { - if (guest_has_dbaccess(db_name)) + /* + * If the statement is drop_user and the + * user is guest: 1. If the db is "master" + * or "tempdb", don't disable the guest + * user. 2. Else, disable the guest user + * if enabled. 3. Otherwise throw an + * error. + */ + if (drop_user && strcmp(rolspec->rolename, "guest") == 0) { - if (strcmp(db_name, "master") == 0 || strcmp(db_name, "tempdb") == 0) + if (guest_has_dbaccess(db_name)) + { + if (strcmp(db_name, "master") == 0 || strcmp(db_name, "tempdb") == 0) + ereport(ERROR, + (errcode(ERRCODE_CHECK_VIOLATION), + errmsg("Cannot disable access to the guest user in master or tempdb."))); + + alter_user_can_connect(false, rolspec->rolename, db_name); + return; + } + else ereport(ERROR, - (errcode(ERRCODE_CHECK_VIOLATION), - errmsg("Cannot disable access to the guest user in master or tempdb."))); - - alter_user_can_connect(false, rolspec->rolename, db_name); - return; + (errcode(ERRCODE_CHECK_VIOLATION), + errmsg("User 'guest' cannot be dropped, it can only be disabled. " + "The user is already disabled in the current database."))); } - else - ereport(ERROR, - (errcode(ERRCODE_CHECK_VIOLATION), - errmsg("User 'guest' cannot be dropped, it can only be disabled. " - "The user is already disabled in the current database."))); - } - pfree(rolspec->rolename); - rolspec->rolename = user_name; + pfree(rolspec->rolename); + rolspec->rolename = user_name; + } } + else + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_DATABASE), + errmsg("Current database missing. " + "Can only drop users in current database. "))); } - else - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_DATABASE), - errmsg("Current database missing. " - "Can only drop users in current database. "))); } - } - /* List must be all one type of babelfish role. Cannot mix. */ - foreach (item, stmt->roles) - { - RoleSpec *rolspec = lfirst(item); - Form_pg_authid roleform; - HeapTuple tuple; - - role_name = rolspec->rolename; - tuple = SearchSysCache1(AUTHNAME, - PointerGetDatum(role_name)); - /* Let DropRole handle missing roles */ - if (HeapTupleIsValid(tuple)) - roleform = (Form_pg_authid) GETSTRUCT(tuple); - else + /* + * List must be all one type of babelfish role. Cannot + * mix. + */ + foreach(item, stmt->roles) { - /* Supplied login name might be in windows format i.e, domain\login form */ - if (strchr(role_name, '\\') != NULL) + RoleSpec *rolspec = lfirst(item); + Form_pg_authid roleform; + HeapTuple tuple; + + role_name = rolspec->rolename; + tuple = SearchSysCache1(AUTHNAME, + PointerGetDatum(role_name)); + /* Let DropRole handle missing roles */ + if (HeapTupleIsValid(tuple)) + roleform = (Form_pg_authid) GETSTRUCT(tuple); + else { /* - * This means that provided login name is in windows format - * so let's update role_name with UPN format. + * Supplied login name might be in windows format + * i.e, domain\login form */ - role_name = convertToUPN(role_name); - tuple = SearchSysCache1(AUTHNAME, - PointerGetDatum(role_name)); - if (HeapTupleIsValid(tuple)) + if (strchr(role_name, '\\') != NULL) { - roleform = (Form_pg_authid) GETSTRUCT(tuple); - pfree(rolspec->rolename); - rolspec->rolename = role_name; + /* + * This means that provided login name is in + * windows format so let's update role_name + * with UPN format. + */ + role_name = convertToUPN(role_name); + tuple = SearchSysCache1(AUTHNAME, + PointerGetDatum(role_name)); + if (HeapTupleIsValid(tuple)) + { + roleform = (Form_pg_authid) GETSTRUCT(tuple); + pfree(rolspec->rolename); + rolspec->rolename = role_name; + } + else + { + continue; + } } else { continue; } } - else - { - continue; - } - } - if (is_login(roleform->oid)) - all_logins = true; - else if (is_user(roleform->oid)) - all_users = true; - else if (is_role(roleform->oid)) - all_roles = true; - else - other = true; + if (is_login(roleform->oid)) + all_logins = true; + else if (is_user(roleform->oid)) + all_users = true; + else if (is_role(roleform->oid)) + all_roles = true; + else + other = true; - ReleaseSysCache(tuple); + ReleaseSysCache(tuple); - /* Only one should be true */ - if (all_logins + all_users + all_roles + other != 1) - ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("cannot mix dropping babelfish role types"))); - } - - /* If not user or role, then login */ - if (!drop_user && !drop_role) - { - int role_oid = get_role_oid(role_name, true); - if (role_oid == InvalidOid) - ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("Cannot drop the login '%s', because it does not exist or you do not have permission.", role_name))); + /* Only one should be true */ + if (all_logins + all_users + all_roles + other != 1) + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("cannot mix dropping babelfish role types"))); + } - /* Prevent if it is active login (begin used by other sessions) */ - if (is_active_login(role_oid)) - ereport(ERROR, - (errcode(ERRCODE_OBJECT_IN_USE), - errmsg("Could not drop login '%s' as the user is currently logged in.", role_name))); - } + /* If not user or role, then login */ + if (!drop_user && !drop_role) + { + int role_oid = get_role_oid(role_name, true); - if (all_logins || all_users || all_roles) - { - /* Set current user as appropriate for drop permissions */ - prev_current_user = GetUserNameFromId(GetUserId(), false); + if (role_oid == InvalidOid) + ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("Cannot drop the login '%s', because it does not exist or you do not have permission.", role_name))); - /* Only use dbo if dropping a user/role in a Babelfish session. */ - if (drop_user || drop_role) - bbf_set_current_user(get_dbo_role_name(get_cur_db_name())); - else - bbf_set_current_user("sysadmin"); + /* + * Prevent if it is active login (begin used by other + * sessions) + */ + if (is_active_login(role_oid)) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_IN_USE), + errmsg("Could not drop login '%s' as the user is currently logged in.", role_name))); + } - PG_TRY(); + if (all_logins || all_users || all_roles) { - if (prev_ProcessUtility) - prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, - params, queryEnv, dest, - qc); + /* + * Set current user as appropriate for drop + * permissions + */ + prev_current_user = GetUserNameFromId(GetUserId(), false); + + /* + * Only use dbo if dropping a user/role in a Babelfish + * session. + */ + if (drop_user || drop_role) + bbf_set_current_user(get_dbo_role_name(get_cur_db_name())); else - standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, + bbf_set_current_user("sysadmin"); + + PG_TRY(); + { + if (prev_ProcessUtility) + prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, queryEnv, dest, qc); - } - PG_CATCH(); - { - bbf_set_current_user(prev_current_user); - PG_RE_THROW(); - } - PG_END_TRY(); + else + standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, + params, queryEnv, dest, + qc); + } + PG_CATCH(); + { + bbf_set_current_user(prev_current_user); + PG_RE_THROW(); + } + PG_END_TRY(); - bbf_set_current_user(prev_current_user); + bbf_set_current_user(prev_current_user); - return; + return; + } } + break; } - break; - } case T_CreateSchemaStmt: - { - if (sql_dialect == SQL_DIALECT_TSQL) - { - CreateSchemaStmt *create_schema = (CreateSchemaStmt *) parsetree; - const char *orig_schema = NULL; - const char *grant_query = "GRANT USAGE ON SCHEMA dummy TO public"; - List *res; - GrantStmt *stmt; - PlannedStmt *wrapper; - - if (strcmp(queryString, "(CREATE LOGICAL DATABASE )") == 0 - && context == PROCESS_UTILITY_SUBCOMMAND ) + { + if (sql_dialect == SQL_DIALECT_TSQL) { - if (pstmt->stmt_len == 19) - orig_schema = "guest"; - else - orig_schema = "dbo"; - } - - if (prev_ProcessUtility) - prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, - queryEnv, dest, qc); - else - standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, - queryEnv, dest, qc); - - add_ns_ext_info(create_schema, queryString, orig_schema); + CreateSchemaStmt *create_schema = (CreateSchemaStmt *) parsetree; + const char *orig_schema = NULL; + const char *grant_query = "GRANT USAGE ON SCHEMA dummy TO public"; + List *res; + GrantStmt *stmt; + PlannedStmt *wrapper; + + if (strcmp(queryString, "(CREATE LOGICAL DATABASE )") == 0 + && context == PROCESS_UTILITY_SUBCOMMAND) + { + if (pstmt->stmt_len == 19) + orig_schema = "guest"; + else + orig_schema = "dbo"; + } - res = raw_parser(grant_query, RAW_PARSE_DEFAULT); + if (prev_ProcessUtility) + prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, + queryEnv, dest, qc); + else + standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, + queryEnv, dest, qc); - if (list_length(res) != 1) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("Expected 1 statement, but got %d statements after parsing", - list_length(res)))); - - stmt = (GrantStmt *) parsetree_nth_stmt(res, 0); - stmt->objects = list_truncate(stmt->objects, 0); - stmt->objects = lappend(stmt->objects, makeString(pstrdup(create_schema->schemaname))); - - wrapper = makeNode(PlannedStmt); - wrapper->commandType = CMD_UTILITY; - wrapper->canSetTag = false; - wrapper->utilityStmt = (Node *) stmt; - wrapper->stmt_location = pstmt->stmt_location; - wrapper->stmt_len = pstmt->stmt_len; - - ProcessUtility(wrapper, - queryString, - readOnlyTree, - PROCESS_UTILITY_SUBCOMMAND, - params, - NULL, - None_Receiver, - NULL); + add_ns_ext_info(create_schema, queryString, orig_schema); - CommandCounterIncrement(); + res = raw_parser(grant_query, RAW_PARSE_DEFAULT); - return; - } - else - break; - } - case T_DropStmt: - { - DropStmt *drop_stmt = (DropStmt *) parsetree; - if (drop_stmt->removeType != OBJECT_SCHEMA) - break; + if (list_length(res) != 1) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Expected 1 statement, but got %d statements after parsing", + list_length(res)))); + + stmt = (GrantStmt *) parsetree_nth_stmt(res, 0); + stmt->objects = list_truncate(stmt->objects, 0); + stmt->objects = lappend(stmt->objects, makeString(pstrdup(create_schema->schemaname))); + + wrapper = makeNode(PlannedStmt); + wrapper->commandType = CMD_UTILITY; + wrapper->canSetTag = false; + wrapper->utilityStmt = (Node *) stmt; + wrapper->stmt_location = pstmt->stmt_location; + wrapper->stmt_len = pstmt->stmt_len; + + ProcessUtility(wrapper, + queryString, + readOnlyTree, + PROCESS_UTILITY_SUBCOMMAND, + params, + NULL, + None_Receiver, + NULL); + + CommandCounterIncrement(); - if (sql_dialect == SQL_DIALECT_TSQL) + return; + } + else + break; + } + case T_DropStmt: { - // Prevent dropping guest schema unless it is part of drop database command. - const char *schemaname = strVal(lfirst(list_head(drop_stmt->objects))); - if (strcmp(queryString, "(DROP DATABASE )") != 0) + DropStmt *drop_stmt = (DropStmt *) parsetree; + + if (drop_stmt->removeType != OBJECT_SCHEMA) + break; + + if (sql_dialect == SQL_DIALECT_TSQL) { - char *cur_db = get_cur_db_name(); - char *guest_schema_name = get_physical_schema_name(cur_db, "guest"); + /* + * Prevent dropping guest schema unless it is part of drop + * database command. + */ + const char *schemaname = strVal(lfirst(list_head(drop_stmt->objects))); - if (strcmp(schemaname, guest_schema_name) == 0) { - ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("Cannot drop the schema \'%s\'", schemaname))); + if (strcmp(queryString, "(DROP DATABASE )") != 0) + { + char *cur_db = get_cur_db_name(); + char *guest_schema_name = get_physical_schema_name(cur_db, "guest"); + + if (strcmp(schemaname, guest_schema_name) == 0) + { + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("Cannot drop the schema \'%s\'", schemaname))); + } } - } - del_ns_ext_info(schemaname, drop_stmt->missing_ok); + del_ns_ext_info(schemaname, drop_stmt->missing_ok); - if (prev_ProcessUtility) - prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, - queryEnv, dest, qc); - else - standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, - queryEnv, dest, qc); - return; - } - else - { - if (prev_ProcessUtility) - prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, - queryEnv, dest, qc); + if (prev_ProcessUtility) + prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, + queryEnv, dest, qc); + else + standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, + queryEnv, dest, qc); + return; + } else - standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, - queryEnv, dest, qc); - check_extra_schema_restrictions(parsetree); - return; + { + if (prev_ProcessUtility) + prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, + queryEnv, dest, qc); + else + standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, + queryEnv, dest, qc); + check_extra_schema_restrictions(parsetree); + return; + } } - } case T_CreatedbStmt: - if (sql_dialect == SQL_DIALECT_TSQL) - { + if (sql_dialect == SQL_DIALECT_TSQL) + { create_bbf_db(pstate, (CreatedbStmt *) parsetree); return; } break; - case T_DropdbStmt: - if (sql_dialect == SQL_DIALECT_TSQL) - { - DropdbStmt *stmt = (DropdbStmt *) parsetree; - drop_bbf_db(stmt->dbname, stmt->missing_ok, false); + case T_DropdbStmt: + if (sql_dialect == SQL_DIALECT_TSQL) + { + DropdbStmt *stmt = (DropdbStmt *) parsetree; + + drop_bbf_db(stmt->dbname, stmt->missing_ok, false); return; - } - break; + } + break; case T_GrantRoleStmt: - if (sql_dialect == SQL_DIALECT_TSQL) - { + if (sql_dialect == SQL_DIALECT_TSQL) + { GrantRoleStmt *grant_role = (GrantRoleStmt *) parsetree; + if (is_alter_server_stmt(grant_role)) { - const char *prev_current_user; - const char *session_user_name; + const char *prev_current_user; + const char *session_user_name; check_alter_server_stmt(grant_role); prev_current_user = GetUserNameFromId(GetUserId(), false); @@ -3228,10 +3366,10 @@ static void bbf_ProcessUtility(PlannedStmt *pstmt, if (prev_ProcessUtility) prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, - queryEnv, dest, qc); + queryEnv, dest, qc); else standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, - queryEnv, dest, qc); + queryEnv, dest, qc); } PG_CATCH(); @@ -3247,8 +3385,8 @@ static void bbf_ProcessUtility(PlannedStmt *pstmt, } else if (is_alter_role_stmt(grant_role)) { - const char *prev_current_user; - const char *session_user_name; + const char *prev_current_user; + const char *session_user_name; check_alter_role_stmt(grant_role); prev_current_user = GetUserNameFromId(GetUserId(), false); @@ -3259,10 +3397,10 @@ static void bbf_ProcessUtility(PlannedStmt *pstmt, { if (prev_ProcessUtility) prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, - queryEnv, dest, qc); + queryEnv, dest, qc); else standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, - queryEnv, dest, qc); + queryEnv, dest, qc); } PG_CATCH(); @@ -3279,105 +3417,107 @@ static void bbf_ProcessUtility(PlannedStmt *pstmt, } break; case T_RenameStmt: - { - RenameStmt *stmt = (RenameStmt *) parsetree; - if (prev_ProcessUtility) - prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, - params, queryEnv, dest, qc); - else - standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, - params, queryEnv, dest, qc); - if (sql_dialect == SQL_DIALECT_TSQL) { - rename_update_bbf_catalog(stmt); - /* Clean up. Restore previous state. */ + RenameStmt *stmt = (RenameStmt *) parsetree; + + if (prev_ProcessUtility) + prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, + params, queryEnv, dest, qc); + else + standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, + params, queryEnv, dest, qc); + if (sql_dialect == SQL_DIALECT_TSQL) + { + rename_update_bbf_catalog(stmt); + /* Clean up. Restore previous state. */ + return; + } + check_extra_schema_restrictions(parsetree); + return; } - check_extra_schema_restrictions(parsetree); - - return; - } case T_CreateTableAsStmt: - { - if (sql_dialect == SQL_DIALECT_TSQL) { - CreateTableAsStmt *stmt = (CreateTableAsStmt *) parsetree; - Oid relid; - Relation rel; - TupleDesc tupdesc; - AttrNumber attr_num; - - if (prev_ProcessUtility) - prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, - queryEnv, dest, qc); - else - standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, - queryEnv, dest, qc); + if (sql_dialect == SQL_DIALECT_TSQL) + { + CreateTableAsStmt *stmt = (CreateTableAsStmt *) parsetree; + Oid relid; + Relation rel; + TupleDesc tupdesc; + AttrNumber attr_num; + + if (prev_ProcessUtility) + prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, + queryEnv, dest, qc); + else + standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, + queryEnv, dest, qc); - relid = RangeVarGetRelid(stmt->into->rel, NoLock, false); - rel = RelationIdGetRelation(relid); - tupdesc = RelationGetDescr(rel); + relid = RangeVarGetRelid(stmt->into->rel, NoLock, false); + rel = RelationIdGetRelation(relid); + tupdesc = RelationGetDescr(rel); - /* - * If table contains a rowversion column add a default node to that - * column. It is needed as table created with SELECT-INTO will not - * get the column defaults from parent table. - */ - for (attr_num = 0; attr_num < tupdesc->natts; attr_num++) - { - Form_pg_attribute attr; + /* + * If table contains a rowversion column add a default + * node to that column. It is needed as table created with + * SELECT-INTO will not get the column defaults from + * parent table. + */ + for (attr_num = 0; attr_num < tupdesc->natts; attr_num++) + { + Form_pg_attribute attr; - attr = TupleDescAttr(tupdesc, attr_num); + attr = TupleDescAttr(tupdesc, attr_num); - /* Skip dropped columns */ - if (attr->attisdropped) - continue; + /* Skip dropped columns */ + if (attr->attisdropped) + continue; - if ((*common_utility_plugin_ptr->is_tsql_rowversion_or_timestamp_datatype)(attr->atttypid)) - { - RawColumnDefault *rawEnt; - Constraint *con; - - con = get_rowversion_default_constraint(makeTypeNameFromOid(attr->atttypid, attr->atttypmod)); - rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault)); - rawEnt->attnum = attr_num + 1; - rawEnt->raw_default = (Node *) con->raw_expr; - AddRelationNewConstraints(rel, list_make1(rawEnt), NIL, - false, true, true, NULL); - break; + if ((*common_utility_plugin_ptr->is_tsql_rowversion_or_timestamp_datatype) (attr->atttypid)) + { + RawColumnDefault *rawEnt; + Constraint *con; + + con = get_rowversion_default_constraint(makeTypeNameFromOid(attr->atttypid, attr->atttypmod)); + rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault)); + rawEnt->attnum = attr_num + 1; + rawEnt->raw_default = (Node *) con->raw_expr; + AddRelationNewConstraints(rel, list_make1(rawEnt), NIL, + false, true, true, NULL); + break; + } } - } - RelationClose(rel); - return; + RelationClose(rel); + return; + } + break; } - break; - } case T_CreateStmt: { CreateStmt *create_stmt = (CreateStmt *) parsetree; - RangeVar *rel = create_stmt->relation; - bool isTableVariable = (rel->relname[0] == '@'); + RangeVar *rel = create_stmt->relation; + bool isTableVariable = (rel->relname[0] == '@'); - if(restore_tsql_tabletype) + if (restore_tsql_tabletype) create_stmt->tsql_tabletype = true; if (prev_ProcessUtility) prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, - queryEnv, dest, qc); + queryEnv, dest, qc); else standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, - queryEnv, dest, qc); + queryEnv, dest, qc); if (create_stmt->tsql_tabletype || isTableVariable) { - List *name; + List *name; if (rel->schemaname) name = list_make2(makeString(rel->schemaname), makeString(rel->relname)); else name = list_make1(makeString(rel->relname)); - + set_pgtype_byval(name, true); if (create_stmt->tsql_tabletype) @@ -3392,10 +3532,10 @@ static void bbf_ProcessUtility(PlannedStmt *pstmt, if (prev_ProcessUtility) prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, - queryEnv, dest, qc); + queryEnv, dest, qc); else standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, - queryEnv, dest, qc); + queryEnv, dest, qc); revoke_type_permission_from_public(pstmt, queryString, readOnlyTree, context, params, queryEnv, dest, qc, create_domain->domainname); return; @@ -3406,30 +3546,31 @@ static void bbf_ProcessUtility(PlannedStmt *pstmt, if (prev_ProcessUtility) prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, - queryEnv, dest, qc); + queryEnv, dest, qc); else standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, - queryEnv, dest, qc); + queryEnv, dest, qc); } /* * Update the pg_type catalog entry for the given name to have * typbyval set to the given value. */ -static void set_pgtype_byval(List *name, bool byval) +static void +set_pgtype_byval(List *name, bool byval) { Relation catalog; TypeName *typename; HeapTuple tup; - + Datum values[Natts_pg_type]; bool nulls[Natts_pg_type]; bool replaces[Natts_pg_type]; HeapTuple newtup; /* - * Table types need to set the typbyval column in pg_type to 't' - */ + * Table types need to set the typbyval column in pg_type to 't' + */ catalog = table_open(TypeRelationId, RowExclusiveLock); typename = makeTypeNameFromNameList(name); tup = typenameType(NULL, typename, NULL); @@ -3458,28 +3599,30 @@ static void set_pgtype_byval(List *name, bool byval) */ #define MD5_HASH_LEN 32 -static bool pltsql_truncate_identifier(char *ident, int len, bool warn) +static bool +pltsql_truncate_identifier(char *ident, int len, bool warn) { - char md5[MD5_HASH_LEN + 1]; - char buf[NAMEDATALEN]; - bool success; + char md5[MD5_HASH_LEN + 1]; + char buf[NAMEDATALEN]; + bool success; const char *errstr = NULL; if (sql_dialect != SQL_DIALECT_TSQL) - return false; /* will rely on existing PG behavior */ + return false; /* will rely on existing PG behavior */ Assert(len >= NAMEDATALEN); /* should be already checked */ if (tsql_is_server_collation_CI_AS()) { /* md5 should be generated by case-insensitive way */ - char *downcased_ident = downcase_identifier(ident, len, false, false); + char *downcased_ident = downcase_identifier(ident, len, false, false); + success = pg_md5_hash(downcased_ident, strlen(downcased_ident), md5, &errstr); } else success = pg_md5_hash(ident, len, md5, &errstr); - if (unlikely(!success)) /* OOM */ + if (unlikely(!success)) /* OOM */ ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("could not compute %s hash: %s", "MD5", errstr))); @@ -3500,22 +3643,26 @@ static bool pltsql_truncate_identifier(char *ident, int len, bool warn) return true; } -Name pltsql_cstr_to_name(char *s, int len) +Name +pltsql_cstr_to_name(char *s, int len) { Name result; - char buf[NAMEDATALEN]; + char buf[NAMEDATALEN]; /* Truncate oversize input */ - if (len >= NAMEDATALEN) { - if (sql_dialect == SQL_DIALECT_TSQL) { - char md5[MD5_HASH_LEN + 1]; - bool success; + if (len >= NAMEDATALEN) + { + if (sql_dialect == SQL_DIALECT_TSQL) + { + char md5[MD5_HASH_LEN + 1]; + bool success; const char *errstr = NULL; if (tsql_is_server_collation_CI_AS()) { /* md5 should be generated in a case-insensitive way */ - char *downcased_s = downcase_identifier(s, len, false, false); + char *downcased_s = downcase_identifier(s, len, false, false); + success = pg_md5_hash(downcased_s, strlen(downcased_s), md5, &errstr); } else @@ -3523,8 +3670,8 @@ Name pltsql_cstr_to_name(char *s, int len) if (unlikely(!success)) /* OOM */ ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("could not compute %s hash: %s", "MD5", errstr))); + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("could not compute %s hash: %s", "MD5", errstr))); len = pg_mbcliplen(s, len, NAMEDATALEN - MD5_HASH_LEN - 1); Assert(len + MD5_HASH_LEN < NAMEDATALEN); @@ -3535,7 +3682,9 @@ Name pltsql_cstr_to_name(char *s, int len) s = buf; len += MD5_HASH_LEN; - } else { + } + else + { /* PG default implementation */ len = pg_mbcliplen(s, len, NAMEDATALEN - 1); } @@ -3543,6 +3692,7 @@ Name pltsql_cstr_to_name(char *s, int len) /* We use palloc0 here to ensure result is zero-padded */ result = (Name) palloc0(NAMEDATALEN); + memcpy(NameStr(*result), s, len); return result; @@ -3553,29 +3703,29 @@ PG_FUNCTION_INFO_V1(pltsql_truncate_identifier_func); Datum pltsql_truncate_identifier_func(PG_FUNCTION_ARGS) { - char *name = text_to_cstring(PG_GETARG_TEXT_PP(0)); - int len = strlen(name); + char *name = text_to_cstring(PG_GETARG_TEXT_PP(0)); + int len = strlen(name); const char *saved_dialect = GetConfigOption("babelfishpg_tsql.sql_dialect", true, true); PG_TRY(); { /* this is BBF help function. use BBF truncation logic */ set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); truncate_identifier(name, len, false); } PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RE_THROW(); } PG_END_TRY(); set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_TEXT_P(cstring_to_text(name)); } @@ -3590,8 +3740,8 @@ _PG_init(void) { /* Be sure we do initialization only once (should be redundant now) */ static bool inited = false; - FunctionCallInfo fcinfo = NULL; /* empty interface */ - + FunctionCallInfo fcinfo = NULL; /* empty interface */ + if (inited) return; @@ -3602,13 +3752,13 @@ _PG_init(void) pg_bindtextdomain(TEXTDOMAIN); DefineCustomBoolVariable("babelfishpg_tsql.debug_parser", - gettext_noop("Write PL/tsql parser messages to server log (for debugging)."), - NULL, - &pltsql_debug_parser, - false, - PGC_SUSET, - GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("Write PL/tsql parser messages to server log (for debugging)."), + NULL, + &pltsql_debug_parser, + false, + PGC_SUSET, + GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomEnumVariable("babelfishpg_tsql.variable_conflict", @@ -3621,21 +3771,21 @@ _PG_init(void) NULL, NULL, NULL); DefineCustomEnumVariable("babelfishpg_tsql.schema_mapping", - gettext_noop("Sets the db schema in babelfishpg_tsql"), - NULL, - &pltsql_schema_mapping, - PLTSQL_RESOLVE_ERROR, - schema_mapping_options, - PGC_SUSET, - GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, NULL, NULL); + gettext_noop("Sets the db schema in babelfishpg_tsql"), + NULL, + &pltsql_schema_mapping, + PLTSQL_RESOLVE_ERROR, + schema_mapping_options, + PGC_SUSET, + GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); DefineCustomStringVariable("babelfishpg_tsql.identity_insert", gettext_noop("Enable inserts into identity columns."), NULL, &identity_insert_string, "", - PGC_USERSET, + PGC_USERSET, GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, NULL, assign_identity_insert, @@ -3678,14 +3828,14 @@ _PG_init(void) NULL, NULL, NULL); DefineCustomIntVariable("babelfishpg_tsql.textsize", - gettext_noop("set TEXTSIZE"), - NULL, - &text_size, - 0, -1, INT_MAX, - PGC_USERSET, - GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, - NULL, assign_textsize, NULL); - + gettext_noop("set TEXTSIZE"), + NULL, + &text_size, + 0, -1, INT_MAX, + PGC_USERSET, + GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, assign_textsize, NULL); + define_custom_variables(); EmitWarningsOnPlaceholders("pltsql"); @@ -3701,14 +3851,14 @@ _PG_init(void) assign_tablecmds_hook(); install_backend_gram_hooks(); init_catalog(fcinfo); - + /* Set up a rendezvous point with optional instrumentation plugin */ pltsql_plugin_ptr = (PLtsql_plugin **) find_rendezvous_variable("PLtsql_plugin"); pltsql_instr_plugin_ptr = (PLtsql_instr_plugin **) find_rendezvous_variable("PLtsql_instr_plugin"); /* Set up a rendezvous point with optional protocol plugin */ pltsql_protocol_plugin_ptr = (PLtsql_protocol_plugin **) - find_rendezvous_variable("PLtsql_protocol_plugin"); + find_rendezvous_variable("PLtsql_protocol_plugin"); /* If a protocol extension is loaded, initialize the inline handler. */ if (*pltsql_protocol_plugin_ptr) @@ -3716,12 +3866,12 @@ _PG_init(void) (*pltsql_protocol_plugin_ptr)->pltsql_nocount_addr = &pltsql_nocount; (*pltsql_protocol_plugin_ptr)->sql_batch_callback = &pltsql_inline_handler; (*pltsql_protocol_plugin_ptr)->sp_executesql_callback = &pltsql_inline_handler; - (*pltsql_protocol_plugin_ptr)->sp_prepare_callback = &sp_prepare; - (*pltsql_protocol_plugin_ptr)->sp_execute_callback = &pltsql_inline_handler; - (*pltsql_protocol_plugin_ptr)->sp_prepexec_callback = &pltsql_inline_handler; - (*pltsql_protocol_plugin_ptr)->sp_unprepare_callback = &sp_unprepare; - (*pltsql_protocol_plugin_ptr)->reset_session_properties = &reset_session_properties; - (*pltsql_protocol_plugin_ptr)->bulk_load_callback = &execute_bulk_load_insert; + (*pltsql_protocol_plugin_ptr)->sp_prepare_callback = &sp_prepare; + (*pltsql_protocol_plugin_ptr)->sp_execute_callback = &pltsql_inline_handler; + (*pltsql_protocol_plugin_ptr)->sp_prepexec_callback = &pltsql_inline_handler; + (*pltsql_protocol_plugin_ptr)->sp_unprepare_callback = &sp_unprepare; + (*pltsql_protocol_plugin_ptr)->reset_session_properties = &reset_session_properties; + (*pltsql_protocol_plugin_ptr)->bulk_load_callback = &execute_bulk_load_insert; (*pltsql_protocol_plugin_ptr)->pltsql_declare_var_callback = &pltsql_declare_variable; (*pltsql_protocol_plugin_ptr)->pltsql_read_out_param_callback = &pltsql_read_composite_out_param; (*pltsql_protocol_plugin_ptr)->sqlvariant_set_metadata = common_utility_plugin_ptr->TdsSetMetaData; @@ -3825,7 +3975,8 @@ _PG_init(void) cstr_to_name_hook = pltsql_cstr_to_name; tsql_has_pgstat_permissions_hook = tsql_has_pgstat_permissions; - if(pltsql_enable_linked_servers){ + if (pltsql_enable_linked_servers) + { prev_tsql_has_linked_srv_permissions_hook = tsql_has_linked_srv_permissions_hook; tsql_has_linked_srv_permissions_hook = tsql_has_linked_srv_permissions; } @@ -3882,10 +4033,11 @@ _PG_fini(void) * Also, cleanup aborted transaction here. */ -static void terminate_batch(bool send_error, bool compile_error) +static void +terminate_batch(bool send_error, bool compile_error) { - bool error_mapping_failed = false; - int rc; + bool error_mapping_failed = false; + int rc; elog(DEBUG2, "TSQL TXN finish current batch, error : %d compilation error : %d", send_error, compile_error); @@ -3897,8 +4049,9 @@ static void terminate_batch(bool send_error, bool compile_error) if (send_error) { - ErrorData *edata; + ErrorData *edata; MemoryContext oldCtx = CurrentMemoryContext; + MemoryContextSwitchTo(MessageContext); edata = CopyErrorData(); MemoryContextSwitchTo(oldCtx); @@ -3922,8 +4075,9 @@ static void terminate_batch(bool send_error, bool compile_error) /* Clean pending snapshot from portal */ if (pltsql_snapshot_portal->portalSnapshot != NULL && ActiveSnapshotSet()) { - /* Cleanup all snapshots, some might have been leaked during SPI - * execution + /* + * Cleanup all snapshots, some might have been leaked during + * SPI execution */ while (ActiveSnapshotSet()) PopActiveSnapshot(); @@ -3937,15 +4091,16 @@ static void terminate_batch(bool send_error, bool compile_error) if (compile_error && IsTransactionBlockActive()) { - if (error_mapping_failed || - is_txn_aborting_compilation_error(latest_error_code) || - (pltsql_xact_abort && is_xact_abort_txn_compilation_error(latest_error_code))) - AbortCurTransaction = true; + if (error_mapping_failed || + is_txn_aborting_compilation_error(latest_error_code) || + (pltsql_xact_abort && is_xact_abort_txn_compilation_error(latest_error_code))) + AbortCurTransaction = true; } if (AbortCurTransaction) { MemoryContext oldcontext = CurrentMemoryContext; + pltsql_xact_cb(XACT_EVENT_ABORT, NULL); PLTsqlRollbackTransaction(NULL, NULL, false); CommitTransactionCommand(); @@ -3959,13 +4114,14 @@ static void terminate_batch(bool send_error, bool compile_error) (errcode(ERRCODE_TRANSACTION_ROLLBACK), errmsg("Uncommittable transaction is detected at the end of the batch. The transaction is rolled back."))); } - else if(send_error && !IsTransactionBlockActive()) + else if (send_error && !IsTransactionBlockActive()) { /* - * In case of error without active transaction, cleanup - * active transaction state + * In case of error without active transaction, cleanup active + * transaction state */ MemoryContext oldcontext = CurrentMemoryContext; + AbortCurrentTransaction(); StartTransactionCommand(); MemoryContextSwitchTo(oldcontext); @@ -3978,12 +4134,13 @@ static void terminate_batch(bool send_error, bool compile_error) } void -static pltsql_non_tsql_proc_entry(int proc_count, int sys_func_count) +static +pltsql_non_tsql_proc_entry(int proc_count, int sys_func_count) { elog(DEBUG4, "TSQL TXN PG procedure entry PG count : %d SYS count : %d", proc_count, sys_func_count); pltsql_non_tsql_proc_entry_count += proc_count; - pltsql_sys_func_entry_count += sys_func_count; + pltsql_sys_func_entry_count += sys_func_count; } bool @@ -4020,18 +4177,18 @@ PG_FUNCTION_INFO_V1(pltsql_call_handler); Datum pltsql_call_handler(PG_FUNCTION_ARGS) { - bool nonatomic; + bool nonatomic; PLtsql_function *func; PLtsql_execstate *save_cur_estate; Datum retval; int rc; - int save_nestlevel; + int save_nestlevel; int scope_level; - MemoryContext savedPortalCxt; - bool support_tsql_trans = pltsql_support_tsql_transactions(); - Oid prev_procid = InvalidOid; - int save_pltsql_trigger_depth = pltsql_trigger_depth; - int saved_dialect = sql_dialect; + MemoryContext savedPortalCxt; + bool support_tsql_trans = pltsql_support_tsql_transactions(); + Oid prev_procid = InvalidOid; + int save_pltsql_trigger_depth = pltsql_trigger_depth; + int saved_dialect = sql_dialect; create_queryEnv2(CacheMemoryContext, false); @@ -4043,12 +4200,12 @@ pltsql_call_handler(PG_FUNCTION_ARGS) /* * Connect to SPI manager */ + /* - * Override portal context with message context when portal - * context is NULL otherwise SPI connect will create procedure - * context as top context without any parent. - * Ideally should be done inside SPI connect but is it OK - * to modify SPI connect? + * Override portal context with message context when portal context is + * NULL otherwise SPI connect will create procedure context as top context + * without any parent. Ideally should be done inside SPI connect but is it + * OK to modify SPI connect? */ savedPortalCxt = PortalContext; if (PortalContext == NULL) @@ -4065,9 +4222,9 @@ pltsql_call_handler(PG_FUNCTION_ARGS) { /* * Set the dialect to tsql - we have to do that here because the fmgr - * has set the dialect to postgres. That happens when we are validating - * a PL/tsql program because the validator function is not written in - * PL/tsql, it's written in C. + * has set the dialect to postgres. That happens when we are + * validating a PL/tsql program because the validator function is not + * written in PL/tsql, it's written in C. */ sql_dialect = SQL_DIALECT_TSQL; @@ -4087,25 +4244,30 @@ pltsql_call_handler(PG_FUNCTION_ARGS) PG_TRY(); { set_procid(func->fn_oid); + /* * Determine if called as function or trigger and call appropriate * subhandler */ - if (CALLED_AS_TRIGGER(fcinfo)){ - if (!pltsql_recursive_triggers && save_cur_estate!=NULL - && is_recursive_trigger(save_cur_estate)){ + if (CALLED_AS_TRIGGER(fcinfo)) + { + if (!pltsql_recursive_triggers && save_cur_estate != NULL + && is_recursive_trigger(save_cur_estate)) + { retval = (Datum) 0; - }else{ + } + else + { pltsql_trigger_depth++; retval = PointerGetDatum(pltsql_exec_trigger(func, - (TriggerData *) fcinfo->context)); + (TriggerData *) fcinfo->context)); pltsql_trigger_depth = save_pltsql_trigger_depth; } } else if (CALLED_AS_EVENT_TRIGGER(fcinfo)) { pltsql_exec_event_trigger(func, - (EventTriggerData *) fcinfo->context); + (EventTriggerData *) fcinfo->context); retval = (Datum) 0; } else @@ -4124,7 +4286,7 @@ pltsql_call_handler(PG_FUNCTION_ARGS) remove_queryEnv(); pltsql_revert_guc(save_nestlevel); pltsql_revert_last_scope_identity(scope_level); - terminate_batch(true /* send_error */, false /* compile_error */); + terminate_batch(true /* send_error */ , false /* compile_error */ ); sql_dialect = saved_dialect; return retval; } @@ -4145,7 +4307,7 @@ pltsql_call_handler(PG_FUNCTION_ARGS) pltsql_revert_guc(save_nestlevel); pltsql_revert_last_scope_identity(scope_level); - terminate_batch(false /* send_error */, false /* compile_error */); + terminate_batch(false /* send_error */ , false /* compile_error */ ); return retval; } @@ -4160,26 +4322,27 @@ pltsql_call_handler(PG_FUNCTION_ARGS) Datum pltsql_inline_handler(PG_FUNCTION_ARGS) { - InlineCodeBlock *codeblock = castNode(InlineCodeBlock, DatumGetPointer(PG_GETARG_DATUM(0))); - InlineCodeBlockArgs *codeblock_args = NULL; - PLtsql_function *func; - FmgrInfo flinfo; - EState *simple_eval_estate; - Datum retval; + InlineCodeBlock *codeblock = castNode(InlineCodeBlock, DatumGetPointer(PG_GETARG_DATUM(0))); + InlineCodeBlockArgs *codeblock_args = NULL; + PLtsql_function *func; + FmgrInfo flinfo; + EState *simple_eval_estate; + Datum retval; int rc; int saved_dialect = sql_dialect; int nargs = PG_NARGS(); - int i; - MemoryContext savedPortalCxt; + int i; + MemoryContext savedPortalCxt; FunctionCallInfo fake_fcinfo = palloc0(SizeForFunctionCallInfo(nargs)); - bool nonatomic; - bool support_tsql_trans = pltsql_support_tsql_transactions(); - ReturnSetInfo rsinfo; /* for INSERT ... EXECUTE */ - - /* - * FIXME: We leak sp_describe_first_result_set_inprogress if CREATE VIEW fails - * internally when executing sp_describe_first_result_set procedure. So we - * reset sp_describe_first_result_set_inprogress here to work around this. + bool nonatomic; + bool support_tsql_trans = pltsql_support_tsql_transactions(); + ReturnSetInfo rsinfo; /* for INSERT ... EXECUTE */ + + /* + * FIXME: We leak sp_describe_first_result_set_inprogress if CREATE VIEW + * fails internally when executing sp_describe_first_result_set procedure. + * So we reset sp_describe_first_result_set_inprogress here to work around + * this. */ sp_describe_first_result_set_inprogress = false; @@ -4198,7 +4361,7 @@ pltsql_inline_handler(PG_FUNCTION_ARGS) codeblock_args = (InlineCodeBlockArgs *) DatumGetPointer(PG_GETARG_DATUM(1)); sql_dialect = SQL_DIALECT_TSQL; - + /* * Connect to SPI manager */ @@ -4221,7 +4384,7 @@ pltsql_inline_handler(PG_FUNCTION_ARGS) func = find_cached_batch(codeblock_args->handle); if (!func) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("Prepared statement not found: %d", codeblock_args->handle))); + errmsg("Prepared statement not found: %d", codeblock_args->handle))); /* Mark the function as busy, just pro forma */ func->use_count++; } @@ -4238,9 +4401,10 @@ pltsql_inline_handler(PG_FUNCTION_ARGS) if (OPTION_ENABLED(codeblock_args, NO_EXEC)) { func->use_count--; + /* - * Disconnect from SPI manager - */ + * Disconnect from SPI manager + */ if ((rc = SPI_finish()) != SPI_OK_FINISH) elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc)); @@ -4252,10 +4416,11 @@ pltsql_inline_handler(PG_FUNCTION_ARGS) } PG_CATCH(); { - terminate_batch(true /* send_error */, true /* compile_error */); + terminate_batch(true /* send_error */ , true /* compile_error */ ); return retval; } PG_END_TRY(); + /* * Set up a fake fcinfo with just enough info to satisfy * pltsql_exec_function(). In particular note that this sets things up @@ -4286,12 +4451,12 @@ pltsql_inline_handler(PG_FUNCTION_ARGS) */ if (codeblock->relation && codeblock->attrnos) { - Oid reltypeid; - TupleDesc reldesc; - TupleDesc retdesc; - int natts = 0; - ListCell *lc; - ListCell *next; + Oid reltypeid; + TupleDesc reldesc; + TupleDesc retdesc; + int natts = 0; + ListCell *lc; + ListCell *next; /* look up the INSERT target relation rowtype's tupdesc */ reltypeid = get_rel_type_id(codeblock->relation); @@ -4321,10 +4486,13 @@ pltsql_inline_handler(PG_FUNCTION_ARGS) /* And run the function */ PG_TRY(); { - /* If the number of arguments supplied are not equal to what is expected then throw error. */ + /* + * If the number of arguments supplied are not equal to what is + * expected then throw error. + */ if (fake_fcinfo->nargs != func->fn_nargs) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("The parameterized query expects %d number of parameters, but %d were supplied", func->fn_nargs, fake_fcinfo->nargs))); + errmsg("The parameterized query expects %d number of parameters, but %d were supplied", func->fn_nargs, fake_fcinfo->nargs))); retval = pltsql_exec_function(func, fake_fcinfo, simple_eval_estate, codeblock->atomic); fcinfo->isnull = false; @@ -4339,8 +4507,8 @@ pltsql_inline_handler(PG_FUNCTION_ARGS) * private EState. * * Before releasing the private EState, we must clean up any - * simple_econtext_stack entries pointing into it. It is done - * inside pltsql_exec_function + * simple_econtext_stack entries pointing into it. It is done inside + * pltsql_exec_function */ /* Function should now have no remaining use-counts ... */ @@ -4356,7 +4524,7 @@ pltsql_inline_handler(PG_FUNCTION_ARGS) } sql_dialect = saved_dialect; - terminate_batch(true /* send_error */, false /* compile_error */); + terminate_batch(true /* send_error */ , false /* compile_error */ ); return retval; } PG_END_TRY(); @@ -4364,13 +4532,14 @@ pltsql_inline_handler(PG_FUNCTION_ARGS) if (codeblock->dest && rsinfo.setDesc && rsinfo.setResult) { /* - * If we are here for INSERT ... EXECUTE, send all tuples accumulated in - * resultinfo to the DestReceiver, which will later be consumed by the - * INSERT execution. + * If we are here for INSERT ... EXECUTE, send all tuples accumulated + * in resultinfo to the DestReceiver, which will later be consumed by + * the INSERT execution. */ TupleTableSlot *slot = MakeSingleTupleTableSlot(rsinfo.expectedDesc, &TTSOpsMinimalTuple); - DestReceiver *dest = (DestReceiver *)codeblock->dest; + DestReceiver *dest = (DestReceiver *) codeblock->dest; + for (;;) { if (!tuplestore_gettupleslot(rsinfo.setResult, true, false, slot)) @@ -4392,8 +4561,8 @@ pltsql_inline_handler(PG_FUNCTION_ARGS) pltsql_free_function_memory(func); } sql_dialect = saved_dialect; - - terminate_batch(false /* send_error */, false /* compile_error */); + + terminate_batch(false /* send_error */ , false /* compile_error */ ); return retval; } @@ -4421,11 +4590,12 @@ pltsql_validator(PG_FUNCTION_ARGS) bool is_dml_trigger = false; bool is_event_trigger = false; int i; + /* Special handling is neede for Inline Table-Valued Functions */ - bool is_itvf; - char *prosrc = NULL; + bool is_itvf; + char *prosrc = NULL; MemoryContext oldMemoryContext = CurrentMemoryContext; - int saved_dialect = sql_dialect; + int saved_dialect = sql_dialect; if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid)) PG_RETURN_VOID(); @@ -4438,14 +4608,14 @@ pltsql_validator(PG_FUNCTION_ARGS) /* Disallow text, ntext, and image type result */ if (!babelfish_dump_restore && - ((*common_utility_plugin_ptr->is_tsql_text_datatype)(proc->prorettype) || - (*common_utility_plugin_ptr->is_tsql_ntext_datatype)(proc->prorettype) || - (*common_utility_plugin_ptr->is_tsql_image_datatype)(proc->prorettype))) + ((*common_utility_plugin_ptr->is_tsql_text_datatype) (proc->prorettype) || + (*common_utility_plugin_ptr->is_tsql_ntext_datatype) (proc->prorettype) || + (*common_utility_plugin_ptr->is_tsql_image_datatype) (proc->prorettype))) { ereport(ERROR, - (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), - errmsg("PL/tsql functions cannot return type %s", - format_type_be(proc->prorettype)))); + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("PL/tsql functions cannot return type %s", + format_type_be(proc->prorettype)))); } functyptype = get_typtype(proc->prorettype); @@ -4488,21 +4658,21 @@ pltsql_validator(PG_FUNCTION_ARGS) } is_itvf = proc->prokind == PROKIND_FUNCTION && proc->proretset && - get_typtype(proc->prorettype) != TYPTYPE_COMPOSITE; + get_typtype(proc->prorettype) != TYPTYPE_COMPOSITE; PG_TRY(); { /* * Set the dialect to tsql - we have to do that here because the fmgr - * has set the dialect to postgres. That happens when we are validating - * a PL/tsql program because the validator function is not written in - * PL/tsql, it's written in C. + * has set the dialect to postgres. That happens when we are + * validating a PL/tsql program because the validator function is not + * written in PL/tsql, it's written in C. */ sql_dialect = SQL_DIALECT_TSQL; /* - * Postpone body checks if !check_function_bodies, except for - * itvf which we always needs to test-compile to record the query. + * Postpone body checks if !check_function_bodies, except for itvf + * which we always needs to test-compile to record the query. */ if (check_function_bodies || is_itvf) { @@ -4545,22 +4715,27 @@ pltsql_validator(PG_FUNCTION_ARGS) if (is_itvf && !babelfish_dump_restore) { PLtsql_stmt_return_query *returnQueryStmt; + /* - * For inline table-valued function, we need to record its query so - * that we can construct the column definition list. + * For inline table-valued function, we need to record its + * query so that we can construct the column definition list. */ func = pltsql_compile(fake_fcinfo, true); returnQueryStmt = (PLtsql_stmt_return_query *) linitial(func->action->body); - /* ITVF should contain 2 statements - RETURN QUERY and PUSH RESULT */ + /* + * ITVF should contain 2 statements - RETURN QUERY and PUSH + * RESULT + */ if (list_length(func->action->body) != 2 || (returnQueryStmt && returnQueryStmt->cmd_type != PLTSQL_STMT_RETURN_QUERY)) ereport(ERROR, (errcode(ERRCODE_RESTRICT_VIOLATION), - errmsg("Inline table-valued function must have a single RETURN SELECT statement"))); + errmsg("Inline table-valued function must have a single RETURN SELECT statement"))); prosrc = MemoryContextStrdup(oldMemoryContext, returnQueryStmt->query->itvf_query); - } else + } + else func = pltsql_compile(fake_fcinfo, true); /* @@ -4574,36 +4749,36 @@ pltsql_validator(PG_FUNCTION_ARGS) /* * For inline table-valued function, we need to construct the column - * definition list by planning the query in the function, and modifying the - * pg_proc entry for this function. + * definition list by planning the query in the function, and + * modifying the pg_proc entry for this function. */ if (is_itvf && !babelfish_dump_restore) { - SPIPlanPtr spi_plan; - int spi_rc; - Relation rel; - HeapTuple tup; - HeapTuple oldtup; - bool nulls[Natts_pg_proc]; - Datum values[Natts_pg_proc]; - bool replaces[Natts_pg_proc]; - TupleDesc tupDesc; - ArrayType *allParameterTypesPointer; - ArrayType *parameterModesPointer; - ArrayType *parameterNamesPointer; - Datum *allTypesNew; - Datum *paramModesNew; - Datum *paramNamesNew; - int parameterCountNew; - List *plansources; + SPIPlanPtr spi_plan; + int spi_rc; + Relation rel; + HeapTuple tup; + HeapTuple oldtup; + bool nulls[Natts_pg_proc]; + Datum values[Natts_pg_proc]; + bool replaces[Natts_pg_proc]; + TupleDesc tupDesc; + ArrayType *allParameterTypesPointer; + ArrayType *parameterModesPointer; + ArrayType *parameterNamesPointer; + Datum *allTypesNew; + Datum *paramModesNew; + Datum *paramNamesNew; + int parameterCountNew; + List *plansources; CachedPlanSource *plansource; - Query *query; - TupleDesc tupdesc; - int targetListLength; - ListCell *lc; + Query *query; + TupleDesc tupdesc; + int targetListLength; + ListCell *lc; MemoryContext SPIMemoryContext; - Oid rettypeNew = InvalidOid; - int numresjunks = 0; + Oid rettypeNew = InvalidOid; + int numresjunks = 0; if ((spi_rc = SPI_connect()) != SPI_OK_CONNECT) elog(ERROR, "SPI_connect() failed in pltsql_validator with return code %d", spi_rc); @@ -4611,7 +4786,7 @@ pltsql_validator(PG_FUNCTION_ARGS) spi_plan = SPI_prepare(prosrc, numargs, argtypes); if (spi_plan == NULL) elog(WARNING, "SPI_prepare_params failed for \"%s\": %s", - prosrc, SPI_result_code_string(SPI_result)); + prosrc, SPI_result_code_string(SPI_result)); plansources = SPI_plan_get_plan_sources(spi_plan); Assert(list_length(plansources) == 1); @@ -4652,14 +4827,14 @@ pltsql_validator(PG_FUNCTION_ARGS) foreach(lc, query->targetList) { TargetEntry *te = (TargetEntry *) lfirst(lc); - int new_i; - Oid new_type; - ListCell *prev_lc; + int new_i; + Oid new_type; + ListCell *prev_lc; /* - * If resjunk is true then the column is a working column and should - * be removed from the final output of the query, according to the - * definition of TargetEntry. + * If resjunk is true then the column is a working column and + * should be removed from the final output of the query, + * according to the definition of TargetEntry. */ if (te->resjunk) { @@ -4674,8 +4849,8 @@ pltsql_validator(PG_FUNCTION_ARGS) pfree(paramModesNew); pfree(paramNamesNew); elog(ERROR, - "CREATE FUNCTION failed because a column name is not specified for column %d", - i+1); + "CREATE FUNCTION failed because a column name is not specified for column %d", + i + 1); } foreach(prev_lc, query->targetList) @@ -4689,15 +4864,15 @@ pltsql_validator(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("parameter name \"%s\" used more than once", - te->resname))); + te->resname))); } new_i = i + numargs; new_type = SPI_gettypeid(tupdesc, te->resno); /* - * Record the type in case we need to change the function return - * type to it later + * Record the type in case we need to change the function + * return type to it later */ rettypeNew = new_type; @@ -4712,10 +4887,10 @@ pltsql_validator(PG_FUNCTION_ARGS) elog(ERROR, "SPI_finish() failed in pltsql_validator with return code %d", spi_rc); /* - * For table functions whose return table only has one column, Postgres - * considers them as scalar functions. So, we need to update the - * function's return type to be the type of that column, instead of - * RECORD. + * For table functions whose return table only has one column, + * Postgres considers them as scalar functions. So, we need to + * update the function's return type to be the type of that + * column, instead of RECORD. */ if (i == 1) { @@ -4725,7 +4900,7 @@ pltsql_validator(PG_FUNCTION_ARGS) parameterCountNew -= numresjunks; allParameterTypesPointer = construct_array(allTypesNew, parameterCountNew, OIDOID, - sizeof(Oid), true, 'i'); + sizeof(Oid), true, 'i'); parameterModesPointer = construct_array(paramModesNew, parameterCountNew, CHAROID, 1, true, 'c'); parameterNamesPointer = construct_array(paramNamesNew, parameterCountNew, TEXTOID, @@ -4769,7 +4944,7 @@ pltsql_validator(PG_FUNCTION_ARGS) static void get_language_procs(const char *langname, Oid *compiler, Oid *validator) { - HeapTuple langTup = SearchSysCache1(LANGNAME, PointerGetDatum(langname)); + HeapTuple langTup = SearchSysCache1(LANGNAME, PointerGetDatum(langname)); if (HeapTupleIsValid(langTup)) { @@ -4859,75 +5034,75 @@ canCommitTransaction(void) static void pltsql_guc_push_old_value(struct config_generic *gconf, GucAction action) { - GucStack *stack; - - /* If we're not inside a nest level, do nothing */ - if (PltsqlGUCNestLevel == 0) - return; - - /* Do we already have a stack entry of the current nest level? */ - stack = gconf->session_stack; - if (stack && stack->nest_level >= PltsqlGUCNestLevel) - { - /* Yes, so adjust its state if necessary */ - Assert(stack->nest_level == PltsqlGUCNestLevel); - switch (action) - { - case GUC_ACTION_SET: - stack->state = GUC_SET; - break; - case GUC_ACTION_SAVE: - stack->state = GUC_SAVE; - break; - default : - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Set action not supported"))); - } - Assert(pltsql_guc_dirty); - return; - } - - /* - * Push a new stack entry - * - */ - stack = (GucStack *) MemoryContextAllocZero(TopMemoryContext, - sizeof(GucStack)); - - stack->prev = gconf->session_stack; - stack->nest_level = PltsqlGUCNestLevel; - switch (action) - { - case GUC_ACTION_SET: - stack->state = GUC_SET; - break; - case GUC_ACTION_SAVE: - stack->state = GUC_SAVE; - break; - default : - Assert(false); - } - stack->source = gconf->source; - stack->scontext = gconf->scontext; - guc_set_stack_value(gconf, &stack->prior); - - gconf->session_stack = stack; - pltsql_guc_dirty = true; + GucStack *stack; + + /* If we're not inside a nest level, do nothing */ + if (PltsqlGUCNestLevel == 0) + return; + + /* Do we already have a stack entry of the current nest level? */ + stack = gconf->session_stack; + if (stack && stack->nest_level >= PltsqlGUCNestLevel) + { + /* Yes, so adjust its state if necessary */ + Assert(stack->nest_level == PltsqlGUCNestLevel); + switch (action) + { + case GUC_ACTION_SET: + stack->state = GUC_SET; + break; + case GUC_ACTION_SAVE: + stack->state = GUC_SAVE; + break; + default: + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Set action not supported"))); + } + Assert(pltsql_guc_dirty); + return; + } + + /* + * Push a new stack entry + * + */ + stack = (GucStack *) MemoryContextAllocZero(TopMemoryContext, + sizeof(GucStack)); + + stack->prev = gconf->session_stack; + stack->nest_level = PltsqlGUCNestLevel; + switch (action) + { + case GUC_ACTION_SET: + stack->state = GUC_SET; + break; + case GUC_ACTION_SAVE: + stack->state = GUC_SAVE; + break; + default: + Assert(false); + } + stack->source = gconf->source; + stack->scontext = gconf->scontext; + guc_set_stack_value(gconf, &stack->prior); + + gconf->session_stack = stack; + pltsql_guc_dirty = true; } int pltsql_new_guc_nest_level(void) { - return ++PltsqlGUCNestLevel; + return ++PltsqlGUCNestLevel; } void pltsql_revert_guc(int nest_level) { - bool still_dirty; - int i; - int num_guc_variables; + bool still_dirty; + int i; + int num_guc_variables; struct config_generic **guc_variables; Assert(nest_level > 0 && nest_level == PltsqlGUCNestLevel); @@ -4945,7 +5120,7 @@ pltsql_revert_guc(int nest_level) for (i = 0; i < num_guc_variables; i++) { struct config_generic *gconf = guc_variables[i]; - GucStack *stack = gconf->session_stack; + GucStack *stack = gconf->session_stack; if (stack != NULL && stack->nest_level == nest_level) { @@ -4953,107 +5128,109 @@ pltsql_revert_guc(int nest_level) /* Perform appropriate restoration of the stacked value */ config_var_value newvalue = stack->prior; - GucSource newsource = stack->source; - GucContext newscontext = stack->scontext; + GucSource newsource = stack->source; + GucContext newscontext = stack->scontext; switch (gconf->vartype) { case PGC_BOOL: - { - struct config_bool *conf = (struct config_bool *) gconf; - bool newval = newvalue.val.boolval; - void *newextra = newvalue.extra; - - if (*conf->variable != newval || conf->gen.extra != newextra) { - if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - guc_set_extra_field(&conf->gen, &conf->gen.extra, newextra); + struct config_bool *conf = (struct config_bool *) gconf; + bool newval = newvalue.val.boolval; + void *newextra = newvalue.extra; + + if (*conf->variable != newval || conf->gen.extra != newextra) + { + if (conf->assign_hook) + conf->assign_hook(newval, newextra); + *conf->variable = newval; + guc_set_extra_field(&conf->gen, &conf->gen.extra, newextra); + } + break; } - break; - } case PGC_INT: - { - struct config_int *conf = (struct config_int *) gconf; - int newval = newvalue.val.intval; - void *newextra = newvalue.extra; - - if (*conf->variable != newval || conf->gen.extra != newextra) { - if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - guc_set_extra_field(&conf->gen, &conf->gen.extra, newextra); + struct config_int *conf = (struct config_int *) gconf; + int newval = newvalue.val.intval; + void *newextra = newvalue.extra; + + if (*conf->variable != newval || conf->gen.extra != newextra) + { + if (conf->assign_hook) + conf->assign_hook(newval, newextra); + *conf->variable = newval; + guc_set_extra_field(&conf->gen, &conf->gen.extra, newextra); + } + break; } - break; - } case PGC_REAL: - { - struct config_real *conf = (struct config_real *) gconf; - double newval = newvalue.val.realval; - void *newextra = newvalue.extra; - - if (*conf->variable != newval || conf->gen.extra != newextra) { - if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - guc_set_extra_field(&conf->gen, &conf->gen.extra, newextra); + struct config_real *conf = (struct config_real *) gconf; + double newval = newvalue.val.realval; + void *newextra = newvalue.extra; + + if (*conf->variable != newval || conf->gen.extra != newextra) + { + if (conf->assign_hook) + conf->assign_hook(newval, newextra); + *conf->variable = newval; + guc_set_extra_field(&conf->gen, &conf->gen.extra, newextra); + } + break; } - break; - } case PGC_STRING: - { - struct config_string *conf = (struct config_string *) gconf; - char *newval = newvalue.val.stringval; - void *newextra = newvalue.extra; - - /* Special case for identity_insert */ - if (strcmp(gconf->name, "babelfishpg_tsql.identity_insert") == 0) { - tsql_identity_insert = (tsql_identity_insert_fields) - {false, InvalidOid, InvalidOid}; - } + struct config_string *conf = (struct config_string *) gconf; + char *newval = newvalue.val.stringval; + void *newextra = newvalue.extra; - if (*conf->variable != newval || conf->gen.extra != newextra) - { - if (conf->assign_hook) - conf->assign_hook(newval, newextra); - guc_set_string_field(conf, conf->variable, newval); - guc_set_extra_field(&conf->gen, &conf->gen.extra, newextra); - } + /* Special case for identity_insert */ + if (strcmp(gconf->name, "babelfishpg_tsql.identity_insert") == 0) + { + tsql_identity_insert = (tsql_identity_insert_fields) + { + false, InvalidOid, InvalidOid + }; + } - /* - * Release stacked values if not used anymore. We - * could use discard_stack_value() here, but since - * we have type-specific code anyway, might as - * well inline it. - */ - guc_set_string_field(conf, &stack->prior.val.stringval, NULL); - guc_set_string_field(conf, &stack->masked.val.stringval, NULL); - break; - } - case PGC_ENUM: - { - struct config_enum *conf = (struct config_enum *) gconf; - int newval = newvalue.val.enumval; - void *newextra = newvalue.extra; + if (*conf->variable != newval || conf->gen.extra != newextra) + { + if (conf->assign_hook) + conf->assign_hook(newval, newextra); + guc_set_string_field(conf, conf->variable, newval); + guc_set_extra_field(&conf->gen, &conf->gen.extra, newextra); + } - if (*conf->variable != newval || conf->gen.extra != newextra) + /* + * Release stacked values if not used anymore. We + * could use discard_stack_value() here, but since we + * have type-specific code anyway, might as well + * inline it. + */ + guc_set_string_field(conf, &stack->prior.val.stringval, NULL); + guc_set_string_field(conf, &stack->masked.val.stringval, NULL); + break; + } + case PGC_ENUM: { - if (conf->assign_hook) - conf->assign_hook(newval, newextra); - *conf->variable = newval; - guc_set_extra_field(&conf->gen, &conf->gen.extra, newextra); + struct config_enum *conf = (struct config_enum *) gconf; + int newval = newvalue.val.enumval; + void *newextra = newvalue.extra; + + if (*conf->variable != newval || conf->gen.extra != newextra) + { + if (conf->assign_hook) + conf->assign_hook(newval, newextra); + *conf->variable = newval; + guc_set_extra_field(&conf->gen, &conf->gen.extra, newextra); + } + break; } - break; - } } /* - * Release stacked extra values if not used anymore. - */ + * Release stacked extra values if not used anymore. + */ guc_set_extra_field(gconf, &(stack->prior.extra), NULL); guc_set_extra_field(gconf, &(stack->masked.extra), NULL); @@ -5064,7 +5241,7 @@ pltsql_revert_guc(int nest_level) /* Finish popping the state stack */ gconf->session_stack = prev; pfree(stack); - } /* end of stack-popping loop */ + } /* end of stack-popping loop */ if (stack != NULL) still_dirty = true; @@ -5086,12 +5263,13 @@ set_current_query_is_create_tbl_check_constraint(Node *expr) foreach(elements, stmt->tableElts) { - Node *element = lfirst(elements); + Node *element = lfirst(elements); if (nodeTag(element) == T_Constraint) { Constraint *c = (Constraint *) element; - if(c->contype == CONSTR_CHECK) + + if (c->contype == CONSTR_CHECK) { current_query_is_create_tbl_check_constraint = true; break; diff --git a/contrib/babelfishpg_tsql/src/pl_reserved_kwlist.h b/contrib/babelfishpg_tsql/src/pl_reserved_kwlist.h index f2edd49fdc..ecc67ea232 100644 --- a/contrib/babelfishpg_tsql/src/pl_reserved_kwlist.h +++ b/contrib/babelfishpg_tsql/src/pl_reserved_kwlist.h @@ -14,9 +14,9 @@ * *------------------------------------------------------------------------- */ - + /* There is deliberately not an #ifndef PL_RESERVED_KWLIST_H here. */ - + /* * List of (keyword-name, keyword-token-value) pairs. * @@ -25,7 +25,7 @@ * !!WARNING!!: This list must be sorted by ASCII name, because binary * search is used to locate entries. */ - + /* name, value */ PG_KEYWORD("all", K_ALL) PG_KEYWORD("as", K_AS) diff --git a/contrib/babelfishpg_tsql/src/pl_scanner.c b/contrib/babelfishpg_tsql/src/pl_scanner.c index f6439f1191..3f6a547b60 100644 --- a/contrib/babelfishpg_tsql/src/pl_scanner.c +++ b/contrib/babelfishpg_tsql/src/pl_scanner.c @@ -64,7 +64,7 @@ IdentifierLookup pltsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL; /* Token codes for PL/pgSQL keywords */ #define PG_KEYWORD(kwname, value) value, - + static const uint16 ReservedPLKeywordTokens[] = { #include "pl_reserved_kwlist.h" }; @@ -130,7 +130,7 @@ static const char *cur_line_end; static int cur_line_num; /* Initialise the global variable declared in err_handler.h */ -int CurrentLineNumber = 1; +int CurrentLineNumber = 1; /* Internal functions */ static int internal_yylex(TokenAuxData *auxdata); @@ -186,10 +186,10 @@ pltsql_yylex(void) if (tok5 == IDENT) { if (pltsql_parse_tripword(aux1.lval.str, - aux3.lval.str, - aux5.lval.str, - &aux1.lval.wdatum, - &aux1.lval.cword)) + aux3.lval.str, + aux5.lval.str, + &aux1.lval.wdatum, + &aux1.lval.cword)) tok1 = T_DATUM; else tok1 = T_CWORD; @@ -200,9 +200,9 @@ pltsql_yylex(void) push_back_token(tok5, &aux5); push_back_token(tok4, &aux4); if (pltsql_parse_dblword(aux1.lval.str, - aux3.lval.str, - &aux1.lval.wdatum, - &aux1.lval.cword)) + aux3.lval.str, + &aux1.lval.wdatum, + &aux1.lval.cword)) tok1 = T_DATUM; else tok1 = T_CWORD; @@ -213,9 +213,9 @@ pltsql_yylex(void) /* not A.B.C, so just process A.B */ push_back_token(tok4, &aux4); if (pltsql_parse_dblword(aux1.lval.str, - aux3.lval.str, - &aux1.lval.wdatum, - &aux1.lval.cword)) + aux3.lval.str, + &aux1.lval.wdatum, + &aux1.lval.cword)) tok1 = T_DATUM; else tok1 = T_CWORD; @@ -227,12 +227,12 @@ pltsql_yylex(void) push_back_token(tok3, &aux3); push_back_token(tok2, &aux2); if (pltsql_parse_word(aux1.lval.str, - core_yy.scanbuf + aux1.lloc, - &aux1.lval.wdatum, - &aux1.lval.word)) + core_yy.scanbuf + aux1.lloc, + &aux1.lval.wdatum, + &aux1.lval.word)) tok1 = T_DATUM; else if (!aux1.lval.word.quoted && - (kwnum = ScanKeywordLookup(aux1.lval.word.ident, + (kwnum = ScanKeywordLookup(aux1.lval.word.ident, &UnreservedPLKeywords)) >= 0) { aux1.lval.keyword = GetScanKeyword(kwnum, @@ -263,16 +263,16 @@ pltsql_yylex(void) /* try for unreserved keyword, then for variable name */ if (core_yy.scanbuf[aux1.lloc] != '"' && (kwnum = ScanKeywordLookup(aux1.lval.str, - &UnreservedPLKeywords)) >= 0) + &UnreservedPLKeywords)) >= 0) { aux1.lval.keyword = GetScanKeyword(kwnum, &UnreservedPLKeywords); tok1 = UnreservedPLKeywordTokens[kwnum]; } else if (pltsql_parse_word(aux1.lval.str, - core_yy.scanbuf + aux1.lloc, - &aux1.lval.wdatum, - &aux1.lval.word)) + core_yy.scanbuf + aux1.lloc, + &aux1.lval.wdatum, + &aux1.lval.word)) tok1 = T_DATUM; else tok1 = T_WORD; @@ -281,16 +281,16 @@ pltsql_yylex(void) { /* try for variable name, then for unreserved keyword */ if (pltsql_parse_word(aux1.lval.str, - core_yy.scanbuf + aux1.lloc, - &aux1.lval.wdatum, - &aux1.lval.word)) + core_yy.scanbuf + aux1.lloc, + &aux1.lval.wdatum, + &aux1.lval.word)) tok1 = T_DATUM; else if (!aux1.lval.word.quoted && (kwnum = ScanKeywordLookup(aux1.lval.word.ident, - &UnreservedPLKeywords)) >= 0) + &UnreservedPLKeywords)) >= 0) { aux1.lval.keyword = GetScanKeyword(kwnum, - &UnreservedPLKeywords); + &UnreservedPLKeywords); tok1 = UnreservedPLKeywordTokens[kwnum]; } else @@ -301,20 +301,21 @@ pltsql_yylex(void) else if (tok1 == K_BEGIN) { TokenAuxData aux2; - int tok2 = internal_yylex(&aux2); + int tok2 = internal_yylex(&aux2); + if (tok2 == IDENT && (strcasecmp(aux2.lval.str, "transaction") == 0 || - strcasecmp(aux2.lval.str, "tran") == 0)) + strcasecmp(aux2.lval.str, "tran") == 0)) tok1 = T_WORD; push_back_token(tok2, &aux2); } else if (tok1 == K_END) { /* - * We've just scanned an END; if it's followed by - * CATCH or TRY, combine them into a single token + * We've just scanned an END; if it's followed by CATCH or TRY, + * combine them into a single token */ TokenAuxData aux2; - int tok2 = internal_yylex(&aux2); + int tok2 = internal_yylex(&aux2); if (tok2 == K_CATCH) tok1 = K_END_CATCH; @@ -331,19 +332,19 @@ pltsql_yylex(void) * The core scanner treats "@" as an operator, we do not intend to * modify the core scanner for one language especially when it will * increase our delta while potentially causing regressions. We would - * be dealing with a genuine conflict here as the operator "@" (Absolute - * Value) is unary. + * be dealing with a genuine conflict here as the operator "@" + * (Absolute Value) is unary. * - * TSQL does not support this unary operator, and instead, relies on the - * ABS() function that we already support. + * TSQL does not support this unary operator, and instead, relies on + * the ABS() function that we already support. */ if (tok1 == Op) { /* - * Make sure we are resilient to the core scanner returning multiple - * operators as a single Op token. + * Make sure we are resilient to the core scanner returning + * multiple operators as a single Op token. */ - if ((aux1.leng == 1 && aux1.lval.str[0] == '@') || + if ((aux1.leng == 1 && aux1.lval.str[0] == '@') || (aux1.leng == 2 && aux1.lval.str[0] == '@' && aux1.lval.str[1] == '@')) { int tok2; @@ -354,23 +355,25 @@ pltsql_yylex(void) /* @: Read ahead and return as a single token. */ if (tok2 == IDENT) { - StringInfoData var_word; + StringInfoData var_word; initStringInfo(&var_word); appendStringInfoString(&var_word, aux1.lval.str); appendStringInfoString(&var_word, aux2.lval.str); if (pltsql_parse_word(var_word.data, - var_word.data, - &aux1.lval.wdatum, - &aux1.lval.word)) + var_word.data, + &aux1.lval.wdatum, + &aux1.lval.word)) tok1 = T_DATUM; else { tok1 = T_WORD; aux1.lval.str = var_word.data; } - aux1.leng += aux2.leng; /* update leng here since tok2 is already scanned and concatenated to tok1 */ + aux1.leng += aux2.leng; /* update leng here since tok2 is + * already scanned and + * concatenated to tok1 */ } else { @@ -378,10 +381,10 @@ pltsql_yylex(void) } } else if (aux1.leng > 1 && (aux1.lval.str[aux1.leng - 1] == '@' || - (aux1.lval.str[aux1.leng - 1] == '#'))) + (aux1.lval.str[aux1.leng - 1] == '#'))) { - int tok2; - int tok3; + int tok2; + int tok3; TokenAuxData aux2; TokenAuxData aux3; @@ -413,7 +416,7 @@ pltsql_yylex(void) } else if (tok1 == '#') { - int tok2; + int tok2; TokenAuxData aux2; tok2 = internal_yylex(&aux2); @@ -422,16 +425,16 @@ pltsql_yylex(void) if (tok2 == IDENT && ScanKeywordLookup(aux2.lval.word.ident, &UnreservedPLKeywords) < 0) { - StringInfoData var_word; + StringInfoData var_word; initStringInfo(&var_word); appendStringInfoString(&var_word, "#"); appendStringInfoString(&var_word, aux2.lval.str); if (pltsql_parse_word(var_word.data, - var_word.data, - &aux1.lval.wdatum, - &aux1.lval.word)) + var_word.data, + &aux1.lval.wdatum, + &aux1.lval.word)) tok1 = T_DATUM; /* TSQL allows #-prefixed cursor variables */ else { @@ -485,8 +488,8 @@ internal_yylex(TokenAuxData *auxdata) else { token = pgtsql_core_yylex(&auxdata->lval.core_yystype, - &auxdata->lloc, - yyscanner); + &auxdata->lloc, + yyscanner); /* remember the length of yytext before it gets changed */ yytext = core_yy.scanbuf + auxdata->lloc; @@ -556,7 +559,7 @@ pltsql_token_is_unreserved_keyword(int token) for (i = 0; i < lengthof(UnreservedPLKeywordTokens); i++) { - if (UnreservedPLKeywordTokens[i] == token) + if (UnreservedPLKeywordTokens[i] == token) return true; } return false; @@ -568,7 +571,7 @@ pltsql_token_is_unreserved_keyword(int token) */ void pltsql_append_source_text(StringInfo buf, - int startlocation, int endlocation) + int startlocation, int endlocation) { Assert(startlocation <= endlocation); appendBinaryStringInfo(buf, scanorig + startlocation, @@ -648,14 +651,16 @@ pltsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc, int *tok2_loc) * Peek one token ahead in the input stream, and check if it matches the given * pattern. */ -bool pltsql_peek_word_matches(const char *pattern) +bool +pltsql_peek_word_matches(const char *pattern) { int tok1; TokenAuxData aux1; - bool result; + bool result; tok1 = internal_yylex(&aux1); result = (tok1 == IDENT && pg_strcasecmp(aux1.lval.word.ident, pattern) == 0); + push_back_token(tok1, &aux1); return result; } @@ -755,7 +760,10 @@ pltsql_location_to_lineno(int location) cur_line_start = cur_line_end + 1; cur_line_num++; - /* Store the Current Line Number of the current query, incase we stumble upon a compiletime error. */ + /* + * Store the Current Line Number of the current query, incase we + * stumble upon a compiletime error. + */ CurrentLineNumber++; cur_line_end = strchr(cur_line_start, '\n'); } diff --git a/contrib/babelfishpg_tsql/src/pl_unreserved_kwlist.h b/contrib/babelfishpg_tsql/src/pl_unreserved_kwlist.h index 16bb54be8a..9318f79175 100644 --- a/contrib/babelfishpg_tsql/src/pl_unreserved_kwlist.h +++ b/contrib/babelfishpg_tsql/src/pl_unreserved_kwlist.h @@ -14,9 +14,9 @@ * *------------------------------------------------------------------------- */ - + /* There is deliberately not an #ifndef PL_UNRESERVED_KWLIST_H here. */ - + /* * List of (keyword-name, keyword-token-value) pairs. * @@ -26,7 +26,7 @@ * !!WARNING!!: This list must be sorted by ASCII name, because binary * search is used to locate entries. */ - + /* name, value */ PG_KEYWORD("absolute", K_ABSOLUTE) PG_KEYWORD("alias", K_ALIAS) diff --git a/contrib/babelfishpg_tsql/src/plan_inval.c b/contrib/babelfishpg_tsql/src/plan_inval.c index 4b6fe391b4..c8002dcf9b 100644 --- a/contrib/babelfishpg_tsql/src/plan_inval.c +++ b/contrib/babelfishpg_tsql/src/plan_inval.c @@ -20,12 +20,13 @@ const char *pltsql_identity_insert_name = "tsql_identity_insert"; /* * Defining enum to avoid string comparision in pltsql_check_guc_plan. */ -typedef enum { -IDENTITY_INSERT +typedef enum +{ + IDENTITY_INSERT } plan_info_enum_list; -void pltsql_add_guc_plan(CachedPlanSource *plansource); -bool pltsql_check_guc_plan(CachedPlanSource *plansource); +void pltsql_add_guc_plan(CachedPlanSource *plansource); +bool pltsql_check_guc_plan(CachedPlanSource *plansource); static void pltsql_initialize_identity_insert_plan(CachedPlanSource *plansource); static bool pltsql_revalidate_identity_insert_plan(CachedPlanSource *plansource, @@ -54,23 +55,24 @@ pltsql_add_guc_plan(CachedPlanSource *plansource) bool pltsql_check_guc_plan(CachedPlanSource *plansource) { - bool valid = plansource->is_valid; - ListCell *lc; + bool valid = plansource->is_valid; + ListCell *lc; if (prev_plansource_revalidate_hook) - valid = (* prev_plansource_revalidate_hook) (plansource); + valid = (*prev_plansource_revalidate_hook) (plansource); if (sql_dialect != SQL_DIALECT_TSQL || !valid) return valid; /* Identify each GUC by plan_info_enum_list and revalidate accordingly */ - foreach (lc, plansource->pltsql_plan_info) + foreach(lc, plansource->pltsql_plan_info) { - List *info_sublist = (List *) lfirst(lc); + List *info_sublist = (List *) lfirst(lc); plan_info_enum_list enum_list = (plan_info_enum_list) linitial(info_sublist); /* Execute revalidate function only if it is an insert query. */ - if (plansource->commandTag == CMDTAG_INSERT){ + if (plansource->commandTag == CMDTAG_INSERT) + { if (valid && enum_list == IDENTITY_INSERT) valid = pltsql_revalidate_identity_insert_plan(plansource, info_sublist); } @@ -89,17 +91,17 @@ pltsql_check_guc_plan(CachedPlanSource *plansource) static void pltsql_initialize_identity_insert_plan(CachedPlanSource *plansource) { - List *id_insert_info_sublist = NIL; - plan_info_enum_list* id_insert_enum; + List *id_insert_info_sublist = NIL; + plan_info_enum_list *id_insert_enum; tsql_identity_insert_fields *id_insert_state; - + /* Initialize enum */ id_insert_enum = IDENTITY_INSERT; - + /* Copy state */ id_insert_state = (tsql_identity_insert_fields *) - palloc(sizeof *id_insert_state); + palloc(sizeof *id_insert_state); id_insert_state->valid = tsql_identity_insert.valid; id_insert_state->rel_oid = tsql_identity_insert.rel_oid; id_insert_state->schema_oid = tsql_identity_insert.schema_oid; @@ -131,11 +133,11 @@ pltsql_revalidate_identity_insert_plan(CachedPlanSource *plansource, if (plansource->commandTag == CMDTAG_INSERT) { - ListCell *lc_rel; + ListCell *lc_rel; foreach(lc_rel, plansource->relationOids) { - Oid cur_rel = lfirst_oid(lc_rel); + Oid cur_rel = lfirst_oid(lc_rel); /* Check if plan affects previous or current relation */ if (cur_rel == id_insert_info->rel_oid || diff --git a/contrib/babelfishpg_tsql/src/plerrcodes.h b/contrib/babelfishpg_tsql/src/plerrcodes.h index 1b937d0165..c7dc2e6ec4 100644 --- a/contrib/babelfishpg_tsql/src/plerrcodes.h +++ b/contrib/babelfishpg_tsql/src/plerrcodes.h @@ -1007,4 +1007,3 @@ { "pltsql_error_not_mapped", ERRCODE_PLTSQL_ERROR_NOT_MAPPED }, - diff --git a/contrib/babelfishpg_tsql/src/pltsql-2.h b/contrib/babelfishpg_tsql/src/pltsql-2.h index fbaafb422a..ebf052055a 100644 --- a/contrib/babelfishpg_tsql/src/pltsql-2.h +++ b/contrib/babelfishpg_tsql/src/pltsql-2.h @@ -7,10 +7,10 @@ */ typedef struct { - PLtsql_stmt_type cmd_type; - int lineno; - char *label; - List *exprs; + PLtsql_stmt_type cmd_type; + int lineno; + char *label; + List *exprs; } PLtsql_stmt_print; /* @@ -18,10 +18,10 @@ typedef struct */ typedef struct { - PLtsql_stmt_type cmd_type; - int lineno; - char *label; - List *inits; + PLtsql_stmt_type cmd_type; + int lineno; + char *label; + List *inits; } PLtsql_stmt_init; /* @@ -29,16 +29,16 @@ typedef struct */ typedef struct PLtsql_stmt_try_catch { - PLtsql_stmt_type cmd_type; - int lineno; - char *label; - PLtsql_stmt *body; /* List of statements */ - PLtsql_stmt *handler; + PLtsql_stmt_type cmd_type; + int lineno; + char *label; + PLtsql_stmt *body; /* List of statements */ + PLtsql_stmt *handler; } PLtsql_stmt_try_catch; /* * SELECT-SET statement (this represents a SELECT - * statement that assignes variables to a set of + * statement that assignes variables to a set of * target variables, such as: * SELECT @balance = cust_balance FROM customer ... */ @@ -53,10 +53,10 @@ typedef struct PLtsql_stmt_query_set typedef struct PLtsql_stmt_push_result { - PLtsql_stmt_type cmd_type; - int lineno; - char *label; - PLtsql_expr *query; + PLtsql_stmt_type cmd_type; + int lineno; + char *label; + PLtsql_expr *query; } PLtsql_stmt_push_result; /* @@ -64,29 +64,29 @@ typedef struct PLtsql_stmt_push_result */ typedef struct PLtsql_stmt_exec { - PLtsql_stmt_type cmd_type; - int lineno; - PLtsql_expr *expr; - bool is_call; - PLtsql_variable *target; - int return_code_dno; - int paramno; - List *params; + PLtsql_stmt_type cmd_type; + int lineno; + PLtsql_expr *expr; + bool is_call; + PLtsql_variable *target; + int return_code_dno; + int paramno; + List *params; /* indicates whether we're executing a scalar UDF using EXEC keyword */ bool is_scalar_func; - bool is_cross_db; /* cross database reference */ - char *db_name; - char *proc_name; - char *schema_name; + bool is_cross_db; /* cross database reference */ + char *db_name; + char *proc_name; + char *schema_name; } PLtsql_stmt_exec; typedef struct { - const char *name; - PLtsql_expr *expr; - char mode; - int varno; /* dno of the output variable */ + const char *name; + PLtsql_expr *expr; + char mode; + int varno; /* dno of the output variable */ } tsql_exec_param; /* @@ -114,24 +114,24 @@ typedef enum PLtsql_exec_sp_type_code typedef struct PLtsql_stmt_exec_sp { PLtsql_stmt_type cmd_type; - int lineno; + int lineno; PLtsql_sp_type_code sp_type_code; - int prepared_handleno; - int cursor_handleno; - int return_code_dno; + int prepared_handleno; + int cursor_handleno; + int return_code_dno; PLtsql_expr *handle; - PLtsql_expr *query; /* stmt */ - int paramno; + PLtsql_expr *query; /* stmt */ + int paramno; PLtsql_expr *param_def; - List *params; + List *params; PLtsql_expr *opt1; PLtsql_expr *opt2; PLtsql_expr *opt3; - List *stropt; + List *stropt; } PLtsql_stmt_exec_sp; /* @@ -139,37 +139,37 @@ typedef struct PLtsql_stmt_exec_sp */ typedef struct PLtsql_stmt_decl_table { - PLtsql_stmt_type cmd_type; - int lineno; - int dno; /* dno of the table variable */ + PLtsql_stmt_type cmd_type; + int lineno; + int dno; /* dno of the table variable */ /* One and only one of the remaining two fields should be used */ - char *tbltypname; /* name of the table type */ - char *coldef; /* column definition list */ + char *tbltypname; /* name of the table type */ + char *coldef; /* column definition list */ } PLtsql_stmt_decl_table; typedef struct PLtsql_stmt_exec_batch { - PLtsql_stmt_type cmd_type; + PLtsql_stmt_type cmd_type; int lineno; - PLtsql_expr *expr; + PLtsql_expr *expr; } PLtsql_stmt_exec_batch; typedef struct PLtsql_stmt_raiserror { - PLtsql_stmt_type cmd_type; - int lineno; - List *params; - int paramno; - bool log; - bool nowait; - bool seterror; + PLtsql_stmt_type cmd_type; + int lineno; + List *params; + int paramno; + bool log; + bool nowait; + bool seterror; } PLtsql_stmt_raiserror; typedef struct PLtsql_stmt_throw { - PLtsql_stmt_type cmd_type; - int lineno; - List *params; + PLtsql_stmt_type cmd_type; + int lineno; + List *params; } PLtsql_stmt_throw; /* @@ -192,7 +192,7 @@ typedef struct PLtsql_stmt_throw #define TSQL_CURSOR_OPT_SCROLL_LOCKS (1<<24) #define TSQL_CURSOR_OPT_OPTIMISTIC (1<<25) #define TSQL_CURSOR_OPT_TYPE_WARNING (1<<26) -#define TSQL_CURSOR_OPT_AUTO_CLOSE (1<<27) /* only used in API cursor */ +#define TSQL_CURSOR_OPT_AUTO_CLOSE (1<<27) /* only used in API cursor */ /* * Speical flag to indicate the cursor is made anonymously via 'SET @cur = CURSOR FOR ...'. @@ -217,10 +217,10 @@ typedef struct PLtsql_stmt_deallocate typedef struct PLtsql_stmt_decl_cursor { PLtsql_stmt_type cmd_type; - int lineno; - int curvar; + int lineno; + int curvar; PLtsql_expr *cursor_explicit_expr; - int cursor_options; + int cursor_options; } PLtsql_stmt_decl_cursor; extern bool is_cursor_datatype(Oid oid); @@ -230,12 +230,12 @@ extern bool is_cursor_datatype(Oid oid); */ typedef struct PLtsql_stmt_goto { - PLtsql_stmt_type cmd_type; - int lineno; - char *label; - PLtsql_expr *cond; /* conditional GOTO */ - int32_t target_pc; - char *target_label; + PLtsql_stmt_type cmd_type; + int lineno; + char *label; + PLtsql_expr *cond; /* conditional GOTO */ + int32_t target_pc; + char *target_label; } PLtsql_stmt_goto; /* @@ -244,9 +244,9 @@ typedef struct PLtsql_stmt_goto #define INTERNAL_LABEL_FORMAT "LABEL-0x%lX" typedef struct PLtsql_stmt_label { - PLtsql_stmt_type cmd_type; - int lineno; - char *label; + PLtsql_stmt_type cmd_type; + int lineno; + char *label; } PLtsql_stmt_label; /* @@ -254,9 +254,9 @@ typedef struct PLtsql_stmt_label */ typedef struct PLtsql_stmt_usedb { - PLtsql_stmt_type cmd_type; - int lineno; - char *db_name; + PLtsql_stmt_type cmd_type; + int lineno; + char *db_name; } PLtsql_stmt_usedb; /* @@ -264,10 +264,10 @@ typedef struct PLtsql_stmt_usedb */ typedef struct PLtsql_stmt_save_ctx { - PLtsql_stmt_type cmd_type; - int lineno; - int32_t target_pc; - char *target_label; + PLtsql_stmt_type cmd_type; + int lineno; + int32_t target_pc; + char *target_label; } PLtsql_stmt_save_ctx; /* @@ -275,8 +275,8 @@ typedef struct PLtsql_stmt_save_ctx */ typedef struct PLtsql_stmt_restore_ctx_full { - PLtsql_stmt_type cmd_type; - int lineno; + PLtsql_stmt_type cmd_type; + int lineno; } PLtsql_stmt_restore_ctx_full; /* @@ -284,19 +284,19 @@ typedef struct PLtsql_stmt_restore_ctx_full */ typedef struct PLtsql_stmt_restore_ctx_partial { - PLtsql_stmt_type cmd_type; - int lineno; + PLtsql_stmt_type cmd_type; + int lineno; } PLtsql_stmt_restore_ctx_partial; extern char *yytext; /* * FIXME: implement pltsql_scanner_lineno() in a better way */ -#define pltsql_scanner_lineno pltsql_latest_lineno +#define pltsql_scanner_lineno pltsql_latest_lineno -extern void pltsql_convert_ident(const char *s, char **output, int numidents); +extern void pltsql_convert_ident(const char *s, char **output, int numidents); extern PLtsql_expr *pltsql_read_expression(int until, const char *expected); -extern RangeVar *pltsqlMakeRangeVarFromName(const char *identifier_val); +extern RangeVar *pltsqlMakeRangeVarFromName(const char *identifier_val); #endif diff --git a/contrib/babelfishpg_tsql/src/pltsql.h b/contrib/babelfishpg_tsql/src/pltsql.h index 3384361979..9cb0c6d633 100644 --- a/contrib/babelfishpg_tsql/src/pltsql.h +++ b/contrib/babelfishpg_tsql/src/pltsql.h @@ -56,7 +56,7 @@ (*pltsql_instr_plugin_ptr)->pltsql_instr_increment_metric(metric); \ }) -#define TSQL_TXN_NAME_LIMIT 64 /* Transaction name limit */ +#define TSQL_TXN_NAME_LIMIT 64 /* Transaction name limit */ /* Max number of Args allowed for Prepared stmts. */ #define PREPARE_STMT_MAX_ARGS 2100 @@ -77,7 +77,7 @@ typedef enum PLtsql_nsitem_type */ typedef enum PLtsql_label_type { - PLTSQL_LABEL_BLOCK, /* DECLARE/BEGIN block */ + PLTSQL_LABEL_BLOCK, /* DECLARE/BEGIN block */ PLTSQL_LABEL_LOOP, /* looping construct */ PLTSQL_LABEL_OTHER /* anything else */ } PLtsql_label_type; @@ -134,34 +134,34 @@ typedef enum PLtsql_stmt_type PLTSQL_STMT_BLOCK, PLTSQL_STMT_ASSIGN, PLTSQL_STMT_IF, - PLTSQL_STMT_CASE, /*PLPGSQL*/ - PLTSQL_STMT_LOOP, /*PLPGSQL*/ + PLTSQL_STMT_CASE, /* PLPGSQL */ + PLTSQL_STMT_LOOP, /* PLPGSQL */ PLTSQL_STMT_WHILE, - PLTSQL_STMT_FORI, /*PLPGSQL*/ - PLTSQL_STMT_FORS, /*PLPGSQL*/ - PLTSQL_STMT_FORC, /*PLPGSQL*/ - PLTSQL_STMT_FOREACH_A, /*PLPGSQL*/ + PLTSQL_STMT_FORI, /* PLPGSQL */ + PLTSQL_STMT_FORS, /* PLPGSQL */ + PLTSQL_STMT_FORC, /* PLPGSQL */ + PLTSQL_STMT_FOREACH_A, /* PLPGSQL */ PLTSQL_STMT_EXIT, PLTSQL_STMT_RETURN, - PLTSQL_STMT_RETURN_NEXT, /*PLPGSQL*/ - PLTSQL_STMT_RETURN_QUERY, /*PLPGSQL*/ - PLTSQL_STMT_RAISE, /*PLPGSQL*/ - PLTSQL_STMT_ASSERT, /*PLPGSQL*/ + PLTSQL_STMT_RETURN_NEXT, /* PLPGSQL */ + PLTSQL_STMT_RETURN_QUERY, /* PLPGSQL */ + PLTSQL_STMT_RAISE, /* PLPGSQL */ + PLTSQL_STMT_ASSERT, /* PLPGSQL */ PLTSQL_STMT_EXECSQL, - PLTSQL_STMT_DYNEXECUTE, /*PLPGSQL*/ - PLTSQL_STMT_DYNFORS, /*PLPGSQL*/ - PLTSQL_STMT_GETDIAG, /*PLPGSQL*/ + PLTSQL_STMT_DYNEXECUTE, /* PLPGSQL */ + PLTSQL_STMT_DYNFORS, /* PLPGSQL */ + PLTSQL_STMT_GETDIAG, /* PLPGSQL */ PLTSQL_STMT_OPEN, PLTSQL_STMT_FETCH, PLTSQL_STMT_CLOSE, - PLTSQL_STMT_PERFORM, /*PLPGSQL*/ - PLTSQL_STMT_CALL, /*PLPGSQL*/ + PLTSQL_STMT_PERFORM, /* PLPGSQL */ + PLTSQL_STMT_CALL, /* PLPGSQL */ PLTSQL_STMT_COMMIT, PLTSQL_STMT_ROLLBACK, - PLTSQL_STMT_SET, /*PLPGSQL*/ + PLTSQL_STMT_SET, /* PLPGSQL */ /* TSQL-only statement types follow */ PLTSQL_STMT_GOTO, - PLTSQL_STMT_PRINT, + PLTSQL_STMT_PRINT, PLTSQL_STMT_INIT, PLTSQL_STMT_QUERY_SET, PLTSQL_STMT_TRY_CATCH, @@ -173,17 +173,17 @@ typedef enum PLtsql_stmt_type PLTSQL_STMT_RETURN_TABLE, PLTSQL_STMT_DEALLOCATE, PLTSQL_STMT_DECL_CURSOR, - PLTSQL_STMT_LABEL, + PLTSQL_STMT_LABEL, PLTSQL_STMT_RAISERROR, PLTSQL_STMT_THROW, PLTSQL_STMT_USEDB, PLTSQL_STMT_SET_EXPLAIN_MODE, - /* TSQL-only executable node */ - PLTSQL_STMT_SAVE_CTX, - PLTSQL_STMT_RESTORE_CTX_FULL, - PLTSQL_STMT_RESTORE_CTX_PARTIAL, - PLTSQL_STMT_INSERT_BULK, - PLTSQL_STMT_GRANTDB + /* TSQL-only executable node */ + PLTSQL_STMT_SAVE_CTX, + PLTSQL_STMT_RESTORE_CTX_FULL, + PLTSQL_STMT_RESTORE_CTX_PARTIAL, + PLTSQL_STMT_INSERT_BULK, + PLTSQL_STMT_GRANTDB } PLtsql_stmt_type; /* @@ -251,7 +251,7 @@ typedef enum PLtsql_schema_mapping PLTSQL_DB_SCHEMA, PLTSQL_DB, PLTSQL_SCHEMA -} PLtsql_schema_mapping; +} PLtsql_schema_mapping; #define TSQL_TRIGGER_STARTED 0x1 #define TSQL_TRAN_STARTED 0x2 @@ -267,18 +267,20 @@ typedef struct PLtsql_type { char *typname; /* (simple) name of the type */ Oid typoid; /* OID of the data type */ - PLtsql_type_type ttype; /* PLTSQL_TTYPE_ code */ + PLtsql_type_type ttype; /* PLTSQL_TTYPE_ code */ int16 typlen; /* stuff copied from its pg_type entry */ bool typbyval; char typtype; Oid collation; /* from pg_type, but can be overridden */ bool typisarray; /* is "true" array, or domain over one */ int32 atttypmod; /* typmod (taken from someplace else) */ + /* - * This field is only used when a table variable does not have a pre-defined - * type, e.g. DECLARE @tableVar TABLE (a int, b int) + * This field is only used when a table variable does not have a + * pre-defined type, e.g. DECLARE @tableVar TABLE (a int, b int) */ char *coldef; + /* * Remaining fields are used only for named composite types (not RECORD) * and table types @@ -309,7 +311,7 @@ typedef struct PLtsql_expr int expr_simple_generation; /* plancache generation we checked */ Oid expr_simple_type; /* result type Oid, if simple */ int32 expr_simple_typmod; /* result typmod, if simple */ - bool expr_simple_mutable; /* true if simple expr is mutable */ + bool expr_simple_mutable; /* true if simple expr is mutable */ /* * if expr is simple AND prepared in current transaction, @@ -322,7 +324,8 @@ typedef struct PLtsql_expr LocalTransactionId expr_simple_lxid; /* here for itvf? queries with all idents replaced with NULLs */ - char *itvf_query; // make sure always set to NULL + char *itvf_query; + /* make sure always set to NULL */ } PLtsql_expr; /* @@ -488,14 +491,14 @@ typedef struct PLtsql_tbl /* end of PLtsql_variable fields */ PLtsql_type *datatype; - Oid tbltypeid; /* declared type of variable */ - char *tblname; /* name of the underlying table */ + Oid tbltypeid; /* declared type of variable */ + char *tblname; /* name of the underlying table */ + /* * If a table variable is declared inside a function, then we need to drop - * its underlying table at the end of execution. - * If a table variable is passed in as a table-valued parameter, then we - * don't need to drop its underlying table - it's the caller's - * responsibility. + * its underlying table at the end of execution. If a table variable is + * passed in as a table-valued parameter, then we don't need to drop its + * underlying table - it's the caller's responsibility. */ bool need_drop; } PLtsql_tbl; @@ -706,9 +709,9 @@ typedef struct PLtsql_stmt_if PLtsql_stmt_type cmd_type; int lineno; PLtsql_expr *cond; /* boolean expression for THEN */ - PLtsql_stmt *then_body; /* List of statements */ + PLtsql_stmt *then_body; /* List of statements */ List *elsif_list; /* List of PLtsql_if_elsif structs */ - PLtsql_stmt *else_body; /* List of statements */ + PLtsql_stmt *else_body; /* List of statements */ } PLtsql_stmt_if; /* @@ -915,16 +918,16 @@ typedef struct PLtsql_stmt_exit typedef struct PLtsql_stmt_insert_bulk { PLtsql_stmt_type cmd_type; - int lineno; - char *table_name; - char *schema_name; - char *db_name; - List *column_refs; + int lineno; + char *table_name; + char *schema_name; + char *db_name; + List *column_refs; /* Insert Bulk Options. */ - char *kilobytes_per_batch; - char *rows_per_batch; - bool keep_nulls; + char *kilobytes_per_batch; + char *rows_per_batch; + bool keep_nulls; } PLtsql_stmt_insert_bulk; /* @@ -956,7 +959,7 @@ typedef struct PLtsql_stmt_return_query { PLtsql_stmt_type cmd_type; int lineno; - PLtsql_expr *query; /* if static query */ + PLtsql_expr *query; /* if static query */ PLtsql_expr *dynquery; /* if dynamic query (RETURN QUERY EXECUTE) */ List *params; /* USING arguments for dynamic query */ } PLtsql_stmt_return_query; @@ -989,10 +992,10 @@ typedef struct PLtsql_raise_option */ typedef struct PLtsql_stmt_grantdb { - PLtsql_stmt_type cmd_type; - int lineno; - bool is_grant; - List *grantees; /* list of users */ + PLtsql_stmt_type cmd_type; + int lineno; + bool is_grant; + List *grantees; /* list of users */ } PLtsql_stmt_grantdb; /* @@ -1008,9 +1011,9 @@ typedef struct PLtsql_stmt_assert typedef struct PLtsql_txn_data { - TransactionStmtKind stmt_kind; /* Commit or rollback */ - char *txn_name; /* Transaction name */ - PLtsql_expr *txn_name_expr; /* Transaction name variable */ + TransactionStmtKind stmt_kind; /* Commit or rollback */ + char *txn_name; /* Transaction name */ + PLtsql_expr *txn_name_expr; /* Transaction name variable */ } PLtsql_txn_data; /* @@ -1025,23 +1028,25 @@ typedef struct PLtsql_stmt_execsql * mod_stmt is set when we plan the query */ bool into; /* INTO supplied? */ bool strict; /* INTO STRICT flag */ - PLtsql_txn_data *txn_data; /* Transaction data */ + PLtsql_txn_data *txn_data; /* Transaction data */ PLtsql_variable *target; /* INTO target (record or row) */ - bool mod_stmt_tablevar; /* is the stmt INSERT/UPDATE/DELETE on a - * table variable? Note: mod_stmt_tablevar - * is set when we plan the query*/ - bool need_to_push_result; /* push result to client */ - bool is_tsql_select_assign_stmt; /* T-SQL SELECT-assign (i.e. SELECT @a=1) */ - bool insert_exec; /* INSERT-EXEC stmt? */ + bool mod_stmt_tablevar; /* is the stmt INSERT/UPDATE/DELETE on a + * table variable? Note: + * mod_stmt_tablevar is set when we plan + * the query */ + bool need_to_push_result; /* push result to client */ + bool is_tsql_select_assign_stmt; /* T-SQL SELECT-assign (i.e. + * SELECT @a=1) */ + bool insert_exec; /* INSERT-EXEC stmt? */ bool is_cross_db; /* cross database reference */ bool is_dml; /* DML statement? */ bool is_ddl; /* DDL statement? */ bool func_call; /* Function call? */ - char *schema_name; /* Schema specified */ - char *db_name; /* db_name: only for cross db query */ - bool is_schema_specified; /*is schema name specified? */ - bool is_create_view; /* CREATE VIEW? */ - char *original_query; /* Only for batch level statement. */ + char *schema_name; /* Schema specified */ + char *db_name; /* db_name: only for cross db query */ + bool is_schema_specified; /* is schema name specified? */ + bool is_create_view; /* CREATE VIEW? */ + char *original_query; /* Only for batch level statement. */ } PLtsql_stmt_execsql; /* @@ -1052,11 +1057,11 @@ typedef struct PLtsql_stmt_execsql typedef struct PLtsql_stmt_set_explain_mode { PLtsql_stmt_type cmd_type; - int lineno; - char *query; - bool is_explain_only; - bool is_explain_analyze; - bool val; + int lineno; + char *query; + bool is_explain_only; + bool is_explain_analyze; + bool val; } PLtsql_stmt_set_explain_mode; /* @@ -1066,7 +1071,7 @@ typedef struct PLtsql_stmt_dynexecute { PLtsql_stmt_type cmd_type; int lineno; - PLtsql_expr *query; /* string expression */ + PLtsql_expr *query; /* string expression */ bool into; /* INTO supplied? */ bool strict; /* INTO STRICT flag */ PLtsql_variable *target; /* INTO target (record or row) */ @@ -1078,7 +1083,10 @@ typedef struct PLtsql_stmt_dynexecute */ typedef struct PLtsql_func_hashkey { - /* lower 32bit for stored procedure's OID, upper 32bit for prepared batch's handle */ + /* + * lower 32bit for stored procedure's OID, upper 32bit for prepared + * batch's handle + */ uint64_t funcOid; bool isTrigger; /* true if called as a DML trigger */ @@ -1127,14 +1135,14 @@ typedef enum PLtsql_trigtype typedef struct InlineCodeBlockArgs { - int numargs; - Oid *argtypes; - int32 *argtypmods; - char **argnames; - char *argmodes; - int *varnos; - unsigned long options; - int handle; + int numargs; + Oid *argtypes; + int32 *argtypmods; + char **argnames; + char *argmodes; + int *varnos; + unsigned long options; + int handle; } InlineCodeBlockArgs; #define OPTION_ENABLED(args, option) \ @@ -1171,13 +1179,13 @@ typedef struct PLtsql_function int new_varno; int old_varno; - TupleDesc fn_tupdesc; /* tuple descriptor for return info */ + TupleDesc fn_tupdesc; /* tuple descriptor for return info */ /* table variables */ List *table_varnos; - bool is_itvf; - bool is_mstvf; + bool is_itvf; + bool is_mstvf; PLtsql_resolve_option resolve_option; @@ -1199,9 +1207,9 @@ typedef struct PLtsql_function struct PLtsql_execstate *cur_estate; unsigned long use_count; - /* execution codes for new executor */ - struct ExecCodes *exec_codes; - bool exec_codes_valid; + /* execution codes for new executor */ + struct ExecCodes *exec_codes; + bool exec_codes_valid; /* arguments for inline code block */ InlineCodeBlockArgs *inline_args; @@ -1221,7 +1229,7 @@ typedef struct PLtsql_function * BEGIN CATCH * STMT_BLOCK2 * END CATCH - * + * * 1. Preparation (before entering STMT_BLOCK1) * 1.1 Save context before entering STMT_BLOCK1, including * a) stack for error signal handling (setjmp longjmp) @@ -1237,7 +1245,7 @@ typedef struct PLtsql_function * 3.3 move error context to active_err_ctx_stack before entering STMT_BLOCK2 * a) this is needed because STMT_BLOCK2 could also be a try-catch block * and it may also raise error - * 3.4 retrieve active error context and restore the remaining + * 3.4 retrieve active error context and restore the remaining * save_cur_error : error data existed before entering try catch * stmt_mcontext : memory containing current error * @@ -1253,7 +1261,7 @@ typedef struct PLtsql_function * END CATCH * END TRY * BEGIN CATCH STMT_BLOCK_A END CATCH -- handling error3 - * Before entering STMT_BLOCK_A, one unknown active error context will be found, + * Before entering STMT_BLOCK_A, one unknown active error context will be found, * which was pushed into stack before entering STMT_BLOCK_Z. * It contains error1 and stmt_mcontext for STMT_BLOCK_Y for saving its error (error2) * memory will be reclaimed through top level memory context deallocation @@ -1262,8 +1270,8 @@ typedef struct PLtsql_function typedef struct PLtsql_estate_err { - ErrorData *error; - char *procedure; + ErrorData *error; + char *procedure; int number; int severity; int state; @@ -1271,33 +1279,33 @@ typedef struct PLtsql_estate_err typedef struct { - /* for error handling */ - sigjmp_buf *save_exception_stack; - ErrorContextCallback *save_context_stack; - sigjmp_buf local_sigjmp_buf; + /* for error handling */ + sigjmp_buf *save_exception_stack; + ErrorContextCallback *save_context_stack; + sigjmp_buf local_sigjmp_buf; + + /* location of error handling statements */ + int target_pc; - /* location of error handling statements */ - int target_pc; + /* various contexts */ + MemoryContext oldcontext; + ResourceOwner oldowner; + ExprContext *old_eval_econtext; - /* various contexts */ - MemoryContext oldcontext; - ResourceOwner oldowner; - ExprContext *old_eval_econtext; + PLtsql_estate_err *save_cur_error; - PLtsql_estate_err *save_cur_error; - - MemoryContext stmt_mcontext; + MemoryContext stmt_mcontext; - bool partial_restored; /* set true before executing catch block */ + bool partial_restored; /* set true before executing catch block */ } PLtsql_errctx; typedef struct ExplainInfo { /* Estimated (or Actual) Query Execution Plan for a single statement */ - char *data; + char *data; /* indent for the next ExplainInfo */ - size_t next_indent; + size_t next_indent; /* used to restore session to original schema if "use db" is invoked */ const char *initial_database; @@ -1320,7 +1328,8 @@ typedef struct PLtsql_execstate bool readonly_func; bool atomic; - PLtsql_impl_txn_type impl_txn_type; /* status of implicit transaction associated */ + PLtsql_impl_txn_type impl_txn_type; /* status of implicit transaction + * associated */ char *exitlabel; /* the "target" label of the current EXIT or * CONTINUE stmt, if any */ @@ -1380,15 +1389,16 @@ typedef struct PLtsql_execstate /* * @@NESTLEVEL is needed to determine the name of underlying tables that - * need to be created for table variables. So we cache it here so that when - * there are multiple table variable declarations, we only need to calculate - * it once. + * need to be created for table variables. So we cache it here so that + * when there are multiple table variable declarations, we only need to + * calculate it once. */ int nestlevel; - /* iterative executor status */ - size_t pc; /* programe counter to current stmt in exec_code_buf */ - DynaVec *err_ctx_stack; /* stack for nested try catch block */ - size_t cur_err_ctx_idx; + /* iterative executor status */ + size_t pc; /* programe counter to current stmt in + * exec_code_buf */ + DynaVec *err_ctx_stack; /* stack for nested try catch block */ + size_t cur_err_ctx_idx; int tsql_trigger_flags; @@ -1396,15 +1406,15 @@ typedef struct PLtsql_execstate * A same procedure can be invoked by either normal EXECUTE or INSERT ... * EXECUTE, and can behave differently. */ - bool insert_exec; + bool insert_exec; - List *explain_infos; - char *schema_name; - const char *db_name; + List *explain_infos; + char *schema_name; + const char *db_name; instr_time planning_start; instr_time planning_end; - instr_time execution_start; - instr_time execution_end; + instr_time execution_start; + instr_time execution_end; } PLtsql_execstate; /* @@ -1457,26 +1467,27 @@ typedef struct PLtsql_plugin * "PLtsql_instr_plugin" that points to an instance of type PLtsql_instr_plugin. * * We use this rendezvous variable to safely share information with - * the engine even before the extension is loaded. If you call + * the engine even before the extension is loaded. If you call * find_rendezvous_variable("PLtsql_config") and find that *result * is NULL, then the extension has not been loaded. If you find - * that *result is non-NULL, it points to an instance of the + * that *result is non-NULL, it points to an instance of the * PLtsql_config struct shown here. */ typedef struct PLtsql_instr_plugin { /* Function pointers set up by the plugin */ - void (*pltsql_instr_increment_metric) (int metric); - bool (*pltsql_instr_increment_func_metric) (const char *funcName); + void (*pltsql_instr_increment_metric) (int metric); + bool (*pltsql_instr_increment_func_metric) (const char *funcName); } PLtsql_instr_plugin; -typedef struct error_map_details_t{ - char sql_state[5]; +typedef struct error_map_details_t +{ + char sql_state[5]; const char *error_message; - int tsql_error_code; - int tsql_error_severity; - char *error_msg_keywords; -}error_map_details_t; + int tsql_error_code; + int tsql_error_severity; + char *error_msg_keywords; +} error_map_details_t; /* * A PLtsql_protocol_plugin structure represents a protocol plugin that can be @@ -1514,142 +1525,142 @@ typedef struct error_map_details_t{ typedef struct PLtsql_protocol_plugin { /* True if Protocol being used by client is TDS. */ - bool is_tds_client; + bool is_tds_client; /* - * List of GUCs used/set by protocol plugin. We can always use this pointer - * to read the GUC value directly. We've declared volatile so that the - * compiler always reads the value from the memory location instead of - * the register. - * We should be careful while setting data using this pointer - as the value - * will not be verified and changes can't be rolled back automatically in - * case of an error. + * List of GUCs used/set by protocol plugin. We can always use this + * pointer to read the GUC value directly. We've declared volatile so + * that the compiler always reads the value from the memory location + * instead of the register. We should be careful while setting data using + * this pointer - as the value will not be verified and changes can't be + * rolled back automatically in case of an error. */ volatile bool *pltsql_nocount_addr; - /* - * stmt_need_logging checks whether stmt needs to be logged at babelfishpg_tsql parser - * and logs the statement at the end of statement execution on TDS + /* + * stmt_need_logging checks whether stmt needs to be logged at + * babelfishpg_tsql parser and logs the statement at the end of statement + * execution on TDS */ - bool stmt_needs_logging; + bool stmt_needs_logging; /* Function pointers set up by the plugin */ void (*send_info) (int number, int state, int info_class, - char *message, int line_no); + char *message, int line_no); void (*send_done) (int tag, int status, - int curcmd, uint64_t nprocessed); + int curcmd, uint64_t nprocessed); void (*send_env_change) (int envid, const char *new_val, const char *old_val); - bool (*get_tsql_error) (ErrorData *edata, - int *tsql_error_code, - int *tsql_error_severity, - int *tsql_error_state, - char *error_context); + bool (*get_tsql_error) (ErrorData *edata, + int *tsql_error_code, + int *tsql_error_severity, + int *tsql_error_state, + char *error_context); void (*stmt_beg) (PLtsql_execstate *estate, PLtsql_stmt *stmt); void (*stmt_end) (PLtsql_execstate *estate, PLtsql_stmt *stmt); void (*stmt_exception) (PLtsql_execstate *estate, PLtsql_stmt *stmt, bool terminate_batch); - char* (*get_login_domainname) (void); + char *(*get_login_domainname) (void); void (*set_guc_stat_var) (const char *guc, bool boolVal, const char *strVal, int intVal); void (*set_at_at_stat_var) (const char *at_at_var, int intVal, uint64 bigintVal); void (*set_db_stat_var) (int16 db_id); bool (*get_stat_values) (Datum *values, bool *nulls, int len, int pid, int curr_backend); void (*invalidate_stat_view) (void); - char* (*get_host_name) (void); + char *(*get_host_name) (void); Datum (*get_datum_from_byte_ptr) (StringInfo buf, int datatype, int scale); Datum (*get_datum_from_date_time_struct) (uint64 time, int32 date, int datatype, int optional_attr); Datum (*get_context_info) (void); - void (*set_context_info) (bytea* context_info); + void (*set_context_info) (bytea *context_info); /* Function pointers set by PL/tsql itself */ Datum (*sql_batch_callback) (PG_FUNCTION_ARGS); Datum (*sp_executesql_callback) (PG_FUNCTION_ARGS); - Datum (*sp_prepare_callback) (PG_FUNCTION_ARGS); - Datum (*sp_execute_callback) (PG_FUNCTION_ARGS); - Datum (*sp_prepexec_callback) (PG_FUNCTION_ARGS); - Datum (*sp_unprepare_callback) (PG_FUNCTION_ARGS); + Datum (*sp_prepare_callback) (PG_FUNCTION_ARGS); + Datum (*sp_execute_callback) (PG_FUNCTION_ARGS); + Datum (*sp_prepexec_callback) (PG_FUNCTION_ARGS); + Datum (*sp_unprepare_callback) (PG_FUNCTION_ARGS); - void (*reset_session_properties) (void); + void (*reset_session_properties) (void); void (*sqlvariant_set_metadata) (bytea *result, int pgBaseType, int scale, int precision, int maxLen); void (*sqlvariant_get_metadata) (bytea *result, int pgBaseType, int *scale, - int *precision, int *maxLen); - int (*sqlvariant_inline_pg_base_type)(bytea *vlena); - void (*sqlvariant_get_pg_base_type) (uint8 variantBaseType, int *pgBaseType, int tempLen, - int *dataLen, int *variantHeaderLen); - void (*sqlvariant_get_variant_base_type) (int pgBaseType, int *variantBaseType, - bool *isBaseNum, bool *isBaseChar, - bool *isBaseDec, bool *isBaseBin, bool *isBaseDate, int *variantHeaderLen); + int *precision, int *maxLen); + int (*sqlvariant_inline_pg_base_type) (bytea *vlena); + void (*sqlvariant_get_pg_base_type) (uint8 variantBaseType, int *pgBaseType, int tempLen, + int *dataLen, int *variantHeaderLen); + void (*sqlvariant_get_variant_base_type) (int pgBaseType, int *variantBaseType, + bool *isBaseNum, bool *isBaseChar, + bool *isBaseDec, bool *isBaseBin, bool *isBaseDate, int *variantHeaderLen); + + void (*pltsql_declare_var_callback) (Oid type, int32 typmod, char *name, + char mode, Datum value, bool isnull, + int index, InlineCodeBlockArgs **args, + FunctionCallInfo *fcinfo); + void (*pltsql_read_out_param_callback) (Datum comp_value, Datum **values, + bool **nulls); + int (*sp_cursoropen_callback) (int *cursor_handle, const char *stmt, int *scrollopt, int *ccopt, + int *row_count, int nparams, Datum *values, const char *nulls); + int (*sp_cursorprepare_callback) (int *stmt_handle, const char *stmt, int options, int *scrollopt, int *ccopt, + int nBindParams, Oid *boundParamsOidList); + int (*sp_cursorexecute_callback) (int stmt_handle, int *cursor_handle, int *scrollopt, int *ccopt, + int *rowcount, int nparams, Datum *values, const char *nulls); + int (*sp_cursorprepexec_callback) (int *stmt_handle, int *cursor_handle, const char *stmt, int options, int *scrollopt, int *ccopt, + int *row_count, int nparams, int nBindParams, Oid *boundParamsOidList, Datum *values, const char *nulls); + int (*sp_cursorunprepare_callback) (int stmt_handle); + int (*sp_cursoroption_callback) (int cursor_handle, int code, int value); + int (*sp_cursor_callback) (int cursor_handle, int opttype, int rownum, const char *tablename, List *values); + int (*sp_cursorfetch_callback) (int cursor_handle, int *fetchtype, int *rownum, int *nrows); + int (*sp_cursorclose_callback) (int cursor_handle); - void (*pltsql_declare_var_callback) (Oid type, int32 typmod, char *name, - char mode, Datum value, bool isnull, - int index, InlineCodeBlockArgs **args, - FunctionCallInfo *fcinfo); - void (*pltsql_read_out_param_callback) (Datum comp_value, Datum **values, - bool **nulls); - int (*sp_cursoropen_callback)(int *cursor_handle, const char *stmt, int *scrollopt, int *ccopt, - int *row_count, int nparams, Datum *values, const char *nulls); - int (*sp_cursorprepare_callback)(int *stmt_handle, const char *stmt, int options, int *scrollopt, int *ccopt, - int nBindParams, Oid *boundParamsOidList); - int (*sp_cursorexecute_callback)(int stmt_handle, int *cursor_handle, int *scrollopt, int *ccopt, - int *rowcount, int nparams, Datum *values, const char *nulls); - int (*sp_cursorprepexec_callback)(int *stmt_handle, int *cursor_handle, const char *stmt, int options, int *scrollopt, int *ccopt, - int *row_count, int nparams, int nBindParams, Oid *boundParamsOidList, Datum *values, const char *nulls); - int (*sp_cursorunprepare_callback)(int stmt_handle); - int (*sp_cursoroption_callback)(int cursor_handle, int code, int value); - int (*sp_cursor_callback)(int cursor_handle, int opttype, int rownum, const char *tablename, List* values); - int (*sp_cursorfetch_callback)(int cursor_handle, int *fetchtype, int *rownum, int *nrows); - int (*sp_cursorclose_callback)(int cursor_handle); + int *pltsql_read_proc_return_status; - int *pltsql_read_proc_return_status; + void (*send_column_metadata) (TupleDesc typeinfo, List *targetlist, int16 *formats); + void (*pltsql_read_procedure_info) (StringInfo inout_str, + bool *is_proc, + Oid *atttypid, + Oid *atttypmod, + int *attcollation); - void (*send_column_metadata) (TupleDesc typeinfo, List *targetlist, int16 *formats); - void (*pltsql_read_procedure_info) (StringInfo inout_str, - bool *is_proc, - Oid *atttypid, - Oid *atttypmod, - int *attcollation); + int *pltsql_current_lineno; - int *pltsql_current_lineno; + int (*pltsql_read_numeric_typmod) (Oid funcid, int nargs, Oid declared_oid); - int (*pltsql_read_numeric_typmod) (Oid funcid, int nargs, Oid declared_oid); + bool (*pltsql_get_errdata) (int *tsql_error_code, int *tsql_error_severity, int *tsql_error_state); - bool (*pltsql_get_errdata) (int *tsql_error_code, int *tsql_error_severity, int *tsql_error_state); + int16 (*pltsql_get_database_oid) (const char *dbname); - int16 (*pltsql_get_database_oid) (const char *dbname); + bool (*pltsql_is_login) (Oid role_oid); - bool (*pltsql_is_login) (Oid role_oid); + char *(*pltsql_get_login_default_db) (char *login_name); - char* (*pltsql_get_login_default_db) (char *login_name); + void *(*get_mapped_error_list) (void); - void* (*get_mapped_error_list) (void); + int *(*get_mapped_tsql_error_code_list) (void); - int* (*get_mapped_tsql_error_code_list) (void); + uint64 (*bulk_load_callback) (int ncol, int nrow, + Datum *Values, bool *Nulls); - uint64 (*bulk_load_callback) (int ncol, int nrow, - Datum *Values, bool *Nulls); + int (*pltsql_get_generic_typmod) (Oid funcid, int nargs, Oid declared_oid); - int (*pltsql_get_generic_typmod) (Oid funcid, int nargs, Oid declared_oid); + const char *(*pltsql_get_logical_schema_name) (const char *physical_schema_name, bool missingOk); - const char* (*pltsql_get_logical_schema_name) (const char *physical_schema_name, bool missingOk); + bool *pltsql_is_fmtonly_stmt; - bool *pltsql_is_fmtonly_stmt; + char *(*pltsql_get_user_for_database) (const char *db_name); - char* (*pltsql_get_user_for_database) (const char *db_name); + char *(*TsqlEncodingConversion) (const char *s, int len, int encoding, int *encodedByteLen); - char* (*TsqlEncodingConversion)(const char *s, int len, int encoding, int *encodedByteLen); + int (*TdsGetEncodingFromLcid) (int32_t lcid); - int (*TdsGetEncodingFromLcid)(int32_t lcid); + int (*get_insert_bulk_rows_per_batch) (); - int (*get_insert_bulk_rows_per_batch) (); - - int (*get_insert_bulk_kilobytes_per_batch) (); + int (*get_insert_bulk_kilobytes_per_batch) (); - void* (*tsql_varchar_input) (const char *s, size_t len, int32 atttypmod); + void *(*tsql_varchar_input) (const char *s, size_t len, int32 atttypmod); - void* (*tsql_char_input) (const char *s, size_t len, int32 atttypmod); + void *(*tsql_char_input) (const char *s, size_t len, int32 atttypmod); - char* (*get_cur_db_name) (); + char *(*get_cur_db_name) (); - char* (*get_physical_schema_name) (char *db_name, const char *schema_name); + char *(*get_physical_schema_name) (char *db_name, const char *schema_name); /* Session level GUCs */ bool quoted_identifier; @@ -1660,11 +1671,11 @@ typedef struct PLtsql_protocol_plugin bool ansi_padding; bool ansi_nulls; bool concat_null_yields_null; - int textsize; - int datefirst; - int lock_timeout; - const char* language; - + int textsize; + int datefirst; + int lock_timeout; + const char *language; + } PLtsql_protocol_plugin; /* @@ -1701,21 +1712,21 @@ typedef enum IDENTIFIER_LOOKUP_EXPR /* In SQL expression --- special case */ } IdentifierLookup; -typedef struct +typedef struct { - AttrNumber x_attnum; - int trigger_depth; - int total_columns; - char *column_name; + AttrNumber x_attnum; + int trigger_depth; + int total_columns; + char *column_name; } UpdatedColumn; extern IdentifierLookup pltsql_IdentifierLookup; typedef struct tsql_identity_insert_fields { - bool valid; - Oid rel_oid; - Oid schema_oid; + bool valid; + Oid rel_oid; + Oid schema_oid; } tsql_identity_insert_fields; extern tsql_identity_insert_fields tsql_identity_insert; @@ -1728,7 +1739,7 @@ extern plansource_revalidate_hook_type prev_plansource_revalidate_hook; extern pltsql_nextval_hook_type prev_pltsql_nextval_hook; extern pltsql_resetcache_hook_type prev_pltsql_resetcache_hook; -extern int pltsql_variable_conflict; +extern int pltsql_variable_conflict; /* extra compile-time checks */ #define PLTSQL_XCHECK_NONE 0 @@ -1756,29 +1767,29 @@ extern common_utility_plugin *common_utility_plugin_ptr; #define IS_TDS_CLIENT() (*pltsql_protocol_plugin_ptr && \ (*pltsql_protocol_plugin_ptr)->is_tds_client) -extern Oid procid_var; +extern Oid procid_var; extern uint64 rowcount_var; -extern List* columns_updated_list; -extern int pltsql_trigger_depth; -extern int latest_error_code; -extern int latest_pg_error_code; +extern List *columns_updated_list; +extern int pltsql_trigger_depth; +extern int latest_error_code; +extern int latest_pg_error_code; extern bool last_error_mapping_failed; -extern int fetch_status_var; -extern int pltsql_proc_return_code; +extern int fetch_status_var; +extern int pltsql_proc_return_code; -extern char* pltsql_version; +extern char *pltsql_version; typedef struct PLtsqlErrorData { - bool xact_abort_on; - bool rethrow_error; - bool trigger_error; - PLtsql_execstate *error_estate; - char *error_procedure; - int error_number; - int error_severity; - int error_state; + bool xact_abort_on; + bool rethrow_error; + bool trigger_error; + PLtsql_execstate *error_estate; + char *error_procedure; + int error_number; + int error_severity; + int error_state; } PLtsqlErrorData; typedef struct PLExecStateCallStack @@ -1798,12 +1809,12 @@ extern bool pltsql_disable_internal_savepoint; extern bool pltsql_disable_txn_in_triggers; extern bool pltsql_recursive_triggers; -extern int text_size; -extern int pltsql_rowcount; -extern int pltsql_lock_timeout; +extern int text_size; +extern int pltsql_rowcount; +extern int pltsql_lock_timeout; extern Portal pltsql_snapshot_portal; -extern int pltsql_non_tsql_proc_entry_count; -extern int pltsql_sys_func_entry_count; +extern int pltsql_non_tsql_proc_entry_count; +extern int pltsql_sys_func_entry_count; extern bool current_query_is_create_tbl_check_constraint; extern char *bulk_load_table_name; @@ -1812,8 +1823,8 @@ extern char *bulk_load_table_name; #define DEFAULT_INSERT_BULK_ROWS_PER_BATCH 1000 #define DEFAULT_INSERT_BULK_PACKET_SIZE 8 -extern int insert_bulk_rows_per_batch; -extern int insert_bulk_kilobytes_per_batch; +extern int insert_bulk_rows_per_batch; +extern int insert_bulk_kilobytes_per_batch; extern bool insert_bulk_keep_nulls; /********************************************************************** @@ -1824,37 +1835,37 @@ extern bool insert_bulk_keep_nulls; * Functions in pl_comp.c */ extern PLtsql_function *pltsql_compile(FunctionCallInfo fcinfo, - bool forValidator); + bool forValidator); extern PLtsql_function *pltsql_compile_inline(char *proc_source, - InlineCodeBlockArgs *args); + InlineCodeBlockArgs *args); extern void pltsql_parser_setup(struct ParseState *pstate, - PLtsql_expr *expr); + PLtsql_expr *expr); extern bool pltsql_parse_word(char *word1, const char *yytxt, - PLwdatum *wdatum, PLword *word); + PLwdatum *wdatum, PLword *word); extern bool pltsql_parse_dblword(char *word1, char *word2, - PLwdatum *wdatum, PLcword *cword); + PLwdatum *wdatum, PLcword *cword); extern bool pltsql_parse_tripword(char *word1, char *word2, char *word3, - PLwdatum *wdatum, PLcword *cword); + PLwdatum *wdatum, PLcword *cword); extern PLtsql_type *pltsql_parse_wordtype(char *ident); extern PLtsql_type *pltsql_parse_cwordtype(List *idents); extern PLtsql_type *pltsql_parse_wordrowtype(char *ident); extern PLtsql_type *pltsql_parse_cwordrowtype(List *idents); extern PLtsql_type *pltsql_build_datatype(Oid typeOid, int32 typmod, - Oid collation, TypeName *origtypname); + Oid collation, TypeName *origtypname); extern PLtsql_type *pltsql_build_table_datatype_coldef(const char *coldef); extern PLtsql_variable *pltsql_build_variable(const char *refname, int lineno, - PLtsql_type *dtype, - bool add2namespace); + PLtsql_type *dtype, + bool add2namespace); extern PLtsql_rec *pltsql_build_record(const char *refname, int lineno, - PLtsql_type *dtype, Oid rectypeid, - bool add2namespace); + PLtsql_type *dtype, Oid rectypeid, + bool add2namespace); extern PLtsql_tbl *pltsql_build_table(const char *refname, int lineno, - PLtsql_type *dtype, Oid tbltypeid, - bool add2namespace); + PLtsql_type *dtype, Oid tbltypeid, + bool add2namespace); extern PLtsql_recfield *pltsql_build_recfield(PLtsql_rec *rec, - const char *fldname); -extern int pltsql_recognize_err_condition(const char *condname, - bool allow_sqlstate); + const char *fldname); +extern int pltsql_recognize_err_condition(const char *condname, + bool allow_sqlstate); extern PLtsql_condition *pltsql_parse_err_condition(char *condname); extern void pltsql_adddatum(PLtsql_datum *newdatum); extern int pltsql_add_initdatums(int **varnos); @@ -1870,29 +1881,30 @@ extern Datum sp_unprepare(PG_FUNCTION_ARGS); extern bool pltsql_support_tsql_transactions(void); extern bool pltsql_sys_function_pop(void); extern uint64 execute_bulk_load_insert(int ncol, int nrow, - Datum *Values, bool *Nulls); + Datum *Values, bool *Nulls); + /* * Functions in pl_exec.c */ extern Datum pltsql_exec_function(PLtsql_function *func, - FunctionCallInfo fcinfo, - EState *simple_eval_estate, - bool atomic); + FunctionCallInfo fcinfo, + EState *simple_eval_estate, + bool atomic); extern HeapTuple pltsql_exec_trigger(PLtsql_function *func, - TriggerData *trigdata); + TriggerData *trigdata); extern void pltsql_exec_event_trigger(PLtsql_function *func, - EventTriggerData *trigdata); + EventTriggerData *trigdata); extern void pltsql_xact_cb(XactEvent event, void *arg); extern void pltsql_subxact_cb(SubXactEvent event, SubTransactionId mySubid, - SubTransactionId parentSubid, void *arg); -extern Oid pltsql_exec_get_datum_type(PLtsql_execstate *estate, - PLtsql_datum *datum); + SubTransactionId parentSubid, void *arg); +extern Oid pltsql_exec_get_datum_type(PLtsql_execstate *estate, + PLtsql_datum *datum); extern void pltsql_exec_get_datum_type_info(PLtsql_execstate *estate, - PLtsql_datum *datum, - Oid *typeId, int32 *typMod, Oid *collation); + PLtsql_datum *datum, + Oid *typeId, int32 *typMod, Oid *collation); -extern int get_insert_bulk_rows_per_batch(void); -extern int get_insert_bulk_kilobytes_per_batch(void); +extern int get_insert_bulk_rows_per_batch(void); +extern int get_insert_bulk_kilobytes_per_batch(void); extern char *get_original_query_string(void); /* @@ -1900,15 +1912,15 @@ extern char *get_original_query_string(void); */ extern void pltsql_ns_init(void); extern void pltsql_ns_push(const char *label, - PLtsql_label_type label_type); + PLtsql_label_type label_type); extern void pltsql_ns_pop(void); extern PLtsql_nsitem *pltsql_ns_top(void); extern void pltsql_ns_additem(PLtsql_nsitem_type itemtype, int itemno, const char *name); extern PLtsql_nsitem *pltsql_ns_lookup(PLtsql_nsitem *ns_cur, bool localmode, - const char *name1, const char *name2, - const char *name3, int *names_used); + const char *name1, const char *name2, + const char *name3, int *names_used); extern PLtsql_nsitem *pltsql_ns_lookup_label(PLtsql_nsitem *ns_cur, - const char *name); + const char *name); extern PLtsql_nsitem *pltsql_ns_find_nearest_loop(PLtsql_nsitem *ns_cur); /* @@ -1930,11 +1942,11 @@ extern void pltsql_push_back_token(int token); extern bool pltsql_token_is_unreserved_keyword(int token); extern void pltsql_append_source_text(StringInfo buf, int startlocation, int endlocation); -extern int pltsql_get_yyleng(void); +extern int pltsql_get_yyleng(void); extern char *pltsql_get_source(int startlocation, int len); extern int pltsql_peek(void); extern void pltsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc, - int *tok2_loc); + int *tok2_loc); extern bool pltsql_peek_word_matches(const char *pattern); extern int pltsql_scanner_errposition(int location); extern void pltsql_yyerror(const char *message) pg_attribute_noreturn(); @@ -1949,20 +1961,20 @@ extern void pltsql_scanner_finish(void); extern int pltsql_yyparse(void); /* functions in pltsql_utils.c */ -extern int TsqlUTF8LengthInUTF16(const void *vin, int len); +extern int TsqlUTF8LengthInUTF16(const void *vin, int len); extern void TsqlCheckUTF16Length_bpchar(const char *s, int32 len, int32 maxlen, int charlen, bool isExplicit); extern void TsqlCheckUTF16Length_varchar(const char *s, int32 len, int32 maxlen, bool isExplicit); extern void TsqlCheckUTF16Length_varchar_input(const char *s, int32 len, int32 maxlen); extern void TsqlCheckUTF16Length_bpchar_input(const char *s, int32 len, int32 maxlen, int charlen); extern void pltsql_declare_variable(Oid type, int32 typmod, char *name, char mode, Datum value, - bool isnull, int index, InlineCodeBlockArgs **args, - FunctionCallInfo *fcinfo); + bool isnull, int index, InlineCodeBlockArgs **args, + FunctionCallInfo *fcinfo); extern void pltsql_read_composite_out_param(Datum comp_value, Datum **values, bool **nulls); extern void pltsql_read_procedure_info(StringInfo inout_str, - bool *is_proc, - Oid *atttypid, - Oid *atttypmod, - int *attcollation); + bool *is_proc, + Oid *atttypid, + Oid *atttypmod, + int *attcollation); extern void PLTsqlStartTransaction(char *txnName); extern void PLTsqlCommitTransaction(QueryCompletion *qc, bool chain); @@ -1986,34 +1998,35 @@ extern void update_GrantRoleStmt(Node *n, List *privs, List *roles); extern void update_GrantStmt(Node *n, const char *object, const char *obj_schema, const char *grantee); extern void update_RenameStmt(Node *n, const char *old_name, const char *new_name); extern void update_ViewStmt(Node *n, const char *view_schema); -extern void pltsql_check_or_set_default_typmod(TypeName * typeName, int32 *typmod, bool is_cast); +extern void pltsql_check_or_set_default_typmod(TypeName *typeName, int32 *typmod, bool is_cast); extern bool TryLockLogicalDatabaseForSession(int16 dbid, LOCKMODE lockmode); extern void UnlockLogicalDatabaseForSession(int16 dbid, LOCKMODE lockmode, bool force); extern char *bpchar_to_cstring(const BpChar *bpchar); extern char *varchar_to_cstring(const VarChar *varchar); extern char *flatten_search_path(List *oid_list); extern const char *get_pltsql_function_signature_internal(const char *funcname, int nargs, const Oid *argtypes); -extern void report_info_or_warning(int elevel, char* message); +extern void report_info_or_warning(int elevel, char *message); extern void init_and_check_common_utility(void); -extern Oid tsql_get_trigger_oid(char *tgname, Oid tgnamespace, Oid user_id); -extern Oid tsql_get_constraint_oid(char *conname, Oid connamespace, Oid user_id); -extern Oid tsql_get_proc_oid(char *proname, Oid pronamespace, Oid user_id); -extern char** split_object_name(char *name); +extern Oid tsql_get_trigger_oid(char *tgname, Oid tgnamespace, Oid user_id); +extern Oid tsql_get_constraint_oid(char *conname, Oid connamespace, Oid user_id); +extern Oid tsql_get_proc_oid(char *proname, Oid pronamespace, Oid user_id); +extern char **split_object_name(char *name); extern bool is_schema_from_db(Oid schema_oid, Oid db_id); extern void remove_trailing_spaces(char *name); -extern Oid tsql_get_proc_nsp_oid(Oid object_id); -extern Oid tsql_get_constraint_nsp_oid(Oid object_id, Oid user_id); -extern Oid tsql_get_trigger_rel_oid(Oid object_id); +extern Oid tsql_get_proc_nsp_oid(Oid object_id); +extern Oid tsql_get_constraint_nsp_oid(Oid object_id, Oid user_id); +extern Oid tsql_get_trigger_rel_oid(Oid object_id); typedef struct { - bool success; - bool parseTreeCreated; /* used to determine if on error should retry with a different parse mode */ - size_t errpos; - int errcod; + bool success; + bool parseTreeCreated; /* used to determine if on error should + * retry with a different parse mode */ + size_t errpos; + int errcod; const char *errfmt; - size_t n_errargs; - const void *errargs[5]; /* support up to 5 args */ + size_t n_errargs; + const void *errargs[5]; /* support up to 5 args */ } ANTLR_result; extern ANTLR_result antlr_parser_cpp(const char *sourceText); @@ -2027,37 +2040,38 @@ extern bool pltsql_trace_exec_codes; extern bool pltsql_trace_exec_counts; extern bool pltsql_trace_exec_time; -/* +/* * Functions in cursor.c */ -int execute_sp_cursor(int cursor_handle, int opttype, int rownum, const char *tablename, List* values); -int execute_sp_cursoropen_old(int *cursor_handle, const char *stmt, int *scrollopt, int *ccopt, int *row_count, int nparams, Datum *values, const char *nulls); /* old interface to be compatabile with TDS */ -int execute_sp_cursoropen(int *cursor_handle, const char *stmt, int *scrollopt, int *ccopt, int *row_count, int nparams, int nBindParams, Oid *boundParamsOidList, Datum *values, const char *nulls); -int execute_sp_cursorprepare(int *stmt_handle, const char *stmt, int options, int *scrollopt, int *ccopt, int nBindParams, Oid *boundParamsOidList); -int execute_sp_cursorexecute(int stmt_handle, int *cursor_handle, int *scrollopt, int *ccopt, int *rowcount, int nparams, Datum *values, const char *nulls); -int execute_sp_cursorprepexec(int *stmt_handle, int *cursor_handle, const char *stmt, int options, int *scrollopt, int *ccopt, int *row_count, int nparams, int nBindParams, Oid *boundParamsOidList, Datum *values, const char *nulls); -int execute_sp_cursorunprepare(int stmt_handle); -int execute_sp_cursorfetch(int cursor_handle, int *fetchtype, int *rownum, int *nrows); -int execute_sp_cursoroption(int cursor_handle, int code, int value); -int execute_sp_cursoroption2(int cursor_handle, int code, const char *value); -int execute_sp_cursorclose(int cursor_handle); +int execute_sp_cursor(int cursor_handle, int opttype, int rownum, const char *tablename, List *values); +int execute_sp_cursoropen_old(int *cursor_handle, const char *stmt, int *scrollopt, int *ccopt, int *row_count, int nparams, Datum *values, const char *nulls); /* old interface to be + * compatabile with TDS */ +int execute_sp_cursoropen(int *cursor_handle, const char *stmt, int *scrollopt, int *ccopt, int *row_count, int nparams, int nBindParams, Oid *boundParamsOidList, Datum *values, const char *nulls); +int execute_sp_cursorprepare(int *stmt_handle, const char *stmt, int options, int *scrollopt, int *ccopt, int nBindParams, Oid *boundParamsOidList); +int execute_sp_cursorexecute(int stmt_handle, int *cursor_handle, int *scrollopt, int *ccopt, int *rowcount, int nparams, Datum *values, const char *nulls); +int execute_sp_cursorprepexec(int *stmt_handle, int *cursor_handle, const char *stmt, int options, int *scrollopt, int *ccopt, int *row_count, int nparams, int nBindParams, Oid *boundParamsOidList, Datum *values, const char *nulls); +int execute_sp_cursorunprepare(int stmt_handle); +int execute_sp_cursorfetch(int cursor_handle, int *fetchtype, int *rownum, int *nrows); +int execute_sp_cursoroption(int cursor_handle, int code, int value); +int execute_sp_cursoroption2(int cursor_handle, int code, const char *value); +int execute_sp_cursorclose(int cursor_handle); /* * Functions in string.c */ -void prepare_format_string(StringInfo buf, char *msg_string, int nargs, - Datum *args, Oid *argtypes, bool *argisnull); +void prepare_format_string(StringInfo buf, char *msg_string, int nargs, + Datum *args, Oid *argtypes, bool *argisnull); /* * Functions in pltsql_function_probin_handler.c */ -void probin_read_args_typmods(HeapTuple procTup, int nargs, Oid *argtypes, int **typmods); -int probin_read_ret_typmod(Oid funcid, int nargs, Oid declared_oid); -bool pltsql_function_as_checker(const char *lang, List *as, char **prosrc_str_p, char **probin_str_p); -void pltsql_function_probin_writer(CreateFunctionStmt *stmt, Oid languageOid, char** probin_str_p); -void pltsql_function_probin_reader(ParseState *pstate, - List *fargs, Oid *actual_arg_types, Oid *declared_arg_types, Oid funcid); -extern void probin_json_reader(text* probin, int** typmod_arr_p, int typmod_arr_len); +void probin_read_args_typmods(HeapTuple procTup, int nargs, Oid *argtypes, int **typmods); +int probin_read_ret_typmod(Oid funcid, int nargs, Oid declared_oid); +bool pltsql_function_as_checker(const char *lang, List *as, char **prosrc_str_p, char **probin_str_p); +void pltsql_function_probin_writer(CreateFunctionStmt *stmt, Oid languageOid, char **probin_str_p); +void pltsql_function_probin_reader(ParseState *pstate, + List *fargs, Oid *actual_arg_types, Oid *declared_arg_types, Oid funcid); +extern void probin_json_reader(text *probin, int **typmod_arr_p, int typmod_arr_len); /* * This variable is set to true, if setval should behave in T-SQL way, i.e., @@ -2080,6 +2094,6 @@ extern int64 last_scope_identity_value(void); /* * Functions in linked_servers.c */ -void GetOpenqueryTupdescFromMetadata(char* linked_server, char* query, TupleDesc *tupdesc); +void GetOpenqueryTupdescFromMetadata(char *linked_server, char *query, TupleDesc *tupdesc); #endif /* PLTSQL_H */ diff --git a/contrib/babelfishpg_tsql/src/pltsql_bulkcopy.c b/contrib/babelfishpg_tsql/src/pltsql_bulkcopy.c index 752820d698..29ab19b7ef 100644 --- a/contrib/babelfishpg_tsql/src/pltsql_bulkcopy.c +++ b/contrib/babelfishpg_tsql/src/pltsql_bulkcopy.c @@ -58,22 +58,21 @@ typedef struct CopyMultiInsertBuffer ResultRelInfo *resultRelInfo; /* ResultRelInfo for 'relid' */ BulkInsertState bistate; /* BulkInsertState for this rel */ int nused; /* number of 'slots' containing tuples */ - uint64 linenos[MAX_BUFFERED_TUPLES]; /* Line # of tuple in bulk copy - * stream */ + uint64 linenos[MAX_BUFFERED_TUPLES]; /* Line # of tuple in bulk + * copy stream */ } CopyMultiInsertBuffer; static BulkCopyState -BeginBulkCopy(Relation rel, - List *attnamelist); + BeginBulkCopy(Relation rel, + List *attnamelist); static uint64 -ExecuteBulkCopy(BulkCopyState cstate, int rowCount, int colCount, - Datum *Values, bool *Nulls); + ExecuteBulkCopy(BulkCopyState cstate, int rowCount, int colCount, + Datum *Values, bool *Nulls); -static List * -BulkCopyGetAttnums(TupleDesc tupDesc, Relation rel, List *attnamelist); +static List *BulkCopyGetAttnums(TupleDesc tupDesc, Relation rel, List *attnamelist); -void BulkCopyErrorCallback(void *arg); +void BulkCopyErrorCallback(void *arg); /* * BulkCopy - executes the Insert Bulk into a table @@ -88,7 +87,7 @@ BulkCopy(BulkCopyStmt *stmt, uint64 *processed) TupleDesc tupDesc; List *attnums; - Assert (stmt && stmt->relation); + Assert(stmt && stmt->relation); /* Open and lock the relation, using the appropriate lock type. */ rel = table_openrv(stmt->relation, RowExclusiveLock); @@ -103,7 +102,7 @@ BulkCopy(BulkCopyStmt *stmt, uint64 *processed) { if (!stmt->cstate) stmt->cstate = BeginBulkCopy(rel, attnums); - + *processed = ExecuteBulkCopy(stmt->cstate, stmt->nrow, stmt->ncol, stmt->Values, stmt->Nulls); stmt->rows_processed += *processed; } @@ -111,7 +110,7 @@ BulkCopy(BulkCopyStmt *stmt, uint64 *processed) { /* For exact row which caused error, we have BulkCopyErrorCallback. */ elog(WARNING, "Error while executing Bulk Copy. Error occured while processing at " - "implicit Batch number: %d, Rows inserted in total: %ld", stmt->cur_batch_num, stmt->rows_processed); + "implicit Batch number: %d, Rows inserted in total: %ld", stmt->cur_batch_num, stmt->rows_processed); if (rel != NULL) table_close(rel, NoLock); PG_RE_THROW(); @@ -119,9 +118,9 @@ BulkCopy(BulkCopyStmt *stmt, uint64 *processed) PG_END_TRY(); elog(DEBUG2, "Bulk Copy Progress: Successfully inserted implicit number of batches: %d, " - "number of rows inserted in total: %ld, " - "number of rows inserted in current batch: %ld", - stmt->cur_batch_num, stmt->rows_processed, *processed); + "number of rows inserted in total: %ld, " + "number of rows inserted in current batch: %ld", + stmt->cur_batch_num, stmt->rows_processed, *processed); if (rel != NULL) table_close(rel, NoLock); @@ -167,7 +166,7 @@ BulkCopyGetAttnums(TupleDesc tupDesc, Relation rel, List *attnamelist) foreach(l, attnamelist) { - char *name = (char *)lfirst(l); + char *name = (char *) lfirst(l); int attnum; int i; @@ -190,10 +189,10 @@ BulkCopyGetAttnums(TupleDesc tupDesc, Relation rel, List *attnamelist) else if (is_tsql_rowversion_or_timestamp_datatype_hook && is_tsql_rowversion_or_timestamp_datatype_hook(att->atttypid)) ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), - errmsg("column \"%s\" is a ROWVERSION/TIMESTAMP column", + errmsg("column \"%s\" is a ROWVERSION/TIMESTAMP column", name), - errdetail("ROWVERSION/TIMESTAMP columns cannot be used in BULK COPY."))); - + errdetail("ROWVERSION/TIMESTAMP columns cannot be used in BULK COPY."))); + attnum = att->attnum; break; } @@ -233,8 +232,9 @@ void BulkCopyErrorCallback(void *arg) { BulkCopyState cstate = (BulkCopyState) arg; + errcontext("Bulk Copy for %s, row: %ld (doesn't take implicit batching into consideration)", - cstate->cur_relname, cstate->cur_rowno); + cstate->cur_relname, cstate->cur_rowno); } /* @@ -538,9 +538,9 @@ static uint64 ExecuteBulkCopy(BulkCopyState cstate, int rowCount, int colCount, Datum *Values, bool *Nulls) { - int cur_index = 0; - int cur_row_in_batch = 0; - + int cur_index = 0; + int cur_row_in_batch = 0; + ExprContext *econtext; MemoryContext oldcontext = CurrentMemoryContext; @@ -611,16 +611,17 @@ ExecuteBulkCopy(BulkCopyState cstate, int rowCount, int colCount, myslot = CopyMultiInsertInfoNextFreeSlot(&cstate->multiInsertInfo, cstate->resultRelInfo); /* - * Switch to per-tuple context before building the TupleTableSlot, which does - * evaluate default expressions etc. and requires per-tuple context. + * Switch to per-tuple context before building the TupleTableSlot, + * which does evaluate default expressions etc. and requires per-tuple + * context. */ MemoryContextSwitchTo(GetPerTupleMemoryContext(cstate->estate)); ExecClearTuple(myslot); /* - * Directly store the Values/Nulls array in the slot. - * Since Values/Nulls are flattened arrays, we extract only the next row's + * Directly store the Values/Nulls array in the slot. Since + * Values/Nulls are flattened arrays, we extract only the next row's * values and store it in the slot. */ if (cur_index < rowCount * colCount) @@ -629,15 +630,19 @@ ExecuteBulkCopy(BulkCopyState cstate, int rowCount, int colCount, MemSet(myslot->tts_values, 0, myslot->tts_tupleDescriptor->natts * sizeof(Datum)); MemSet(myslot->tts_isnull, false, myslot->tts_tupleDescriptor->natts * sizeof(bool)); - /* colCount could be less than natts if user wants to insert only in a subset of columns. */ + /* + * colCount could be less than natts if user wants to insert only + * in a subset of columns. + */ for (int i = 0, j = 0; i < myslot->tts_tupleDescriptor->natts && j <= colCount; i++) { if (!list_member_int(cstate->attnumlist, i + 1)) { /* - * If there is an identity column then we should insert the value for seuqence. - * This is to be done only when we do not receive any data for this column, - * otherwise we insert the data we receive. + * If there is an identity column then we should insert + * the value for seuqence. This is to be done only when we + * do not receive any data for this column, otherwise we + * insert the data we receive. */ if (cstate->seq_index == i) { @@ -648,7 +653,10 @@ ExecuteBulkCopy(BulkCopyState cstate, int rowCount, int colCount, } else { - /* j will never be >= colCount since that is handled by protocol. */ + /* + * j will never be >= colCount since that is handled by + * protocol. + */ if (Nulls[cur_row_in_batch * colCount + j]) myslot->tts_isnull[i] = Nulls[cur_row_in_batch * colCount + j]; else @@ -656,10 +664,12 @@ ExecuteBulkCopy(BulkCopyState cstate, int rowCount, int colCount, myslot->tts_values[i] = Values[cur_row_in_batch * colCount + j]; } j++; + /* - * We increment cur_index only for the columns we received data for. - * We need not check for overflow (cur_index < rowCount * colCount) - * for each loop since that is handled by the protocol. + * We increment cur_index only for the columns we received + * data for. We need not check for overflow (cur_index < + * rowCount * colCount) for each loop since that is + * handled by the protocol. */ cur_index++; } @@ -668,9 +678,9 @@ ExecuteBulkCopy(BulkCopyState cstate, int rowCount, int colCount, cstate->cur_rowno++; /* - * Now compute and insert any defaults available for the columns not - * provided by the input data. Anything not processed here or above will - * remain NULL. + * Now compute and insert any defaults available for the columns + * not provided by the input data. Anything not processed here or + * above will remain NULL. */ for (int i = 0; i < cstate->num_defaults; i++) { @@ -683,7 +693,7 @@ ExecuteBulkCopy(BulkCopyState cstate, int rowCount, int colCount, if (myslot->tts_isnull[defmap[i]] && (!insert_bulk_keep_nulls || cstate->rv_index == defmap[i])) myslot->tts_values[defmap[i]] = ExecEvalExpr(defexprs[i], econtext, - &myslot->tts_isnull[defmap[i]]); + &myslot->tts_isnull[defmap[i]]); } } else @@ -703,35 +713,34 @@ ExecuteBulkCopy(BulkCopyState cstate, int rowCount, int colCount, if (cstate->resultRelInfo->ri_RelationDesc->rd_att->constr && cstate->resultRelInfo->ri_RelationDesc->rd_att->constr->has_generated_stored) ExecComputeStoredGenerated(cstate->resultRelInfo, cstate->estate, myslot, - CMD_INSERT); + CMD_INSERT); /* - * If the target is a plain table, check the constraints of - * the tuple. + * If the target is a plain table, check the constraints of the tuple. */ if (cstate->resultRelInfo->ri_RelationDesc->rd_att->constr) ExecConstraints(cstate->resultRelInfo, myslot, cstate->estate); /* - * The slot previously might point into the per-tuple - * context. For batching it needs to be longer lived. + * The slot previously might point into the per-tuple context. For + * batching it needs to be longer lived. */ - ExecMaterializeSlot(myslot); + ExecMaterializeSlot(myslot); /* - * Store the slot in the multi-insert buffer. - * Add this tuple to the tuple buffer. + * Store the slot in the multi-insert buffer. Add this tuple to the + * tuple buffer. */ CopyMultiInsertInfoStore(&cstate->multiInsertInfo, - cstate->resultRelInfo, myslot, - cstate->cur_rowno); + cstate->resultRelInfo, myslot, + cstate->cur_rowno); /* Update the number of rows processed. */ processed++; /* - * If enough inserts have queued up, then flush all - * buffers out to the table. + * If enough inserts have queued up, then flush all buffers out to the + * table. */ if (CopyMultiInsertInfoIsFull(&cstate->multiInsertInfo)) CopyMultiInsertInfoFlush(&cstate->multiInsertInfo, cstate->resultRelInfo); @@ -772,13 +781,14 @@ BeginBulkCopy(Relation rel, ListCell *cur; nsitem = addRangeTableEntryForRelation(pstate, rel, RowExclusiveLock, - NULL, false, false); + NULL, false, false); rte = nsitem->p_rte; rte->requiredPerms = ACL_INSERT; foreach(cur, attnums) { int attno = lfirst_int(cur) - FirstLowInvalidHeapAttributeNumber; + rte->insertedCols = bms_add_member(rte->insertedCols, attno); } @@ -789,8 +799,8 @@ BeginBulkCopy(Relation rel, if (check_enable_rls(rte->relid, InvalidOid, false) == RLS_ENABLED) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Bulk Copy not supported with row-level security"), - errhint("Use INSERT statements instead."))); + errmsg("Bulk Copy not supported with row-level security"), + errhint("Use INSERT statements instead."))); /* Check read-only transaction and parallel mode. */ if (XactReadOnly && !rel->rd_islocaltemp) @@ -850,7 +860,7 @@ BeginBulkCopy(Relation rel, { Expr *defexpr = (Expr *) build_column_default(cstate->rel, attnum); - + /* Save the index for the rowversion datatype */ if (is_tsql_rowversion_or_timestamp_datatype_hook && is_tsql_rowversion_or_timestamp_datatype_hook(att->atttypid)) cstate->rv_index = attnum - 1; @@ -900,10 +910,10 @@ BeginBulkCopy(Relation rel, ti_options |= TABLE_INSERT_SKIP_FSM; /* - * We need a ResultRelInfo so we can use the regular executor's - * index-entry-making machinery. (There used to be a huge amount of code - * here that basically duplicated execUtils.c ...). - */ + * We need a ResultRelInfo so we can use the regular executor's + * index-entry-making machinery. (There used to be a huge amount of code + * here that basically duplicated execUtils.c ...). + */ ExecInitRangeTable(cstate->estate, cstate->range_table); cstate->resultRelInfo = cstate->target_resultRelInfo = makeNode(ResultRelInfo); ExecInitResultRelation(cstate->estate, cstate->resultRelInfo, 1); @@ -930,7 +940,7 @@ EndBulkCopy(BulkCopyState cstate) /* Flush any remaining bufferes out to the table. */ if (!CopyMultiInsertInfoIsEmpty(&cstate->multiInsertInfo)) CopyMultiInsertInfoFlush(&cstate->multiInsertInfo, NULL); - + if (cstate->bistate != NULL) FreeBulkInsertState(cstate->bistate); diff --git a/contrib/babelfishpg_tsql/src/pltsql_bulkcopy.h b/contrib/babelfishpg_tsql/src/pltsql_bulkcopy.h index 0a46680b85..6c3646b522 100644 --- a/contrib/babelfishpg_tsql/src/pltsql_bulkcopy.h +++ b/contrib/babelfishpg_tsql/src/pltsql_bulkcopy.h @@ -11,7 +11,8 @@ typedef struct CopyMultiInsertInfo { List *multiInsertBuffers; /* List of tracked CopyMultiInsertBuffers */ int bufferedTuples; /* number of tuples buffered over all buffers */ - BulkCopyState cstate; /* Bulk Copy state for this CopyMultiInsertInfo */ + BulkCopyState cstate; /* Bulk Copy state for this + * CopyMultiInsertInfo */ EState *estate; /* Executor state used for BULK COPY */ CommandId mycid; /* Command Id used for BULK COPY */ int ti_options; /* table insert options */ @@ -46,8 +47,8 @@ typedef struct BulkCopyStateData int *defmap; /* array of default att numbers */ ExprState **defexprs; /* array of default att expressions */ List *range_table; - int seq_index; /* index for an identity column */ - Oid seqid; /* oid of the sequence for an identity column */ + int seq_index; /* index for an identity column */ + Oid seqid; /* oid of the sequence for an identity column */ int rv_index; /* index for a rowversion datatype column */ } BulkCopyStateData; @@ -62,18 +63,22 @@ typedef struct BulkCopyStmt List *attlist; /* List of column names (as Strings), or NIL * for all columns */ - int cur_batch_num; /* Inserts can be batched implicitly depending on protocol side, - * we should hold a counter for the current batch */ - uint64 rows_processed; /* Number of rows processed helps in tracking the progress */ - - int ncol; /* Holds the number of columns */ - int nrow; /* Holds the number of rows for the current batch */ - Datum *Values; /* List of Values (as Datums) that need to be inserted - * for the current batch */ - bool *Nulls; /* List of Nulls (as Datums) that need to be inserted + int cur_batch_num; /* Inserts can be batched implicitly depending + * on protocol side, we should hold a counter * for the current batch */ - BulkCopyState cstate; /* Contains all the state variables used throughout a BULK COPY */ + uint64 rows_processed; /* Number of rows processed helps in tracking + * the progress */ + + int ncol; /* Holds the number of columns */ + int nrow; /* Holds the number of rows for the current + * batch */ + Datum *Values; /* List of Values (as Datums) that need to be + * inserted for the current batch */ + bool *Nulls; /* List of Nulls (as Datums) that need to be + * inserted for the current batch */ + BulkCopyState cstate; /* Contains all the state variables used + * throughout a BULK COPY */ } BulkCopyStmt; extern void BulkCopy(BulkCopyStmt *stmt, uint64 *processed); -extern void EndBulkCopy(BulkCopyState cstate); \ No newline at end of file +extern void EndBulkCopy(BulkCopyState cstate); diff --git a/contrib/babelfishpg_tsql/src/pltsql_coerce.c b/contrib/babelfishpg_tsql/src/pltsql_coerce.c index 4d6085125f..e907d23b1f 100644 --- a/contrib/babelfishpg_tsql/src/pltsql_coerce.c +++ b/contrib/babelfishpg_tsql/src/pltsql_coerce.c @@ -9,7 +9,7 @@ #include "postgres.h" #include "access/htup_details.h" -#include "access/parallel.h" /* InitializingParallelWorker */ +#include "access/parallel.h" /* InitializingParallelWorker */ #include "miscadmin.h" #include "catalog/pg_authid.h" #include "catalog/pg_cast.h" @@ -49,83 +49,86 @@ PG_FUNCTION_INFO_V1(init_tsql_datatype_precedence_hash_tab); /* Memory Context */ static MemoryContext pltsql_coercion_context = NULL; -typedef enum {PG_CAST_ENTRY, TSQL_CAST_ENTRY, TSQL_CAST_WITHOUT_FUNC_ENTRY} cast_type; +typedef enum +{ + PG_CAST_ENTRY, TSQL_CAST_ENTRY, TSQL_CAST_WITHOUT_FUNC_ENTRY +} cast_type; typedef struct tsql_cast_raw_info { - cast_type casttype; - const char * srcnsp; - const char * srctypname; - const char * tarnsp; - const char * tartypname; - const char * castfunc; - char castcontext; - char castmethod; + cast_type casttype; + const char *srcnsp; + const char *srctypname; + const char *tarnsp; + const char *tartypname; + const char *castfunc; + char castcontext; + char castmethod; } tsql_cast_raw_info_t; tsql_cast_raw_info_t tsql_cast_raw_infos[] = { - {PG_CAST_ENTRY, "pg_catalog", "float8", "pg_catalog", "float4", NULL, 'i', 'f'}, - {PG_CAST_ENTRY, "pg_catalog", "float8", "pg_catalog", "numeric", NULL, 'i', 'f'}, - {PG_CAST_ENTRY, "pg_catalog", "float8", "sys", "fixeddecimal", NULL, 'i', 'f'}, - {TSQL_CAST_ENTRY, "pg_catalog", "float8", "pg_catalog", "int8", "dtrunci8", 'i', 'f'}, - {TSQL_CAST_ENTRY, "pg_catalog", "float8", "pg_catalog", "int4", "dtrunci4", 'i', 'f'}, - {TSQL_CAST_ENTRY, "pg_catalog", "float8", "pg_catalog", "int2", "dtrunci2", 'i', 'f'}, -// float4 - {PG_CAST_ENTRY, "pg_catalog", "float4", "pg_catalog", "numeric", NULL, 'i', 'f'}, - {PG_CAST_ENTRY, "pg_catalog", "float4", "sys", "fixeddecimal", NULL, 'i', 'f'}, - {TSQL_CAST_ENTRY, "pg_catalog", "float4", "pg_catalog", "int8", "ftrunci8", 'i', 'f'}, - {TSQL_CAST_ENTRY, "pg_catalog", "float4", "pg_catalog", "int4", "ftrunci4", 'i', 'f'}, - {TSQL_CAST_ENTRY, "pg_catalog", "float4", "pg_catalog", "int2", "ftrunci2", 'i', 'f'}, -// numeric - {TSQL_CAST_ENTRY, "pg_catalog", "numeric", "pg_catalog", "int8", "_trunc_numeric_to_int8", 'i', 'f'}, - {TSQL_CAST_ENTRY, "pg_catalog", "numeric", "pg_catalog", "int4", "_trunc_numeric_to_int4", 'i', 'f'}, - {TSQL_CAST_ENTRY, "pg_catalog", "numeric", "pg_catalog", "int2", "_trunc_numeric_to_int2", 'i', 'f'}, - // {"sys", "fixeddecimal", "pg_catalog", "int8", 'i'}, - {TSQL_CAST_ENTRY, "sys", "fixeddecimal", "pg_catalog", "int8", "_round_fixeddecimal_to_int8", 'i', 'f'}, - {TSQL_CAST_ENTRY, "sys", "fixeddecimal", "pg_catalog", "int4", "_round_fixeddecimal_to_int4", 'i', 'f'}, - {TSQL_CAST_ENTRY, "sys", "fixeddecimal", "pg_catalog", "int2", "_round_fixeddecimal_to_int2", 'i', 'f'}, -// bit - {PG_CAST_ENTRY, "pg_catalog", "int2", "sys", "bit", NULL, 'i', 'f'}, - {PG_CAST_ENTRY, "pg_catalog", "int4", "sys", "bit", NULL, 'i', 'f'}, - {PG_CAST_ENTRY, "pg_catalog", "int8", "sys", "bit", NULL, 'i', 'f'}, -// int8 - {PG_CAST_ENTRY, "pg_catalog", "int8", "pg_catalog", "int4", NULL, 'i', 'f'}, - {PG_CAST_ENTRY, "pg_catalog", "int8", "pg_catalog", "int2", NULL, 'i', 'f'}, - {TSQL_CAST_ENTRY, "pg_catalog", "int8", "sys", "money", "int8_to_money", 'i', 'f'}, - {TSQL_CAST_ENTRY, "pg_catalog", "int8", "sys", "smallmoney", "int8_to_smallmoney", 'i', 'f'}, -// int4 - {PG_CAST_ENTRY, "pg_catalog", "int4", "pg_catalog", "int2", NULL, 'i', 'f'}, -// varbinary {only allow to cast to integral data type) - {PG_CAST_ENTRY, "sys", "bbf_varbinary", "pg_catalog", "int8", NULL, 'i', 'f'}, - {PG_CAST_ENTRY, "sys", "bbf_varbinary", "pg_catalog", "int4", NULL, 'i', 'f'}, - {PG_CAST_ENTRY, "sys", "bbf_varbinary", "pg_catalog", "int2", NULL, 'i', 'f'}, - {TSQL_CAST_ENTRY, "sys", "bbf_varbinary", "sys", "rowversion", "varbinaryrowversion", 'i', 'f'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "bbf_varbinary", "sys", "bbf_binary", NULL, 'i', 'b'}, -// binary {only allow to cast to integral data type) - {PG_CAST_ENTRY, "sys", "bbf_binary", "pg_catalog", "int8", NULL, 'i', 'f'}, - {PG_CAST_ENTRY, "sys", "bbf_binary", "pg_catalog", "int4", NULL, 'i', 'f'}, - {PG_CAST_ENTRY, "sys", "bbf_binary", "pg_catalog", "int2", NULL, 'i', 'f'}, - {TSQL_CAST_ENTRY, "sys", "bbf_binary", "sys", "rowversion", "binaryrowversion", 'i', 'f'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "bbf_binary", "sys", "bbf_varbinary", NULL, 'i', 'b'}, -// rowversion - {PG_CAST_ENTRY, "sys", "rowversion", "pg_catalog", "int8", NULL, 'i', 'f'}, - {PG_CAST_ENTRY, "sys", "rowversion", "pg_catalog", "int4", NULL, 'i', 'f'}, - {PG_CAST_ENTRY, "sys", "rowversion", "pg_catalog", "int2", NULL, 'i', 'f'}, - {TSQL_CAST_ENTRY, "pg_catalog", "xid8", "sys", "rowversion", "xid8rowversion", 'i', 'f'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "rowversion", "sys", "bbf_varbinary", NULL, 'i', 'b'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "rowversion", "sys", "bbf_binary", NULL, 'i', 'b'}, -// characters - {TSQL_CAST_ENTRY, "pg_catalog", "text", "sys", "fixeddecimal", "char_to_fixeddecimal", 'i', 'f'}, - {TSQL_CAST_ENTRY, "pg_catalog", "bpchar", "sys", "fixeddecimal", "char_to_fixeddecimal", 'i', 'f'}, + {PG_CAST_ENTRY, "pg_catalog", "float8", "pg_catalog", "float4", NULL, 'i', 'f'}, + {PG_CAST_ENTRY, "pg_catalog", "float8", "pg_catalog", "numeric", NULL, 'i', 'f'}, + {PG_CAST_ENTRY, "pg_catalog", "float8", "sys", "fixeddecimal", NULL, 'i', 'f'}, + {TSQL_CAST_ENTRY, "pg_catalog", "float8", "pg_catalog", "int8", "dtrunci8", 'i', 'f'}, + {TSQL_CAST_ENTRY, "pg_catalog", "float8", "pg_catalog", "int4", "dtrunci4", 'i', 'f'}, + {TSQL_CAST_ENTRY, "pg_catalog", "float8", "pg_catalog", "int2", "dtrunci2", 'i', 'f'}, +/* float4 */ + {PG_CAST_ENTRY, "pg_catalog", "float4", "pg_catalog", "numeric", NULL, 'i', 'f'}, + {PG_CAST_ENTRY, "pg_catalog", "float4", "sys", "fixeddecimal", NULL, 'i', 'f'}, + {TSQL_CAST_ENTRY, "pg_catalog", "float4", "pg_catalog", "int8", "ftrunci8", 'i', 'f'}, + {TSQL_CAST_ENTRY, "pg_catalog", "float4", "pg_catalog", "int4", "ftrunci4", 'i', 'f'}, + {TSQL_CAST_ENTRY, "pg_catalog", "float4", "pg_catalog", "int2", "ftrunci2", 'i', 'f'}, +/* numeric */ + {TSQL_CAST_ENTRY, "pg_catalog", "numeric", "pg_catalog", "int8", "_trunc_numeric_to_int8", 'i', 'f'}, + {TSQL_CAST_ENTRY, "pg_catalog", "numeric", "pg_catalog", "int4", "_trunc_numeric_to_int4", 'i', 'f'}, + {TSQL_CAST_ENTRY, "pg_catalog", "numeric", "pg_catalog", "int2", "_trunc_numeric_to_int2", 'i', 'f'}, + /* {"sys", "fixeddecimal", "pg_catalog", "int8", 'i'}, */ + {TSQL_CAST_ENTRY, "sys", "fixeddecimal", "pg_catalog", "int8", "_round_fixeddecimal_to_int8", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "fixeddecimal", "pg_catalog", "int4", "_round_fixeddecimal_to_int4", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "fixeddecimal", "pg_catalog", "int2", "_round_fixeddecimal_to_int2", 'i', 'f'}, +/* bit */ + {PG_CAST_ENTRY, "pg_catalog", "int2", "sys", "bit", NULL, 'i', 'f'}, + {PG_CAST_ENTRY, "pg_catalog", "int4", "sys", "bit", NULL, 'i', 'f'}, + {PG_CAST_ENTRY, "pg_catalog", "int8", "sys", "bit", NULL, 'i', 'f'}, +/* int8 */ + {PG_CAST_ENTRY, "pg_catalog", "int8", "pg_catalog", "int4", NULL, 'i', 'f'}, + {PG_CAST_ENTRY, "pg_catalog", "int8", "pg_catalog", "int2", NULL, 'i', 'f'}, + {TSQL_CAST_ENTRY, "pg_catalog", "int8", "sys", "money", "int8_to_money", 'i', 'f'}, + {TSQL_CAST_ENTRY, "pg_catalog", "int8", "sys", "smallmoney", "int8_to_smallmoney", 'i', 'f'}, +/* int4 */ + {PG_CAST_ENTRY, "pg_catalog", "int4", "pg_catalog", "int2", NULL, 'i', 'f'}, +/* varbinary {only allow to cast to integral data type) */ + {PG_CAST_ENTRY, "sys", "bbf_varbinary", "pg_catalog", "int8", NULL, 'i', 'f'}, + {PG_CAST_ENTRY, "sys", "bbf_varbinary", "pg_catalog", "int4", NULL, 'i', 'f'}, + {PG_CAST_ENTRY, "sys", "bbf_varbinary", "pg_catalog", "int2", NULL, 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "bbf_varbinary", "sys", "rowversion", "varbinaryrowversion", 'i', 'f'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "bbf_varbinary", "sys", "bbf_binary", NULL, 'i', 'b'}, +/* binary {only allow to cast to integral data type) */ + {PG_CAST_ENTRY, "sys", "bbf_binary", "pg_catalog", "int8", NULL, 'i', 'f'}, + {PG_CAST_ENTRY, "sys", "bbf_binary", "pg_catalog", "int4", NULL, 'i', 'f'}, + {PG_CAST_ENTRY, "sys", "bbf_binary", "pg_catalog", "int2", NULL, 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "bbf_binary", "sys", "rowversion", "binaryrowversion", 'i', 'f'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "bbf_binary", "sys", "bbf_varbinary", NULL, 'i', 'b'}, +/* rowversion */ + {PG_CAST_ENTRY, "sys", "rowversion", "pg_catalog", "int8", NULL, 'i', 'f'}, + {PG_CAST_ENTRY, "sys", "rowversion", "pg_catalog", "int4", NULL, 'i', 'f'}, + {PG_CAST_ENTRY, "sys", "rowversion", "pg_catalog", "int2", NULL, 'i', 'f'}, + {TSQL_CAST_ENTRY, "pg_catalog", "xid8", "sys", "rowversion", "xid8rowversion", 'i', 'f'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "rowversion", "sys", "bbf_varbinary", NULL, 'i', 'b'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "rowversion", "sys", "bbf_binary", NULL, 'i', 'b'}, +/* characters */ + {TSQL_CAST_ENTRY, "pg_catalog", "text", "sys", "fixeddecimal", "char_to_fixeddecimal", 'i', 'f'}, + {TSQL_CAST_ENTRY, "pg_catalog", "bpchar", "sys", "fixeddecimal", "char_to_fixeddecimal", 'i', 'f'}, {TSQL_CAST_ENTRY, "sys", "bpchar", "sys", "fixeddecimal", "char_to_fixeddecimal", 'i', 'f'}, - {TSQL_CAST_ENTRY, "pg_catalog", "varchar", "sys", "fixeddecimal", "char_to_fixeddecimal", 'i', 'f'}, + {TSQL_CAST_ENTRY, "pg_catalog", "varchar", "sys", "fixeddecimal", "char_to_fixeddecimal", 'i', 'f'}, {TSQL_CAST_ENTRY, "sys", "varchar", "sys", "fixeddecimal", "char_to_fixeddecimal", 'i', 'f'}, -// smalldatetime - {PG_CAST_ENTRY, "pg_catalog", "date", "sys", "smalldatetime", NULL, 'i', 'f'}, - {PG_CAST_ENTRY, "pg_catalog", "time", "sys", "smalldatetime", NULL, 'i', 'f'}, - {PG_CAST_ENTRY, "sys", "smalldatetime", "sys", "datetime", NULL, 'i', 'b'}, - {PG_CAST_ENTRY, "sys", "smalldatetime", "sys", "datetime2", NULL, 'i', 'b'}, +/* smalldatetime */ + {PG_CAST_ENTRY, "pg_catalog", "date", "sys", "smalldatetime", NULL, 'i', 'f'}, + {PG_CAST_ENTRY, "pg_catalog", "time", "sys", "smalldatetime", NULL, 'i', 'f'}, + {PG_CAST_ENTRY, "sys", "smalldatetime", "sys", "datetime", NULL, 'i', 'b'}, + {PG_CAST_ENTRY, "sys", "smalldatetime", "sys", "datetime2", NULL, 'i', 'b'}, {PG_CAST_ENTRY, "sys", "smalldatetime", "pg_catalog", "varchar", NULL, 'i', 'f'}, {PG_CAST_ENTRY, "sys", "smalldatetime", "sys", "varchar", NULL, 'i', 'f'}, {PG_CAST_ENTRY, "sys", "smalldatetime", "pg_catalog", "bpchar", NULL, 'i', 'f'}, @@ -133,10 +136,10 @@ tsql_cast_raw_info_t tsql_cast_raw_infos[] = {PG_CAST_ENTRY, "sys", "varchar", "sys", "smalldatetime", NULL, 'i', 'f'}, {PG_CAST_ENTRY, "pg_catalog", "bpchar", "sys", "smalldatetime", NULL, 'i', 'f'}, {PG_CAST_ENTRY, "sys", "bpchar", "sys", "smalldatetime", NULL, 'i', 'f'}, -// datetime - {PG_CAST_ENTRY, "sys", "datetime", "pg_catalog", "date", NULL, 'i', 'f'}, - {PG_CAST_ENTRY, "sys", "datetime", "pg_catalog", "time", NULL, 'i', 'f'}, - {PG_CAST_ENTRY, "sys", "datetime", "sys", "smalldatetime", NULL, 'i', 'f'}, +/* datetime */ + {PG_CAST_ENTRY, "sys", "datetime", "pg_catalog", "date", NULL, 'i', 'f'}, + {PG_CAST_ENTRY, "sys", "datetime", "pg_catalog", "time", NULL, 'i', 'f'}, + {PG_CAST_ENTRY, "sys", "datetime", "sys", "smalldatetime", NULL, 'i', 'f'}, {PG_CAST_ENTRY, "sys", "datetime", "pg_catalog", "varchar", NULL, 'i', 'f'}, {PG_CAST_ENTRY, "sys", "datetime", "sys", "varchar", NULL, 'i', 'f'}, {PG_CAST_ENTRY, "sys", "datetime", "pg_catalog", "bpchar", NULL, 'i', 'f'}, @@ -144,199 +147,203 @@ tsql_cast_raw_info_t tsql_cast_raw_infos[] = {PG_CAST_ENTRY, "sys", "varchar", "sys", "datetime", NULL, 'i', 'f'}, {PG_CAST_ENTRY, "pg_catalog", "bpchar", "sys", "datetime", NULL, 'i', 'f'}, {PG_CAST_ENTRY, "sys", "bpchar", "sys", "datetime", NULL, 'i', 'f'}, -// datetime2 - {PG_CAST_ENTRY, "sys", "datetime2", "pg_catalog", "date", NULL, 'i', 'f'}, - {PG_CAST_ENTRY, "sys", "datetime2", "pg_catalog", "time", NULL, 'i', 'f'}, - {PG_CAST_ENTRY, "sys", "datetime2", "sys", "smalldatetime", NULL, 'i', 'f'}, - {PG_CAST_ENTRY, "sys", "datetime2", "sys", "datetime", NULL, 'i', 'f'}, +/* datetime2 */ + {PG_CAST_ENTRY, "sys", "datetime2", "pg_catalog", "date", NULL, 'i', 'f'}, + {PG_CAST_ENTRY, "sys", "datetime2", "pg_catalog", "time", NULL, 'i', 'f'}, + {PG_CAST_ENTRY, "sys", "datetime2", "sys", "smalldatetime", NULL, 'i', 'f'}, + {PG_CAST_ENTRY, "sys", "datetime2", "sys", "datetime", NULL, 'i', 'f'}, {PG_CAST_ENTRY, "sys", "datetime2", "pg_catalog", "varchar", NULL, 'i', 'f'}, {PG_CAST_ENTRY, "sys", "datetime2", "sys", "varchar", NULL, 'i', 'f'}, {PG_CAST_ENTRY, "sys", "datetime2", "pg_catalog", "bpchar", NULL, 'i', 'f'}, {PG_CAST_ENTRY, "pg_catalog", "varchar", "sys", "datetime2", NULL, 'i', 'f'}, {PG_CAST_ENTRY, "sys", "varchar", "sys", "datetime2", NULL, 'i', 'f'}, {PG_CAST_ENTRY, "pg_catalog", "bpchar", "sys", "datetime2", NULL, 'i', 'f'}, -// datetimeoffset - {TSQL_CAST_ENTRY, "sys", "datetimeoffset", "pg_catalog", "time", "datetimeoffset2time", 'i', 'f'}, - {TSQL_CAST_ENTRY, "sys", "datetimeoffset", "pg_catalog", "date", "datetimeoffset2date", 'i', 'f'}, - {TSQL_CAST_ENTRY, "sys", "datetimeoffset", "sys", "datetime", "datetimeoffset2datetime", 'i', 'f'}, - {TSQL_CAST_ENTRY, "sys", "datetimeoffset", "sys", "datetime2", "datetimeoffset2datetime2", 'i', 'f'}, - {TSQL_CAST_ENTRY, "sys", "datetimeoffset", "sys", "smalldatetime", "datetimeoffset2smalldatetime", 'i', 'f'}, - {TSQL_CAST_ENTRY, "pg_catalog", "time", "sys", "datetimeoffset", "time2datetimeoffset", 'i', 'f'}, - {TSQL_CAST_ENTRY, "pg_catalog", "date", "sys", "datetimeoffset", "date2datetimeoffset", 'i', 'f'}, - {TSQL_CAST_ENTRY, "sys", "datetime", "sys", "datetimeoffset", "datetime2datetimeoffset", 'i', 'f'}, - {TSQL_CAST_ENTRY, "sys", "datetime2", "sys", "datetimeoffset", "datetime22datetimeoffset", 'i', 'f'}, - {TSQL_CAST_ENTRY, "sys", "smalldatetime", "sys", "datetimeoffset", "smalldatetime2datetimeoffset", 'i', 'f'}, -// uniqueidentifier - {PG_CAST_ENTRY, "sys", "bbf_binary", "sys", "uniqueidentifier", NULL, 'i', 'f'}, - {PG_CAST_ENTRY, "sys", "bbf_varbinary", "sys", "uniqueidentifier", NULL, 'i', 'f'}, -// sql_variant -// when casting to sql variant, we need to store type information which will be lost for some of pg's domain casts -// so we need to manually add them here to go through tsql's casting sysem - {TSQL_CAST_ENTRY, "sys", "money", "sys", "sql_variant", "money_sqlvariant", 'i', 'f'}, - {TSQL_CAST_ENTRY, "sys", "smallmoney", "sys", "sql_variant", "smallmoney_sqlvariant", 'i', 'f'}, - {TSQL_CAST_ENTRY, "sys", "smallint", "sys", "sql_variant", "smallint_sqlvariant", 'i', 'f'}, - {TSQL_CAST_ENTRY, "sys", "tinyint", "sys", "sql_variant", "tinyint_sqlvariant", 'i', 'f'}, - {TSQL_CAST_ENTRY, "sys", "varchar", "sys", "sql_variant", "varchar_sqlvariant", 'i', 'f'}, +/* datetimeoffset */ + {TSQL_CAST_ENTRY, "sys", "datetimeoffset", "pg_catalog", "time", "datetimeoffset2time", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "datetimeoffset", "pg_catalog", "date", "datetimeoffset2date", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "datetimeoffset", "sys", "datetime", "datetimeoffset2datetime", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "datetimeoffset", "sys", "datetime2", "datetimeoffset2datetime2", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "datetimeoffset", "sys", "smalldatetime", "datetimeoffset2smalldatetime", 'i', 'f'}, + {TSQL_CAST_ENTRY, "pg_catalog", "time", "sys", "datetimeoffset", "time2datetimeoffset", 'i', 'f'}, + {TSQL_CAST_ENTRY, "pg_catalog", "date", "sys", "datetimeoffset", "date2datetimeoffset", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "datetime", "sys", "datetimeoffset", "datetime2datetimeoffset", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "datetime2", "sys", "datetimeoffset", "datetime22datetimeoffset", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "smalldatetime", "sys", "datetimeoffset", "smalldatetime2datetimeoffset", 'i', 'f'}, +/* uniqueidentifier */ + {PG_CAST_ENTRY, "sys", "bbf_binary", "sys", "uniqueidentifier", NULL, 'i', 'f'}, + {PG_CAST_ENTRY, "sys", "bbf_varbinary", "sys", "uniqueidentifier", NULL, 'i', 'f'}, +/* sql_variant */ +/* when casting to sql variant, we need to store type information which will be lost for some of pg's domain casts */ +/* so we need to manually add them here to go through tsql's casting sysem */ + {TSQL_CAST_ENTRY, "sys", "money", "sys", "sql_variant", "money_sqlvariant", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "smallmoney", "sys", "sql_variant", "smallmoney_sqlvariant", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "smallint", "sys", "sql_variant", "smallint_sqlvariant", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "tinyint", "sys", "sql_variant", "tinyint_sqlvariant", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "varchar", "sys", "sql_variant", "varchar_sqlvariant", 'i', 'f'}, {TSQL_CAST_ENTRY, "pg_catalog", "varchar", "sys", "sql_variant", "varchar_sqlvariant", 'i', 'f'}, - {TSQL_CAST_ENTRY, "sys", "nvarchar", "sys", "sql_variant", "nvarchar_sqlvariant", 'i', 'f'}, - {TSQL_CAST_ENTRY, "pg_catalog", "bpchar", "sys", "sql_variant", "char_sqlvariant", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "nvarchar", "sys", "sql_variant", "nvarchar_sqlvariant", 'i', 'f'}, + {TSQL_CAST_ENTRY, "pg_catalog", "bpchar", "sys", "sql_variant", "char_sqlvariant", 'i', 'f'}, {TSQL_CAST_ENTRY, "sys", "bpchar", "sys", "sql_variant", "char_sqlvariant", 'i', 'f'}, - {TSQL_CAST_ENTRY, "sys", "nchar", "sys", "sql_variant", "nchar_sqlvariant", 'i', 'f'}, -// name {special overriding to handle identifier truncation) - {TSQL_CAST_ENTRY, "pg_catalog", "text", "pg_catalog", "name", "text_to_name", 'i', 'f'}, - {TSQL_CAST_ENTRY, "pg_catalog", "bpchar", "pg_catalog", "name", "bpchar_to_name", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "nchar", "sys", "sql_variant", "nchar_sqlvariant", 'i', 'f'}, +/* name {special overriding to handle identifier truncation) */ + {TSQL_CAST_ENTRY, "pg_catalog", "text", "pg_catalog", "name", "text_to_name", 'i', 'f'}, + {TSQL_CAST_ENTRY, "pg_catalog", "bpchar", "pg_catalog", "name", "bpchar_to_name", 'i', 'f'}, {TSQL_CAST_ENTRY, "sys", "bpchar", "pg_catalog", "name", "bpchar_to_name", 'i', 'f'}, - {TSQL_CAST_ENTRY, "pg_catalog", "varchar", "pg_catalog", "name", "varchar_to_name", 'i', 'f'}, + {TSQL_CAST_ENTRY, "pg_catalog", "varchar", "pg_catalog", "name", "varchar_to_name", 'i', 'f'}, {TSQL_CAST_ENTRY, "sys", "varchar", "pg_catalog", "name", "varchar_to_name", 'i', 'f'}, -// string -> float8 via I/O - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "text", "pg_catalog", "float8", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "bpchar", "pg_catalog", "float8", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "varchar", "pg_catalog", "float8", NULL, 'i', 'i'}, -// string -> float4 via I/O - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "text", "pg_catalog", "float4", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "bpchar", "pg_catalog", "float4", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "varchar", "pg_catalog", "float4", NULL, 'i', 'i'}, -// string -> int2 via I/O - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "text", "pg_catalog", "int2", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "bpchar", "pg_catalog", "int2", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "varchar", "pg_catalog", "int2", NULL, 'i', 'i'}, -// string -> int4 via I/O - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "text", "pg_catalog", "int4", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "bpchar", "pg_catalog", "int4", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "varchar", "pg_catalog", "int4", NULL, 'i', 'i'}, -// string -> int8 via I/O - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "text", "pg_catalog", "int8", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "bpchar", "pg_catalog", "int8", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "varchar", "pg_catalog", "int8", NULL, 'i', 'i'}, -// string -> numeric via I/O - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "text", "pg_catalog", "numeric", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "bpchar", "pg_catalog", "numeric", NULL, 'i', 'i'}, +/* string -> float8 via I/O */ + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "text", "pg_catalog", "float8", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "bpchar", "pg_catalog", "float8", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "varchar", "pg_catalog", "float8", NULL, 'i', 'i'}, +/* string -> float4 via I/O */ + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "text", "pg_catalog", "float4", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "bpchar", "pg_catalog", "float4", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "varchar", "pg_catalog", "float4", NULL, 'i', 'i'}, +/* string -> int2 via I/O */ + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "text", "pg_catalog", "int2", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "bpchar", "pg_catalog", "int2", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "varchar", "pg_catalog", "int2", NULL, 'i', 'i'}, +/* string -> int4 via I/O */ + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "text", "pg_catalog", "int4", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "bpchar", "pg_catalog", "int4", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "varchar", "pg_catalog", "int4", NULL, 'i', 'i'}, +/* string -> int8 via I/O */ + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "text", "pg_catalog", "int8", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "bpchar", "pg_catalog", "int8", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "varchar", "pg_catalog", "int8", NULL, 'i', 'i'}, +/* string -> numeric via I/O */ + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "text", "pg_catalog", "numeric", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "bpchar", "pg_catalog", "numeric", NULL, 'i', 'i'}, {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "bpchar", "pg_catalog", "numeric", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "varchar", "pg_catalog", "numeric", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "varchar", "pg_catalog", "numeric", NULL, 'i', 'i'}, {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "varchar", "pg_catalog", "numeric", NULL, 'i', 'i'}, -// string -> uniqueidentifier via I/O - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "text", "sys", "uniqueidentifier", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "bpchar", "sys", "uniqueidentifier", NULL, 'i', 'i'}, +/* string -> uniqueidentifier via I/O */ + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "text", "sys", "uniqueidentifier", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "bpchar", "sys", "uniqueidentifier", NULL, 'i', 'i'}, {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "bpchar", "sys", "uniqueidentifier", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "varchar", "sys", "uniqueidentifier", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "varchar", "sys", "uniqueidentifier", NULL, 'i', 'i'}, {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "varchar", "sys", "uniqueidentifier", NULL, 'i', 'i'}, -// int2 -> string via I/O - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "int2", "pg_catalog", "text", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "int2", "pg_catalog", "bpchar", NULL, 'i', 'i'}, +/* int2 -> string via I/O */ + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "int2", "pg_catalog", "text", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "int2", "pg_catalog", "bpchar", NULL, 'i', 'i'}, {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "int2", "sys", "bpchar", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "int2", "pg_catalog", "varchar", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "int2", "pg_catalog", "varchar", NULL, 'i', 'i'}, {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "int2", "sys", "varchar", NULL, 'i', 'i'}, -// int4 -> string via I/O - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "int4", "pg_catalog", "text", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "int4", "pg_catalog", "bpchar", NULL, 'i', 'i'}, +/* int4 -> string via I/O */ + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "int4", "pg_catalog", "text", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "int4", "pg_catalog", "bpchar", NULL, 'i', 'i'}, {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "int4", "sys", "bpchar", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "int4", "pg_catalog", "varchar", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "int4", "pg_catalog", "varchar", NULL, 'i', 'i'}, {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "int4", "sys", "varchar", NULL, 'i', 'i'}, -// int8 -> string via I/O - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "int8", "pg_catalog", "text", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "int8", "pg_catalog", "bpchar", NULL, 'i', 'i'}, +/* int8 -> string via I/O */ + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "int8", "pg_catalog", "text", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "int8", "pg_catalog", "bpchar", NULL, 'i', 'i'}, {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "int8", "sys", "bpchar", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "int8", "pg_catalog", "varchar", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "int8", "pg_catalog", "varchar", NULL, 'i', 'i'}, {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "int8", "sys", "varchar", NULL, 'i', 'i'}, -// float4 -> string via I/O - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "float4", "pg_catalog", "text", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "float4", "pg_catalog", "bpchar", NULL, 'i', 'i'}, +/* float4 -> string via I/O */ + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "float4", "pg_catalog", "text", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "float4", "pg_catalog", "bpchar", NULL, 'i', 'i'}, {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "float4", "sys", "bpchar", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "float4", "pg_catalog", "varchar", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "float4", "pg_catalog", "varchar", NULL, 'i', 'i'}, {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "float4", "sys", "varchar", NULL, 'i', 'i'}, -// float8 -> string via I/O - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "float8", "pg_catalog", "text", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "float8", "pg_catalog", "bpchar", NULL, 'i', 'i'}, +/* float8 -> string via I/O */ + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "float8", "pg_catalog", "text", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "float8", "pg_catalog", "bpchar", NULL, 'i', 'i'}, {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "float8", "sys", "bpchar", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "float8", "pg_catalog", "varchar", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "float8", "pg_catalog", "varchar", NULL, 'i', 'i'}, {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "float8", "sys", "varchar", NULL, 'i', 'i'}, -// numeric -> string via I/O - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "numeric", "pg_catalog", "text", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "numeric", "pg_catalog", "bpchar", NULL, 'i', 'i'}, +/* numeric -> string via I/O */ + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "numeric", "pg_catalog", "text", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "numeric", "pg_catalog", "bpchar", NULL, 'i', 'i'}, {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "numeric", "sys", "bpchar", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "numeric", "pg_catalog", "varchar", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "numeric", "pg_catalog", "varchar", NULL, 'i', 'i'}, {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "numeric", "sys", "varchar", NULL, 'i', 'i'}, -// // fixeddecimal -> string via I/O - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "fixeddecimal", "pg_catalog", "text", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "fixeddecimal", "pg_catalog", "bpchar", NULL, 'i', 'i'}, +/* // fixeddecimal -> string via I/O */ + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "fixeddecimal", "pg_catalog", "text", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "fixeddecimal", "pg_catalog", "bpchar", NULL, 'i', 'i'}, {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "fixeddecimal", "sys", "bpchar", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "fixeddecimal", "pg_catalog", "varchar", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "fixeddecimal", "pg_catalog", "varchar", NULL, 'i', 'i'}, {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "fixeddecimal", "sys", "varchar", NULL, 'i', 'i'}, -// fixeddecimal -> string via I/O - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "uniqueidentifier", "pg_catalog", "text", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "uniqueidentifier", "pg_catalog", "bpchar", NULL, 'i', 'i'}, +/* fixeddecimal -> string via I/O */ + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "uniqueidentifier", "pg_catalog", "text", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "uniqueidentifier", "pg_catalog", "bpchar", NULL, 'i', 'i'}, {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "uniqueidentifier", "sys", "bpchar", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "uniqueidentifier", "pg_catalog", "varchar", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "uniqueidentifier", "pg_catalog", "varchar", NULL, 'i', 'i'}, {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "uniqueidentifier", "sys", "varchar", NULL, 'i', 'i'}, -// oid -> int4 - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "oid", "pg_catalog", "int4", NULL, 'i', 'b'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "oid", "pg_catalog", "text", NULL, 'i', 'i'}, -// text - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "rowversion", "pg_catalog", "text", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "timestamp", "pg_catalog", "text", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "timestamptz", "pg_catalog", "text", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "varbinary", "pg_catalog", "text", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "bbf_varbinary", "pg_catalog", "text", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "sql_variant", "pg_catalog", "text", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "date", "pg_catalog", "text", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "datetime", "pg_catalog", "text", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "datetime2", "pg_catalog", "text", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "smalldatetime", "pg_catalog", "text", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "bit", "pg_catalog", "text", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "binary", "pg_catalog", "text", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "bbf_binary", "pg_catalog", "text", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "bytea", "pg_catalog", "text", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "datetimeoffset", "pg_catalog", "text", NULL, 'i', 'i'}, - {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "time", "pg_catalog", "text", NULL, 'i', 'i'}, +/* oid -> int4 */ + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "oid", "pg_catalog", "int4", NULL, 'i', 'b'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "oid", "pg_catalog", "text", NULL, 'i', 'i'}, +/* text */ + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "rowversion", "pg_catalog", "text", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "timestamp", "pg_catalog", "text", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "timestamptz", "pg_catalog", "text", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "varbinary", "pg_catalog", "text", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "bbf_varbinary", "pg_catalog", "text", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "sql_variant", "pg_catalog", "text", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "date", "pg_catalog", "text", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "datetime", "pg_catalog", "text", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "datetime2", "pg_catalog", "text", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "smalldatetime", "pg_catalog", "text", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "bit", "pg_catalog", "text", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "binary", "pg_catalog", "text", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "bbf_binary", "pg_catalog", "text", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "bytea", "pg_catalog", "text", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "sys", "datetimeoffset", "pg_catalog", "text", NULL, 'i', 'i'}, + {TSQL_CAST_WITHOUT_FUNC_ENTRY, "pg_catalog", "time", "pg_catalog", "text", NULL, 'i', 'i'}, }; #define TOTAL_TSQL_CAST_COUNT (sizeof(tsql_cast_raw_infos)/sizeof(tsql_cast_raw_infos[0])) typedef struct tsql_precedence_info { - int precedence; - const char * nsp; - const char * typname; + int precedence; + const char *nsp; + const char *typname; } tsql_precedence_info_t; tsql_precedence_info_t tsql_precedence_infos[] = { - {0,"sys","sql_variant"}, - {1,"sys","datetimeoffset"}, - {2,"sys","datetime2"}, - {3,"sys","datetime"}, - {4,"sys","smalldatetime"}, - {5,"pg_catalog","date"}, - {6,"pg_catalog","time"}, - {7,"pg_catalog","float8"}, - {8,"pg_catalog","float4"}, - {9,"pg_catalog","numeric"}, - {10,"sys","fixeddecimal"}, - {11,"sys","money"}, - {12,"sys","smallmoney"}, - {13,"pg_catalog","int8"}, - {14,"pg_catalog","int4"}, - {15,"pg_catalog","int2"}, - {16,"sys","tinyint"}, - {17,"sys","bit"}, - {18,"sys","ntext"}, - {19,"pg_catalog","text"}, - {20,"sys","image"}, - {21,"sys","timestamp"}, - {22,"sys","uniqueidentifier"}, - {23,"sys","nvarchar"}, - {24,"sys","nchar"}, - {25,"sys","varchar"}, - {26,"pg_catalog","varchar"}, - {27,"pg_catalog","char"}, - {28,"sys","bpchar"}, - {29,"pg_catalog","bpchar"}, - {30,"pg_catalog","name"}, /* pg_catalog.name is depriotized than any other string datatype not to be looked up unless requested explicitly */ - {31,"sys","bbf_varbinary"}, - {32,"sys","varbinary"}, - {33,"sys","bbf_binary"}, - {34,"sys","binary"}, - {35,"pg_catalog","bytea"} /* pg_catalog.bytea is depriotized than any other binary datatype not to be looked up unless requested explicitly */ + {0, "sys", "sql_variant"}, + {1, "sys", "datetimeoffset"}, + {2, "sys", "datetime2"}, + {3, "sys", "datetime"}, + {4, "sys", "smalldatetime"}, + {5, "pg_catalog", "date"}, + {6, "pg_catalog", "time"}, + {7, "pg_catalog", "float8"}, + {8, "pg_catalog", "float4"}, + {9, "pg_catalog", "numeric"}, + {10, "sys", "fixeddecimal"}, + {11, "sys", "money"}, + {12, "sys", "smallmoney"}, + {13, "pg_catalog", "int8"}, + {14, "pg_catalog", "int4"}, + {15, "pg_catalog", "int2"}, + {16, "sys", "tinyint"}, + {17, "sys", "bit"}, + {18, "sys", "ntext"}, + {19, "pg_catalog", "text"}, + {20, "sys", "image"}, + {21, "sys", "timestamp"}, + {22, "sys", "uniqueidentifier"}, + {23, "sys", "nvarchar"}, + {24, "sys", "nchar"}, + {25, "sys", "varchar"}, + {26, "pg_catalog", "varchar"}, + {27, "pg_catalog", "char"}, + {28, "sys", "bpchar"}, + {29, "pg_catalog", "bpchar"}, + {30, "pg_catalog", "name"}, /* pg_catalog.name is depriotized than any + * other string datatype not to be looked up + * unless requested explicitly */ + {31, "sys", "bbf_varbinary"}, + {32, "sys", "varbinary"}, + {33, "sys", "bbf_binary"}, + {34, "sys", "binary"}, + {35, "pg_catalog", "bytea"} /* pg_catalog.bytea is depriotized than any + * other binary datatype not to be looked up + * unless requested explicitly */ }; #define TOTAL_TSQL_PRECEDENCE_COUNT (sizeof(tsql_precedence_infos)/sizeof(tsql_precedence_infos[0])) @@ -344,61 +351,63 @@ tsql_precedence_info_t tsql_precedence_infos[] = /* T-SQL Cast */ typedef struct tsql_cast_info_key { - Oid castsource; - Oid casttarget; + Oid castsource; + Oid casttarget; } tsql_cast_info_key_t; typedef struct tsql_cast_info_entry { - Oid castsource; - Oid casttarget; - Oid castfunc; - char castcontext; - char castmethod; + Oid castsource; + Oid casttarget; + Oid castfunc; + char castcontext; + char castmethod; } tsql_cast_info_entry_t; static tsql_cast_info_key_t *tsql_cast_info_keys = NULL; static tsql_cast_info_entry_t *tsql_cast_info_entries = NULL; static HTAB *ht_tsql_cast_info = NULL; -bool inited_ht_tsql_cast_info = false; +bool inited_ht_tsql_cast_info = false; -static CoercionPathType tsql_find_coercion_pathway(Oid sourceTypeId, Oid targetTypeId, CoercionContext ccontext, Oid *funcid) +static CoercionPathType +tsql_find_coercion_pathway(Oid sourceTypeId, Oid targetTypeId, CoercionContext ccontext, Oid *funcid) { - tsql_cast_info_key_t key; + tsql_cast_info_key_t key; tsql_cast_info_entry_t *entry; - CoercionContext castcontext; - CoercionPathType result = COERCION_PATH_NONE; + CoercionContext castcontext; + CoercionPathType result = COERCION_PATH_NONE; /* check if any of source/target type is sql variant */ HeapTuple tuple; - bool isSqlVariantCast = false; - bool isInt8Type = false; - bool isInt8ToMoney = false; - - Oid typeIds[2] = {sourceTypeId, targetTypeId}; - for (int i=0; i<2; i++) + bool isSqlVariantCast = false; + bool isInt8Type = false; + bool isInt8ToMoney = false; + + Oid typeIds[2] = {sourceTypeId, targetTypeId}; + + for (int i = 0; i < 2; i++) { tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeIds[i])); if (HeapTupleIsValid(tuple)) { Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tuple); Oid type_nsoid; - char * type_name; - char * type_nsname; + char *type_name; + char *type_nsname; type_nsoid = typtup->typnamespace; type_nsname = get_namespace_name(type_nsoid); type_name = NameStr(typtup->typname); /* We've found INT8 to MONEY casting */ - if(isInt8Type && strcmp(type_nsname, "sys") == 0 && ((strcmp(type_name, "money") == 0) || (strcmp(type_name, "smallmoney") == 0))) + if (isInt8Type && strcmp(type_nsname, "sys") == 0 && ((strcmp(type_name, "money") == 0) || (strcmp(type_name, "smallmoney") == 0))) isInt8ToMoney = true; /* Check if type is INT8 */ - if(strcmp(type_nsname, "pg_catalog") == 0 && strcmp(type_name, "int8") == 0) + if (strcmp(type_nsname, "pg_catalog") == 0 && strcmp(type_name, "int8") == 0) isInt8Type = true; - // We've found a SQL Variant Casting + /* We've found a SQL Variant Casting */ if (strcmp(type_nsname, "sys") == 0 && strcmp(type_name, "sql_variant") == 0) { isSqlVariantCast = true; @@ -414,9 +423,11 @@ static CoercionPathType tsql_find_coercion_pathway(Oid sourceTypeId, Oid targetT { if (OidIsValid(sourceTypeId)) sourceTypeId = getBaseType(sourceTypeId); + /* - * if we are casting from INT8 to MONEY, don't look for base type of target - * so that it can call the cast function which matches with the exact types + * if we are casting from INT8 to MONEY, don't look for base type of + * target so that it can call the cast function which matches with the + * exact types */ if (OidIsValid(targetTypeId) && !isInt8ToMoney) targetTypeId = getBaseType(targetTypeId); @@ -428,11 +439,12 @@ static CoercionPathType tsql_find_coercion_pathway(Oid sourceTypeId, Oid targetT /* Initialise T-SQL coercion hash table if not already done */ if (!inited_ht_tsql_cast_info) { - FunctionCallInfo fcinfo = NULL; /* empty interface */ + FunctionCallInfo fcinfo = NULL; /* empty interface */ + init_tsql_coerce_hash_tab(fcinfo); } - entry = (tsql_cast_info_entry_t*) hash_search(ht_tsql_cast_info, &key, HASH_FIND, NULL); + entry = (tsql_cast_info_entry_t *) hash_search(ht_tsql_cast_info, &key, HASH_FIND, NULL); if (entry == NULL) return COERCION_PATH_NONE; @@ -461,13 +473,16 @@ static CoercionPathType tsql_find_coercion_pathway(Oid sourceTypeId, Oid targetT { case COERCION_METHOD_FUNCTION: result = COERCION_PATH_FUNC; + *funcid = entry->castfunc; break; case COERCION_METHOD_INOUT: result = COERCION_PATH_COERCEVIAIO; + break; case COERCION_METHOD_BINARY: result = COERCION_PATH_RELABELTYPE; + break; default: elog(ERROR, "unrecognized castmethod: %d", @@ -482,187 +497,193 @@ static CoercionPathType tsql_find_coercion_pathway(Oid sourceTypeId, Oid targetT Datum init_tsql_coerce_hash_tab(PG_FUNCTION_ARGS) { - HASHCTL hashCtl; - MemoryContext oldContext; - void *value; - tsql_cast_info_key_t *key; - tsql_cast_info_entry_t *entry; - Oid sys_nspoid = get_namespace_oid("sys", true); - Oid *argTypes; + HASHCTL hashCtl; + MemoryContext oldContext; + void *value; + tsql_cast_info_key_t *key; + tsql_cast_info_entry_t *entry; + Oid sys_nspoid = get_namespace_oid("sys", true); + Oid *argTypes; - TSQLInstrumentation(INSTR_TSQL_INIT_TSQL_COERCE_HASH_TAB); + TSQLInstrumentation(INSTR_TSQL_INIT_TSQL_COERCE_HASH_TAB); - /* Register Hooks */ - find_coercion_pathway_hook = tsql_find_coercion_pathway; + /* Register Hooks */ + find_coercion_pathway_hook = tsql_find_coercion_pathway; - if (!OidIsValid(sys_nspoid)) - PG_RETURN_INT32(0); + if (!OidIsValid(sys_nspoid)) + PG_RETURN_INT32(0); + + + if (pltsql_coercion_context == NULL) /* initialize memory context */ + { + pltsql_coercion_context = AllocSetContextCreateInternal(NULL, + "PLTSQL CoercionMemory Context", + ALLOCSET_DEFAULT_SIZES); + } + /* create internal table */ + oldContext = MemoryContextSwitchTo(pltsql_coercion_context); + if (tsql_cast_info_keys == NULL) + tsql_cast_info_keys = palloc0(sizeof(tsql_cast_info_key_t) * (TOTAL_TSQL_CAST_COUNT)); + if (tsql_cast_info_entries == NULL) + tsql_cast_info_entries = palloc0(sizeof(tsql_cast_info_entry_t) * (TOTAL_TSQL_CAST_COUNT)); + MemoryContextSwitchTo(oldContext); - if (pltsql_coercion_context == NULL) /* initialize memory context */ - { - pltsql_coercion_context = AllocSetContextCreateInternal(NULL, - "PLTSQL CoercionMemory Context", - ALLOCSET_DEFAULT_SIZES); - } - - /* create internal table */ - oldContext = MemoryContextSwitchTo(pltsql_coercion_context); - if (tsql_cast_info_keys == NULL) - tsql_cast_info_keys = palloc0(sizeof(tsql_cast_info_key_t) * (TOTAL_TSQL_CAST_COUNT)); - if (tsql_cast_info_entries == NULL) - tsql_cast_info_entries = palloc0(sizeof(tsql_cast_info_entry_t) * (TOTAL_TSQL_CAST_COUNT)); - MemoryContextSwitchTo(oldContext); - - /* create hash table */ - if (ht_tsql_cast_info == NULL) - { - MemSet(&hashCtl, 0, sizeof(hashCtl)); - hashCtl.keysize = sizeof(tsql_cast_info_key_t); - hashCtl.entrysize = sizeof(tsql_cast_info_entry_t); - hashCtl.hcxt = pltsql_coercion_context; - ht_tsql_cast_info = hash_create("T-SQL cast", - SPI_processed, - &hashCtl, - HASH_ELEM | HASH_CONTEXT | HASH_BLOBS); - } + /* create hash table */ + if (ht_tsql_cast_info == NULL) + { + MemSet(&hashCtl, 0, sizeof(hashCtl)); + hashCtl.keysize = sizeof(tsql_cast_info_key_t); + hashCtl.entrysize = sizeof(tsql_cast_info_entry_t); + hashCtl.hcxt = pltsql_coercion_context; + ht_tsql_cast_info = hash_create("T-SQL cast", + SPI_processed, + &hashCtl, + HASH_ELEM | HASH_CONTEXT | HASH_BLOBS); + } /* mark the hash table initialised */ inited_ht_tsql_cast_info = true; - /* - * Below array will be used to provide argument types to buildoidvector function. - * A cast function can have 3 arguments: source datatype, typmod (int4) and - * cast context (bool), so we prepare the array here with last two values - * prefilled and source datatype oid will be filled when required. - */ - argTypes = (Oid *) palloc(3 * sizeof(Oid)); - argTypes[1] = INT4OID; - argTypes[2] = BOOLOID; - - for (int i=0;icasttarget = casttarget; - entry->casttarget = casttarget; - key->castsource = castsource; - entry->castsource = castsource; - - switch (tsql_cast_raw_infos[i].casttype) - { - case PG_CAST_ENTRY: - tuple = SearchSysCache2(CASTSOURCETARGET, - ObjectIdGetDatum(castsource), - ObjectIdGetDatum(casttarget)); - if (HeapTupleIsValid(tuple)) - { - castForm = (Form_pg_cast) GETSTRUCT(tuple); - entry->castfunc = castForm->castfunc; - ReleaseSysCache(tuple); - } - else - { - /* function is not loaded. wait for next scan */ - inited_ht_tsql_cast_info = false; - continue; - } - break; - case TSQL_CAST_ENTRY: - entry->castfunc = GetSysCacheOid3(PROCNAMEARGSNSP, Anum_pg_proc_oid, - CStringGetDatum(tsql_cast_raw_infos[i].castfunc), - PointerGetDatum(buildoidvector(&castsource, 1)), - ObjectIdGetDatum(sys_nspoid)); - if (!OidIsValid(entry->castfunc)) - { - /* also search cast function with 3 input arguments */ - argTypes[0] = castsource; - entry->castfunc = GetSysCacheOid3(PROCNAMEARGSNSP, Anum_pg_proc_oid, - CStringGetDatum(tsql_cast_raw_infos[i].castfunc), - PointerGetDatum(buildoidvector(argTypes, 3)), - ObjectIdGetDatum(sys_nspoid)); - - if (!OidIsValid(entry->castfunc)) - { - /* function is not loaded. wait for next scan */ - inited_ht_tsql_cast_info = false; - continue; - } - } - break; - case TSQL_CAST_WITHOUT_FUNC_ENTRY: - entry->castfunc = 0; - break; - default: - ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("Unrecognized Cast Behavior"))); - break; - } - - entry->castcontext = tsql_cast_raw_infos[i].castcontext; - entry->castmethod = tsql_cast_raw_infos[i].castmethod; - - value = hash_search(ht_tsql_cast_info, key, HASH_ENTER, NULL); - *(tsql_cast_info_entry_t*)value = *entry; - } - } - - PG_RETURN_INT32(0); + /* + * Below array will be used to provide argument types to buildoidvector + * function. A cast function can have 3 arguments: source datatype, typmod + * (int4) and cast context (bool), so we prepare the array here with last + * two values prefilled and source datatype oid will be filled when + * required. + */ + argTypes = (Oid *) palloc(3 * sizeof(Oid)); + argTypes[1] = INT4OID; + argTypes[2] = BOOLOID; + + for (int i = 0; i < TOTAL_TSQL_CAST_COUNT; i++) + { + Oid castsource; + Oid casttarget; + Oid srcnspoid; + Oid tarnspoid; + + key = &(tsql_cast_info_keys[i]); + entry = &(tsql_cast_info_entries[i]); + srcnspoid = strcmp(tsql_cast_raw_infos[i].srcnsp, "sys") == 0 ? sys_nspoid : PG_CATALOG_NAMESPACE; + castsource = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, + CStringGetDatum(tsql_cast_raw_infos[i].srctypname), ObjectIdGetDatum(srcnspoid)); + tarnspoid = strcmp(tsql_cast_raw_infos[i].tarnsp, "sys") == 0 ? sys_nspoid : PG_CATALOG_NAMESPACE; + casttarget = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, + CStringGetDatum(tsql_cast_raw_infos[i].tartypname), ObjectIdGetDatum(tarnspoid)); + + if (OidIsValid(casttarget) && OidIsValid(castsource)) + { + HeapTuple tuple; + Form_pg_cast castForm; + + key->casttarget = casttarget; + entry->casttarget = casttarget; + key->castsource = castsource; + entry->castsource = castsource; + + switch (tsql_cast_raw_infos[i].casttype) + { + case PG_CAST_ENTRY: + tuple = SearchSysCache2(CASTSOURCETARGET, + ObjectIdGetDatum(castsource), + ObjectIdGetDatum(casttarget)); + if (HeapTupleIsValid(tuple)) + { + castForm = (Form_pg_cast) GETSTRUCT(tuple); + entry->castfunc = castForm->castfunc; + ReleaseSysCache(tuple); + } + else + { + /* function is not loaded. wait for next scan */ + inited_ht_tsql_cast_info = false; + continue; + } + break; + case TSQL_CAST_ENTRY: + entry->castfunc = GetSysCacheOid3(PROCNAMEARGSNSP, Anum_pg_proc_oid, + CStringGetDatum(tsql_cast_raw_infos[i].castfunc), + PointerGetDatum(buildoidvector(&castsource, 1)), + ObjectIdGetDatum(sys_nspoid)); + if (!OidIsValid(entry->castfunc)) + { + /* also search cast function with 3 input arguments */ + argTypes[0] = castsource; + entry->castfunc = GetSysCacheOid3(PROCNAMEARGSNSP, Anum_pg_proc_oid, + CStringGetDatum(tsql_cast_raw_infos[i].castfunc), + PointerGetDatum(buildoidvector(argTypes, 3)), + ObjectIdGetDatum(sys_nspoid)); + + if (!OidIsValid(entry->castfunc)) + { + /* function is not loaded. wait for next scan */ + inited_ht_tsql_cast_info = false; + continue; + } + } + break; + case TSQL_CAST_WITHOUT_FUNC_ENTRY: + entry->castfunc = 0; + break; + default: + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("Unrecognized Cast Behavior"))); + break; + } + + entry->castcontext = tsql_cast_raw_infos[i].castcontext; + entry->castmethod = tsql_cast_raw_infos[i].castmethod; + + value = hash_search(ht_tsql_cast_info, key, HASH_ENTER, NULL); + *(tsql_cast_info_entry_t *) value = *entry; + } + } + + PG_RETURN_INT32(0); } /* T-SQL Precedence */ typedef struct tsql_datatype_precedence_info_entry { - Oid typ; - int32 precedence; + Oid typ; + int32 precedence; } tsql_datatype_precedence_info_entry_t; static tsql_datatype_precedence_info_entry_t *tsql_datatype_precedence_info_entries = NULL; static HTAB *ht_tsql_datatype_precedence_info = NULL; -bool inited_ht_tsql_datatype_precedence_info = false; +bool inited_ht_tsql_datatype_precedence_info = false; /* * smaller value has higher precedence * for unknown, return -1. (assume it is a user-defined type) */ -static int tsql_get_type_precedence(Oid typeId) +static int +tsql_get_type_precedence(Oid typeId) { tsql_datatype_precedence_info_entry_t *entry; /* Initialise T-SQL datatype precedence hash table if not already done */ if (!inited_ht_tsql_datatype_precedence_info) { - FunctionCallInfo fcinfo = NULL; /* empty interface */ + FunctionCallInfo fcinfo = NULL; /* empty interface */ + init_tsql_datatype_precedence_hash_tab(fcinfo); } - entry = (tsql_datatype_precedence_info_entry_t*) hash_search(ht_tsql_datatype_precedence_info, &typeId, HASH_FIND, NULL); + entry = (tsql_datatype_precedence_info_entry_t *) hash_search(ht_tsql_datatype_precedence_info, &typeId, HASH_FIND, NULL); if (entry == NULL) return -1; return entry->precedence; } -static bool tsql_has_higher_precedence(Oid typeId1, Oid typeId2) +static bool +tsql_has_higher_precedence(Oid typeId1, Oid typeId2) { - int type1_precedence; - int type2_precedence; + int type1_precedence; + int type2_precedence; type1_precedence = tsql_get_type_precedence(typeId1); type2_precedence = tsql_get_type_precedence(typeId2); @@ -670,10 +691,11 @@ static bool tsql_has_higher_precedence(Oid typeId1, Oid typeId2) return type1_precedence < type2_precedence; } -static bool is_vectorized_binary_operator(FuncCandidateList candidate) +static bool +is_vectorized_binary_operator(FuncCandidateList candidate) { - Oid argoid = InvalidOid; - HeapTuple tup = NULL; + Oid argoid = InvalidOid; + HeapTuple tup = NULL; Assert(candidate); @@ -683,7 +705,7 @@ static bool is_vectorized_binary_operator(FuncCandidateList candidate) return false; argoid = candidate->args[0]; - for (int i=1; inargs; ++i) + for (int i = 1; i < candidate->nargs; ++i) if (argoid != candidate->args[i]) return false; @@ -696,21 +718,25 @@ static bool is_vectorized_binary_operator(FuncCandidateList candidate) return true; } -static bool tsql_has_func_args_higher_precedence(int n, Oid *inputtypes, FuncCandidateList candidate1, FuncCandidateList candidate2) +static bool +tsql_has_func_args_higher_precedence(int n, Oid *inputtypes, FuncCandidateList candidate1, FuncCandidateList candidate2) { - int i; - Oid *argtypes1 = candidate1->args; - Oid *argtypes2 = candidate2->args; + int i; + Oid *argtypes1 = candidate1->args; + Oid *argtypes2 = candidate2->args; /* * There is no public documentation how T-SQL chooses the best candidate. - * Let's use a simple heuristic based on type precedence to resolve ambiguity. + * Let's use a simple heuristic based on type precedence to resolve + * ambiguity. * - * Please note that other more important criteria such as (# of exact matching types) should be already - * handled by PG backend. So we don't need to consider it here. + * Please note that other more important criteria such as (# of exact + * matching types) should be already handled by PG backend. So we don't + * need to consider it here. * - * Please note that there still can be an ambiguous case. - * i.e. input is (int,int) but candidate 1 is (int,bigint) and candidate 2 is (bigint,int) + * Please note that there still can be an ambiguous case. i.e. input is + * (int,int) but candidate 1 is (int,bigint) and candidate 2 is + * (bigint,int) */ if (is_vectorized_binary_operator(candidate1) && !is_vectorized_binary_operator(candidate2)) @@ -734,6 +760,7 @@ deep_copy_func_candidate(FuncCandidateList in) { /* deep copy single func-candidate except pointer to a next func-candidate */ FuncCandidateList out; + out = (FuncCandidateList) palloc(sizeof(struct _FuncCandidateList) + in->nargs * sizeof(Oid)); memcpy(out, in, sizeof(struct _FuncCandidateList) + in->nargs * sizeof(Oid)); out->next = NULL; @@ -744,13 +771,13 @@ static FuncCandidateList run_tsql_best_match_heuristics(int nargs, Oid *input_typeids, FuncCandidateList candidates) { FuncCandidateList new_candidates = NULL; - Oid input_base_typeids[FUNC_MAX_ARGS]; - int i; - int nmatch; - int nbestMatch; + Oid input_base_typeids[FUNC_MAX_ARGS]; + int i; + int nmatch; + int nbestMatch; FuncCandidateList current_candidate; FuncCandidateList last_candidate; - Oid *current_typeids; + Oid *current_typeids; for (i = 0; i < nargs; i++) { @@ -779,7 +806,8 @@ run_tsql_best_match_heuristics(int nargs, Oid *input_typeids, FuncCandidateList { if (input_base_typeids[i] != UNKNOWNOID && (current_typeids[i] == input_base_typeids[i] || - current_typeids[i] == input_typeids[i])) /* this is the difference from PG */ + current_typeids[i] == input_typeids[i])) /* this is the + * difference from PG */ nmatch++; } @@ -804,22 +832,25 @@ run_tsql_best_match_heuristics(int nargs, Oid *input_typeids, FuncCandidateList static FuncCandidateList tsql_func_select_candidate(int nargs, - Oid *input_typeids, - FuncCandidateList candidates, - bool unknowns_resolved) + Oid *input_typeids, + FuncCandidateList candidates, + bool unknowns_resolved) { FuncCandidateList new_candidates; FuncCandidateList current_candidate; FuncCandidateList another_candidate; - int i; + int i; if (unknowns_resolved) { - Oid *new_input_typeids = palloc(nargs * sizeof(Oid)); - Oid nspoid = get_namespace_oid("sys", false); - Oid sys_varcharoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, CStringGetDatum("varchar"), ObjectIdGetDatum(nspoid)); + Oid *new_input_typeids = palloc(nargs * sizeof(Oid)); + Oid nspoid = get_namespace_oid("sys", false); + Oid sys_varcharoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, CStringGetDatum("varchar"), ObjectIdGetDatum(nspoid)); - /* For unknown literals, try the following orders: varchar -> text -> others */ + /* + * For unknown literals, try the following orders: varchar -> text -> + * others + */ for (i = 0; i < nargs; i++) { new_input_typeids[i] = (input_typeids[i] == UNKNOWNOID) ? sys_varcharoid : input_typeids[i]; @@ -827,8 +858,9 @@ tsql_func_select_candidate(int nargs, current_candidate = func_select_candidate(nargs, new_input_typeids, candidates); if (current_candidate) { - int n_poly_args = 0; - for (i = 0; i< nargs; i++) + int n_poly_args = 0; + + for (i = 0; i < nargs; i++) if (input_typeids[i] == UNKNOWNOID && IsPolymorphicType(current_candidate->args[i])) ++n_poly_args; @@ -837,15 +869,20 @@ tsql_func_select_candidate(int nargs, } /* - * TODO: PG doens't blindly use TEXT datatype for UNKNOWNOID. It is based on its category and preffered datatype. - * It's not clear to follow the same policy in babelfish. For now, simply always choosing TEXT datatype here. - */ + * TODO: PG doens't blindly use TEXT datatype for UNKNOWNOID. It is + * based on its category and preffered datatype. It's not clear to + * follow the same policy in babelfish. For now, simply always + * choosing TEXT datatype here. + */ for (i = 0; i < nargs; i++) { new_input_typeids[i] = (input_typeids[i] == UNKNOWNOID) ? TEXTOID : input_typeids[i]; } - /* UNKNOWNOID was overwritten to TEXTOID. apply the PG logic again to find the candidate */ + /* + * UNKNOWNOID was overwritten to TEXTOID. apply the PG logic again to + * find the candidate + */ return func_select_candidate(nargs, new_input_typeids, candidates); } @@ -855,7 +892,7 @@ tsql_func_select_candidate(int nargs, current_candidate != NULL; current_candidate = current_candidate->next) { - bool has_highest_precedence = true; + bool has_highest_precedence = true; for (another_candidate = new_candidates; another_candidate != NULL; @@ -875,7 +912,10 @@ tsql_func_select_candidate(int nargs, } } - /* can't find the function which beats all the other functions. still ambiguous. */ + /* + * can't find the function which beats all the other functions. still + * ambiguous. + */ return NULL; } @@ -886,9 +926,9 @@ tsql_coerce_string_literal_hook(ParseCallbackState *pcbstate, Oid targetTypeId, CoercionContext ccontext, CoercionForm cformat, int location) { - Oid baseTypeId = newcon->consttype; - Type baseType = typeidType(baseTypeId); - int32 inputTypeMod = newcon->consttypmod; + Oid baseTypeId = newcon->consttype; + Type baseType = typeidType(baseTypeId); + int32 inputTypeMod = newcon->consttypmod; if (newcon->constisnull) { @@ -896,22 +936,28 @@ tsql_coerce_string_literal_hook(ParseCallbackState *pcbstate, Oid targetTypeId, } else { - int i; + int i; if (ccontext != COERCION_EXPLICIT) { - /* T-SQL may forbid casting from string literal to certain datatypes (i.e. binary, varbinary) */ - if ((*common_utility_plugin_ptr->is_tsql_binary_datatype)(baseTypeId)) + /* + * T-SQL may forbid casting from string literal to certain + * datatypes (i.e. binary, varbinary) + */ + if ((*common_utility_plugin_ptr->is_tsql_binary_datatype) (baseTypeId)) ereport(ERROR, - (errcode(ERRCODE_CANNOT_COERCE), - errmsg("cannot coerce string literal to binary datatype"))); - if ((*common_utility_plugin_ptr->is_tsql_varbinary_datatype)(baseTypeId)) + (errcode(ERRCODE_CANNOT_COERCE), + errmsg("cannot coerce string literal to binary datatype"))); + if ((*common_utility_plugin_ptr->is_tsql_varbinary_datatype) (baseTypeId)) ereport(ERROR, - (errcode(ERRCODE_CANNOT_COERCE), - errmsg("cannot coerce string literal to varbinary datatype"))); + (errcode(ERRCODE_CANNOT_COERCE), + errmsg("cannot coerce string literal to varbinary datatype"))); } - /* T-SQL treats an empty string literal as 0 in certain datatypes, e.g., INT, FLOAT, etc. */ + /* + * T-SQL treats an empty string literal as 0 in certain datatypes, + * e.g., INT, FLOAT, etc. + */ for (i = strlen(value) - 1; i >= 0; i--) { if (value[i] != ' ') @@ -920,7 +966,10 @@ tsql_coerce_string_literal_hook(ParseCallbackState *pcbstate, Oid targetTypeId, if (i == -1) { - /* i == 1 means the value does not contain any characters but spaces */ + /* + * i == 1 means the value does not contain any characters but + * spaces + */ switch (baseTypeId) { case INT2OID: @@ -939,76 +988,83 @@ tsql_coerce_string_literal_hook(ParseCallbackState *pcbstate, Oid targetTypeId, newcon->constvalue = Float8GetDatum(0); break; case NUMERICOID: - { - /* - * T-SQL allows an empty/space-only string as a default constraint of - * NUMERIC column in CREATE TABLE statement. However, it will eventually - * throw an error when actual INSERT happens for the default value. - * - * For example, "CREATE TABLE t1 (c1 INT, c2 NUMERIC DEFAULT '')" can - * be executed without an error, but "INSERT INTO t1 (c1) VALUES (1)" will - * throw an error because an empty string to NUMERIC conversion is disallowed. - * - * To support this behavior without impacting general DML performance, - * we replace the wrong default value with the built-in function, - * sys.babelfish_runtime_error(), which raises an error in execution time. - */ - - Oid argTypes[1]; - List *funcname; - Oid errFuncOid; - Node *result; - - argTypes[0] = ANYCOMPATIBLEOID; - funcname = list_make1(makeString(pstrdup("babelfish_runtime_error"))); - errFuncOid = LookupFuncName(funcname, 1, argTypes, true); - - if (OidIsValid(errFuncOid)) { - char *msg; - List *args; - FuncExpr *errFunc; - Node *coerced; - - msg = pstrdup("An empty or space-only string cannot be converted into numeric/decimal data type"); - - args = list_make1(makeConst(TEXTOID, - -1, - tsql_get_server_collation_oid_internal(false), - -1, - PointerGetDatum(cstring_to_text(msg)), - false, - false)); - errFunc = makeFuncExpr(errFuncOid, targetTypeId, args, 0, 0, COERCE_EXPLICIT_CALL); - - cancel_parser_errposition_callback(pcbstate); - - result = (Node *) errFunc; - - /* If target is a domain, apply constraints. */ - if (baseTypeId != targetTypeId) - result = coerce_to_domain(result, - baseTypeId, baseTypeMod, - targetTypeId, - ccontext, cformat, location, - false); - - coerced = coerce_to_target_type(NULL, result, ANYCOMPATIBLEOID, - NUMERICOID, targetTypeMod, COERCION_PLPGSQL, - cformat, location); - result = coerced ? coerced : result; - - ReleaseSysCache(baseType); - - return result; + /* + * T-SQL allows an empty/space-only string as a + * default constraint of NUMERIC column in CREATE + * TABLE statement. However, it will eventually throw + * an error when actual INSERT happens for the default + * value. + * + * For example, "CREATE TABLE t1 (c1 INT, c2 NUMERIC + * DEFAULT '')" can be executed without an error, but + * "INSERT INTO t1 (c1) VALUES (1)" will throw an + * error because an empty string to NUMERIC conversion + * is disallowed. + * + * To support this behavior without impacting general + * DML performance, we replace the wrong default value + * with the built-in function, + * sys.babelfish_runtime_error(), which raises an + * error in execution time. + */ + + Oid argTypes[1]; + List *funcname; + Oid errFuncOid; + Node *result; + + argTypes[0] = ANYCOMPATIBLEOID; + funcname = list_make1(makeString(pstrdup("babelfish_runtime_error"))); + errFuncOid = LookupFuncName(funcname, 1, argTypes, true); + + if (OidIsValid(errFuncOid)) + { + char *msg; + List *args; + FuncExpr *errFunc; + Node *coerced; + + msg = pstrdup("An empty or space-only string cannot be converted into numeric/decimal data type"); + + args = list_make1(makeConst(TEXTOID, + -1, + tsql_get_server_collation_oid_internal(false), + -1, + PointerGetDatum(cstring_to_text(msg)), + false, + false)); + errFunc = makeFuncExpr(errFuncOid, targetTypeId, args, 0, 0, COERCE_EXPLICIT_CALL); + + cancel_parser_errposition_callback(pcbstate); + + result = (Node *) errFunc; + + /* If target is a domain, apply constraints. */ + if (baseTypeId != targetTypeId) + result = coerce_to_domain(result, + baseTypeId, baseTypeMod, + targetTypeId, + ccontext, cformat, location, + false); + + coerced = coerce_to_target_type(NULL, result, ANYCOMPATIBLEOID, + NUMERICOID, targetTypeMod, COERCION_PLPGSQL, + cformat, location); + result = coerced ? coerced : result; + + ReleaseSysCache(baseType); + + return result; + } + + /* + * If we cannot find errFunc, let normal exception + * happens inside stringTypeDatum(). + */ + newcon->constvalue = stringTypeDatum(baseType, value, inputTypeMod); + break; } - - /* - * If we cannot find errFunc, let normal exception happens inside stringTypeDatum(). - */ - newcon->constvalue = stringTypeDatum(baseType, value, inputTypeMod); - break; - } default: newcon->constvalue = stringTypeDatum(baseType, value, inputTypeMod); } @@ -1022,8 +1078,8 @@ tsql_coerce_string_literal_hook(ParseCallbackState *pcbstate, Oid targetTypeId, ReleaseSysCache(baseType); /* - * NULL means the newcon is updated properly so that - * we can proceed the rest of coerce_type() function. + * NULL means the newcon is updated properly so that we can proceed the + * rest of coerce_type() function. */ return NULL; } @@ -1031,12 +1087,12 @@ tsql_coerce_string_literal_hook(ParseCallbackState *pcbstate, Oid targetTypeId, Datum init_tsql_datatype_precedence_hash_tab(PG_FUNCTION_ARGS) { - HASHCTL hashCtl; - MemoryContext oldContext; + HASHCTL hashCtl; + MemoryContext oldContext; tsql_datatype_precedence_info_entry_t *value; - Oid typoid; - Oid nspoid; - Oid sys_nspoid = get_namespace_oid("sys", true); + Oid typoid; + Oid nspoid; + Oid sys_nspoid = get_namespace_oid("sys", true); TSQLInstrumentation(INSTR_TSQL_INIT_TSQL_DATATYPE_PRECEDENCE_HASH_TAB); @@ -1048,11 +1104,11 @@ init_tsql_datatype_precedence_hash_tab(PG_FUNCTION_ARGS) if (!OidIsValid(sys_nspoid)) PG_RETURN_INT32(0); - if (pltsql_coercion_context == NULL) /* initialize memory context */ + if (pltsql_coercion_context == NULL) /* initialize memory context */ { pltsql_coercion_context = AllocSetContextCreateInternal(NULL, - "PLTSQL CoercionMemory Context", - ALLOCSET_DEFAULT_SIZES); + "PLTSQL CoercionMemory Context", + ALLOCSET_DEFAULT_SIZES); } /* create internal table */ @@ -1069,9 +1125,9 @@ init_tsql_datatype_precedence_hash_tab(PG_FUNCTION_ARGS) hashCtl.entrysize = sizeof(tsql_datatype_precedence_info_entry_t); hashCtl.hcxt = pltsql_coercion_context; ht_tsql_datatype_precedence_info = hash_create("T-SQL datatype precedence", - SPI_processed, - &hashCtl, - HASH_ELEM | HASH_CONTEXT | HASH_BLOBS); + SPI_processed, + &hashCtl, + HASH_ELEM | HASH_CONTEXT | HASH_BLOBS); } /* mark the hash table initialised */ @@ -1080,20 +1136,20 @@ init_tsql_datatype_precedence_hash_tab(PG_FUNCTION_ARGS) for (int i = 0; i < TOTAL_TSQL_PRECEDENCE_COUNT; i++) { nspoid = strcmp(tsql_precedence_infos[i].nsp, "sys") == 0 ? sys_nspoid : PG_CATALOG_NAMESPACE; - typoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, - CStringGetDatum(tsql_precedence_infos[i].typname), ObjectIdGetDatum(nspoid)); + typoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, + CStringGetDatum(tsql_precedence_infos[i].typname), ObjectIdGetDatum(nspoid)); - if (OidIsValid(typoid)) - { + if (OidIsValid(typoid)) + { value = hash_search(ht_tsql_datatype_precedence_info, &typoid, HASH_ENTER, NULL); value->typ = typoid; value->precedence = tsql_precedence_infos[i].precedence; - } - else - { + } + else + { /* type is not loaded. wait for next scan */ inited_ht_tsql_datatype_precedence_info = false; - } + } } PG_RETURN_INT32(0); @@ -1106,25 +1162,29 @@ init_tsql_datatype_precedence_hash_tab(PG_FUNCTION_ARGS) * (i.e. real datatype to integral type - PG uses round but T-SQL uses trunc) */ -// dtrunc in float.c -inline static float8 dtrunc_(float8 arg1) +/* dtrunc in float.c */ +inline static float8 +dtrunc_(float8 arg1) { - float8 result; + float8 result; if (arg1 >= 0) result = floor(arg1); + else result = -floor(-arg1); return result; } -inline static float4 ftrunc_(float4 arg1) +inline static float4 +ftrunc_(float4 arg1) { - float8 result; + float8 result; if (arg1 >= 0) result = floor(arg1); + else result = -floor(-arg1); @@ -1137,7 +1197,7 @@ PG_FUNCTION_INFO_V1(dtrunci8); Datum dtrunci8(PG_FUNCTION_ARGS) { - float8 num = PG_GETARG_FLOAT8(0); + float8 num = PG_GETARG_FLOAT8(0); /* * Get rid of any fractional part in the input. This is so we don't fail @@ -1162,7 +1222,7 @@ PG_FUNCTION_INFO_V1(dtrunci4); Datum dtrunci4(PG_FUNCTION_ARGS) { - float8 num = PG_GETARG_FLOAT8(0); + float8 num = PG_GETARG_FLOAT8(0); /* * Get rid of any fractional part in the input. This is so we don't fail @@ -1187,7 +1247,7 @@ PG_FUNCTION_INFO_V1(dtrunci2); Datum dtrunci2(PG_FUNCTION_ARGS) { - float8 num = PG_GETARG_FLOAT8(0); + float8 num = PG_GETARG_FLOAT8(0); /* * Get rid of any fractional part in the input. This is so we don't fail @@ -1212,7 +1272,7 @@ PG_FUNCTION_INFO_V1(ftrunci8); Datum ftrunci8(PG_FUNCTION_ARGS) { - float4 num = PG_GETARG_FLOAT4(0); + float4 num = PG_GETARG_FLOAT4(0); /* * Get rid of any fractional part in the input. This is so we don't fail @@ -1237,7 +1297,7 @@ PG_FUNCTION_INFO_V1(ftrunci4); Datum ftrunci4(PG_FUNCTION_ARGS) { - float4 num = PG_GETARG_FLOAT4(0); + float4 num = PG_GETARG_FLOAT4(0); /* * Get rid of any fractional part in the input. This is so we don't fail @@ -1262,7 +1322,7 @@ PG_FUNCTION_INFO_V1(ftrunci2); Datum ftrunci2(PG_FUNCTION_ARGS) { - float4 num = PG_GETARG_FLOAT4(0); + float4 num = PG_GETARG_FLOAT4(0); /* * Get rid of any fractional part in the input. This is so we don't fail @@ -1289,9 +1349,9 @@ PG_FUNCTION_INFO_V1(pltsql_bpchar_name); Datum pltsql_text_name(PG_FUNCTION_ARGS) { - text *s = PG_GETARG_TEXT_PP(0); + text *s = PG_GETARG_TEXT_PP(0); Name result; - int len; + int len; const char *saved_dialect = GetConfigOption("babelfishpg_tsql.sql_dialect", true, true); len = VARSIZE_ANY_EXHDR(s); @@ -1299,28 +1359,29 @@ pltsql_text_name(PG_FUNCTION_ARGS) /* Truncate oversize input */ if (len >= NAMEDATALEN) { - if (cstr_to_name_hook) /* to apply special truncation logic */ + if (cstr_to_name_hook) /* to apply special truncation logic */ { - Name n; + Name n; + PG_TRY(); { /* T-SQL casting. follow T-SQL truncation rule */ set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); - n = (*cstr_to_name_hook)(VARDATA_ANY(s), len); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + n = (*cstr_to_name_hook) (VARDATA_ANY(s), len); } PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RE_THROW(); } PG_END_TRY(); set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_NAME(n); } @@ -1330,6 +1391,7 @@ pltsql_text_name(PG_FUNCTION_ARGS) /* We use palloc0 here to ensure result is zero-padded */ result = (Name) palloc0(NAMEDATALEN); + memcpy(NameStr(*result), VARDATA_ANY(s), len); PG_RETURN_NAME(result); @@ -1339,10 +1401,10 @@ pltsql_text_name(PG_FUNCTION_ARGS) Datum pltsql_bpchar_name(PG_FUNCTION_ARGS) { - BpChar *s = PG_GETARG_BPCHAR_PP(0); - char *s_data; + BpChar *s = PG_GETARG_BPCHAR_PP(0); + char *s_data; Name result; - int len; + int len; const char *saved_dialect = GetConfigOption("babelfishpg_tsql.sql_dialect", true, true); len = VARSIZE_ANY_EXHDR(s); @@ -1351,9 +1413,9 @@ pltsql_bpchar_name(PG_FUNCTION_ARGS) /* Truncate oversize input */ if (len >= NAMEDATALEN) { - if (cstr_to_name_hook) /* to apply special truncation logic */ + if (cstr_to_name_hook) /* to apply special truncation logic */ { - Name n; + Name n; /* Remove trailing blanks */ while (len > 0) @@ -1367,21 +1429,21 @@ pltsql_bpchar_name(PG_FUNCTION_ARGS) { /* T-SQL casting. follow T-SQL truncation rule */ set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); - n = (*cstr_to_name_hook)(VARDATA_ANY(s), len); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + n = (*cstr_to_name_hook) (VARDATA_ANY(s), len); } PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RE_THROW(); } PG_END_TRY(); set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_NAME(n); } @@ -1399,6 +1461,7 @@ pltsql_bpchar_name(PG_FUNCTION_ARGS) /* We use palloc0 here to ensure result is zero-padded */ result = (Name) palloc0(NAMEDATALEN); + memcpy(NameStr(*result), s_data, len); PG_RETURN_NAME(result); diff --git a/contrib/babelfishpg_tsql/src/pltsql_function_probin_handler.c b/contrib/babelfishpg_tsql/src/pltsql_function_probin_handler.c index 3ade28c6e1..ae8652fbdf 100644 --- a/contrib/babelfishpg_tsql/src/pltsql_function_probin_handler.c +++ b/contrib/babelfishpg_tsql/src/pltsql_function_probin_handler.c @@ -26,24 +26,25 @@ #define probin_version 1 #define typmod_arr_key "typmod_array" -static char* catalog_read_probin(Oid funcid); -static Jsonb* ProbinJsonbBuilder(CreateFunctionStmt *stmt, char** probin_str); +static char *catalog_read_probin(Oid funcid); +static Jsonb *ProbinJsonbBuilder(CreateFunctionStmt *stmt, char **probin_str); static void pushJsonbPairIntAsText(JsonbParseState **jpstate, - JsonbValue **result, const char* key, const long long int val); + JsonbValue **result, const char *key, const long long int val); static void pushJsonbPairText(JsonbParseState **jpstate, - JsonbValue **result, const char* key, char** val); + JsonbValue **result, const char *key, char **val); static void pushJsonbArray(JsonbParseState **jpstate, - JsonbValue **result, int *items, int array_len); -static void buildTypmodArray(CreateFunctionStmt *stmt, int** typmod_array_p, int* array_len); -int adjustTypmod(Oid oid, int typmod); + JsonbValue **result, int *items, int array_len); +static void buildTypmodArray(CreateFunctionStmt *stmt, int **typmod_array_p, int *array_len); +int adjustTypmod(Oid oid, int typmod); -bool pltsql_function_as_checker(const char *lang, List *as, char **prosrc_str_p, char **probin_str_p) +bool +pltsql_function_as_checker(const char *lang, List *as, char **prosrc_str_p, char **probin_str_p) { /* - * This hook checks if it's pltsql language and if we have two AS - * clauses (probin+prosrc). We'll populate the probin and prosrc strings - * with the AS clauses here and later we'll skip the generation of new - * probin string in write_stored_proc_probin_hook function. + * This hook checks if it's pltsql language and if we have two AS clauses + * (probin+prosrc). We'll populate the probin and prosrc strings with the + * AS clauses here and later we'll skip the generation of new probin + * string in write_stored_proc_probin_hook function. */ if (strcmp(lang, "pltsql") == 0 && as->length == 2) { @@ -54,15 +55,16 @@ bool pltsql_function_as_checker(const char *lang, List *as, char **prosrc_str_p, return false; } -void pltsql_function_probin_writer(CreateFunctionStmt *stmt, Oid languageOid, char** probin_str_p) +void +pltsql_function_probin_writer(CreateFunctionStmt *stmt, Oid languageOid, char **probin_str_p) { - char *langname; - int probin_len; - Jsonb* jb; + char *langname; + int probin_len; + Jsonb *jb; langname = get_language_name(languageOid, true); /* only write probin when language is pltsql */ - if(!langname || strcmp(langname, "pltsql") != 0) + if (!langname || strcmp(langname, "pltsql") != 0) return; /* skip if probin is already set */ @@ -73,24 +75,24 @@ void pltsql_function_probin_writer(CreateFunctionStmt *stmt, Oid languageOid, ch probin_len = strlen(JsonbToCString(NULL, &jb->root, VARSIZE(jb))); /* extra padding space to prevent chunk overwrite */ - *probin_str_p = palloc(probin_len+2); + *probin_str_p = palloc(probin_len + 2); *probin_str_p[0] = '\0'; strncat(*probin_str_p, - JsonbToCString(NULL, &jb->root, probin_len), probin_len+2); + JsonbToCString(NULL, &jb->root, probin_len), probin_len + 2); } void pltsql_function_probin_reader(ParseState *pstate, - List *fargs, - Oid *actual_arg_types, - Oid *declared_arg_types, - Oid funcid) + List *fargs, + Oid *actual_arg_types, + Oid *declared_arg_types, + Oid funcid) { HeapTuple tuple; - int* typmod_array = NULL; - char* probin_c = catalog_read_probin(funcid); + int *typmod_array = NULL; + char *probin_c = catalog_read_probin(funcid); Oid languageOid; - char *langname; + char *langname; tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); if (!HeapTupleIsValid(tuple)) @@ -101,13 +103,13 @@ pltsql_function_probin_reader(ParseState *pstate, langname = get_language_name(languageOid, true); /* only read probin when it is defined and language is pltsql */ - if(!langname || strcmp(langname, "pltsql") != 0 || + if (!langname || strcmp(langname, "pltsql") != 0 || !probin_c || probin_c[0] != '{') { make_fn_arguments(pstate, - fargs, - actual_arg_types, - declared_arg_types); + fargs, + actual_arg_types, + declared_arg_types); } else { @@ -115,9 +117,9 @@ pltsql_function_probin_reader(ParseState *pstate, int i = 0; int numargs = 0; int num_IN_or_OUT_args = 0; - Oid *argtypes; - char **argnames; - char *argmodes; + Oid *argtypes; + char **argnames; + char *argmodes; HeapTuple procTup = NULL; /* @@ -126,7 +128,7 @@ pltsql_function_probin_reader(ParseState *pstate, procTup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); if (!HeapTupleIsValid(procTup)) elog(ERROR, "cache lookup failed for function %u", funcid); - + numargs = get_func_arg_info(procTup, &argtypes, &argnames, &argmodes); if (argmodes) @@ -134,8 +136,9 @@ pltsql_function_probin_reader(ParseState *pstate, for (i = 0; i < numargs; i++) { /* - * We only stored typmod of parameter with mode INPUT/'i', OUTPUT/'o' and INOUT/'b' - * Refer to PROARGMODE_IN in pg_proc.h + * We only stored typmod of parameter with mode INPUT/'i', + * OUTPUT/'o' and INOUT/'b' Refer to PROARGMODE_IN in + * pg_proc.h */ if (argmodes[i] == PROARGMODE_IN || argmodes[i] == PROARGMODE_OUT || @@ -144,19 +147,23 @@ pltsql_function_probin_reader(ParseState *pstate, } i = 0; } - /* No argmodes. Meaning every argument is IN arg. We can simply use numargs */ + + /* + * No argmodes. Meaning every argument is IN arg. We can simply use + * numargs + */ else { num_IN_or_OUT_args = numargs; } /* - * BABEL-2392 There can be less arguments in the EXEC PROC statement compared to - * the full list of arguments desired by the procedure. - * Also the named arguments in the EXEC PROC statement can appear in any order. - * So we have to get the full typmod_array using the number of IN or OUT parameters - * instead of fargs.length. - * Also we need to match the argument name and then invoke adjustTypmod on the + * BABEL-2392 There can be less arguments in the EXEC PROC statement + * compared to the full list of arguments desired by the procedure. + * Also the named arguments in the EXEC PROC statement can appear in + * any order. So we have to get the full typmod_array using the number + * of IN or OUT parameters instead of fargs.length. Also we need to + * match the argument name and then invoke adjustTypmod on the * corresponding typmod_array element. */ probin_json_reader(cstring_to_text(probin_c), &typmod_array, num_IN_or_OUT_args); @@ -167,14 +174,15 @@ pltsql_function_probin_reader(ParseState *pstate, if (IsA(node, NamedArgExpr)) { - NamedArgExpr *na = (NamedArgExpr *) node; - int j = 0; - bool name_matched = false; + NamedArgExpr *na = (NamedArgExpr *) node; + int j = 0; + bool name_matched = false; /* - * BABEL-2392 - * Arguments in EXEC PROC statement can be in any order such as exec mysp @arg2 = 1, @arg1 = 'abc' - * Look for the matching argument name then invoke adjustTypmod on the corresponding typmod_array element + * BABEL-2392 Arguments in EXEC PROC statement can be in any + * order such as exec mysp @arg2 = 1, @arg1 = 'abc' Look for + * the matching argument name then invoke adjustTypmod on the + * corresponding typmod_array element */ for (j = 0; j < num_IN_or_OUT_args; j++) { @@ -189,15 +197,19 @@ pltsql_function_probin_reader(ParseState *pstate, if (name_matched) { node = coerce_to_target_type(pstate, - (Node *) na->arg, - actual_arg_types[i], - declared_arg_types[i], typmod_array[j], - COERCION_EXPLICIT, - COERCE_IMPLICIT_CAST, - -1); + (Node *) na->arg, + actual_arg_types[i], + declared_arg_types[i], typmod_array[j], + COERCION_EXPLICIT, + COERCE_IMPLICIT_CAST, + -1); na->arg = (Expr *) node; } - /* Name unmatched, this should not happen since we've done checks during parse analysis. But just in case */ + + /* + * Name unmatched, this should not happen since we've done + * checks during parse analysis. But just in case + */ else { elog(ERROR, "No match for argument %s of function %u", na->name, funcid); @@ -207,12 +219,12 @@ pltsql_function_probin_reader(ParseState *pstate, { typmod_array[i] += adjustTypmod(declared_arg_types[i], typmod_array[i]); node = coerce_to_target_type(pstate, - node, - actual_arg_types[i], - declared_arg_types[i], typmod_array[i], - COERCION_EXPLICIT, - COERCE_IMPLICIT_CAST, - -1); + node, + actual_arg_types[i], + declared_arg_types[i], typmod_array[i], + COERCION_EXPLICIT, + COERCE_IMPLICIT_CAST, + -1); lfirst(current_fargs) = node; } i++; @@ -221,52 +233,56 @@ pltsql_function_probin_reader(ParseState *pstate, } } -void probin_read_args_typmods(HeapTuple procTup, int nargs, Oid *argtypes, int **typmods) +void +probin_read_args_typmods(HeapTuple procTup, int nargs, Oid *argtypes, int **typmods) { - bool isnull; - char *probin_c = NULL; - Datum tmp = SysCacheGetAttr(PROCOID, procTup, Anum_pg_proc_probin, &isnull); + bool isnull; + char *probin_c = NULL; + Datum tmp = SysCacheGetAttr(PROCOID, procTup, Anum_pg_proc_probin, &isnull); if (!isnull) probin_c = TextDatumGetCString(tmp); - if(!probin_c || probin_c[0] != '{') + if (!probin_c || probin_c[0] != '{') { *typmods = NULL; return; } - probin_json_reader(cstring_to_text(probin_c), typmods, nargs); /* no need to read ret */ + probin_json_reader(cstring_to_text(probin_c), typmods, nargs); /* no need to read ret */ Assert(typmods != NULL); - for (int i=0; ireturnType; - int i = 0; + A_Const *ptr; + List *arg_typmod; + ListCell *x; + TypeName *ret = stmt->returnType; + int i = 0; *array_len_p = list_length(stmt->parameters); /* for functions, we need to store return type typmod */ - if(!stmt->is_procedure) + if (!stmt->is_procedure) { *array_len_p += 1; } /* if no typemod needs to be stored, skip */ if (*array_len_p == 0) return; - *typmod_array_p = (int*)malloc(sizeof(int32_t) * (*array_len_p)); + *typmod_array_p = (int *) malloc(sizeof(int32_t) * (*array_len_p)); memset(*typmod_array_p, 0, sizeof(int32_t) * (*array_len_p)); foreach(x, stmt->parameters) { FunctionParameter *fp = (FunctionParameter *) lfirst(x); + arg_typmod = fp->argType->typmods; - if(!arg_typmod) + if (!arg_typmod) { (*typmod_array_p)[i] = -1; } else { - ListCell* typmod_head = list_head(arg_typmod); - for(int idx = 0; idx < arg_typmod->length; idx++) + ListCell *typmod_head = list_head(arg_typmod); + + for (int idx = 0; idx < arg_typmod->length; idx++) { - ptr = (A_Const *)(lfirst(typmod_head)); + ptr = (A_Const *) (lfirst(typmod_head)); /* numeric type */ - if(idx > 0) + if (idx > 0) { - (*typmod_array_p)[i] = (((*typmod_array_p)[i]) << 16) + ptr->val.ival.ival + VARHDRSZ; + (*typmod_array_p)[i] = (((*typmod_array_p)[i]) << 16) + ptr->val.ival.ival + VARHDRSZ; } else { @@ -415,27 +436,28 @@ static void buildTypmodArray(CreateFunctionStmt *stmt, int** typmod_array_p, int } typmod_head = lnext(arg_typmod, typmod_head); } - + } i++; } /* skip allocating return type typemod for procedures */ - if(stmt->is_procedure) + if (stmt->is_procedure) { return; } /* handle return type */ - if(ret && ret->typmods) + if (ret && ret->typmods) { - ListCell* typmod_head = list_head(ret->typmods); - for(int idx = 0; idx < ret->typmods->length; idx++) + ListCell *typmod_head = list_head(ret->typmods); + + for (int idx = 0; idx < ret->typmods->length; idx++) { - ptr = (A_Const *)(lfirst(typmod_head)); + ptr = (A_Const *) (lfirst(typmod_head)); /* numeric type */ - if(idx > 0) + if (idx > 0) { - (*typmod_array_p)[i] = (((*typmod_array_p)[i]) << 16) + ptr->val.ival.ival + VARHDRSZ; + (*typmod_array_p)[i] = (((*typmod_array_p)[i]) << 16) + ptr->val.ival.ival + VARHDRSZ; } else { @@ -451,51 +473,57 @@ static void buildTypmodArray(CreateFunctionStmt *stmt, int** typmod_array_p, int } void -probin_json_reader(text* probin, int** typmod_arr_p, int typmod_arr_len) +probin_json_reader(text *probin, int **typmod_arr_p, int typmod_arr_len) { - Datum arr_json_d; - Datum elem_d; + Datum arr_json_d; + Datum elem_d; arr_json_d = DirectFunctionCall2(json_object_field, - PointerGetDatum(probin), - PointerGetDatum(cstring_to_text(typmod_arr_key))); + PointerGetDatum(probin), + PointerGetDatum(cstring_to_text(typmod_arr_key))); - *typmod_arr_p = (int*)palloc(sizeof(int32_t) * (typmod_arr_len)); + *typmod_arr_p = (int *) palloc(sizeof(int32_t) * (typmod_arr_len)); - for(int i = 0; i < typmod_arr_len; i++) + for (int i = 0; i < typmod_arr_len; i++) { - char* tmp; + char *tmp; + elem_d = DirectFunctionCall2(json_array_element, arr_json_d, Int32GetDatum(i)); tmp = text_to_cstring(DatumGetTextP(elem_d)); /* remove prefix and trailing \" */ tmp++; - tmp[strlen(tmp)-1]='\0'; + tmp[strlen(tmp) - 1] = '\0'; (*typmod_arr_p)[i] = atoi(tmp); } } /* adjust typmod for some spefic type */ -int adjustTypmod(Oid oid, int typmod) +int +adjustTypmod(Oid oid, int typmod) { - Type baseType; - char* typname; + Type baseType; + char *typname; - if(typmod == 0) + if (typmod == 0) return -1; baseType = typeidType(oid); typname = typeTypeName(baseType); ReleaseSysCache(baseType); - if(strcmp(typname,"varchar") == 0 - || strcmp(typname,"varbinary") == 0 - || strcmp(typname,"binary") == 0 - || strcmp(typname,"nvarchar") == 0 - || strcmp(typname,"nchar") == 0 - || strcmp(typname,"bpchar") == 0) + if (strcmp(typname, "varchar") == 0 + || strcmp(typname, "varbinary") == 0 + || strcmp(typname, "binary") == 0 + || strcmp(typname, "nvarchar") == 0 + || strcmp(typname, "nchar") == 0 + || strcmp(typname, "bpchar") == 0) { if (typmod == -1) - /* Default length without specification of these types is 1 in tsql */ + + /* + * Default length without specification of these types is 1 in + * tsql + */ return VARHDRSZ + 1 - typmod; else return VARHDRSZ; diff --git a/contrib/babelfishpg_tsql/src/pltsql_identity.c b/contrib/babelfishpg_tsql/src/pltsql_identity.c index 974bf58bb2..731fe4a807 100644 --- a/contrib/babelfishpg_tsql/src/pltsql_identity.c +++ b/contrib/babelfishpg_tsql/src/pltsql_identity.c @@ -33,31 +33,32 @@ typedef struct SeqTableIdentityData { Oid relid; /* pg_class OID of this sequence (hash key) */ - bool last_identity_valid; /* check value validity */ + bool last_identity_valid; /* check value validity */ int64 last_identity; /* sequence identity value */ } SeqTableIdentityData; typedef struct ScopeIdentityStack { - struct ScopeIdentityStack *prev; /* previous stack item if any */ - int nest_level; /* nesting depth at which we made entry */ - SeqTableIdentityData last_used_seq_identity_in_scope; /* current scope identity value */ + struct ScopeIdentityStack *prev; /* previous stack item if any */ + int nest_level; /* nesting depth at which we made entry */ + SeqTableIdentityData last_used_seq_identity_in_scope; /* current scope + * identity value */ } ScopeIdentityStack; /* * By default, it is set to false. This is set to true only when we want setval * to set the max/min(current identity value, new identity value to be inserted. */ -bool pltsql_setval_identity_mode = false; +bool pltsql_setval_identity_mode = false; static HTAB *seqhashtabidentity = NULL; static SeqTableIdentityData *last_used_seq_identity = NULL; -static Oid get_table_identity(Oid tableOid); +static Oid get_table_identity(Oid tableOid); static ScopeIdentityStack *last_used_scope_seq_identity = NULL; -static int PltsqlScopeIdentityNestLevel = 0; +static int PltsqlScopeIdentityNestLevel = 0; static void update_scope_identity_stack(SeqTableIdentityData *elm); PG_FUNCTION_INFO_V1(get_identity_param); @@ -69,22 +70,22 @@ PG_FUNCTION_INFO_V1(get_identity_param); Datum get_identity_param(PG_FUNCTION_ARGS) { - text *tablename = PG_GETARG_TEXT_PP(0); - text *optionname = PG_GETARG_TEXT_PP(1); - int prev_sql_dialect = sql_dialect; + text *tablename = PG_GETARG_TEXT_PP(0); + text *optionname = PG_GETARG_TEXT_PP(1); + int prev_sql_dialect = sql_dialect; sql_dialect = SQL_DIALECT_TSQL; - + PG_TRY(); { - RangeVar *tablerv; - Oid tableOid; + RangeVar *tablerv; + Oid tableOid; Oid seqid; - List *seq_options; - ListCell *seq_lc; - char *cur_db_name; - const char *table = text_to_cstring(tablename); - const char *option = text_to_cstring(optionname); + List *seq_options; + ListCell *seq_lc; + char *cur_db_name; + const char *table = text_to_cstring(tablename); + const char *option = text_to_cstring(optionname); tablerv = pltsqlMakeRangeVarFromName(table); cur_db_name = get_cur_db_name(); @@ -106,9 +107,9 @@ get_identity_param(PG_FUNCTION_ARGS) seqid = get_table_identity(tableOid); seq_options = sequence_options(seqid); - foreach (seq_lc, seq_options) + foreach(seq_lc, seq_options) { - DefElem *defel = (DefElem *) lfirst(seq_lc); + DefElem *defel = (DefElem *) lfirst(seq_lc); if (strcmp(defel->defname, option) == 0) { @@ -138,15 +139,15 @@ PG_FUNCTION_INFO_V1(get_identity_current); Datum get_identity_current(PG_FUNCTION_ARGS) { - text *tablename = PG_GETARG_TEXT_PP(0); - const char *table = text_to_cstring(tablename); - RangeVar *tablerv; - Oid tableOid; + text *tablename = PG_GETARG_TEXT_PP(0); + const char *table = text_to_cstring(tablename); + RangeVar *tablerv; + Oid tableOid; Oid seqid = InvalidOid; - List *seq_options; - ListCell *seq_lc; + List *seq_options; + ListCell *seq_lc; int prev_sql_dialect = sql_dialect; - char *cur_db_name; + char *cur_db_name; sql_dialect = SQL_DIALECT_TSQL; @@ -190,9 +191,9 @@ get_identity_current(PG_FUNCTION_ARGS) { seq_options = sequence_options(seqid); - foreach (seq_lc, seq_options) + foreach(seq_lc, seq_options) { - DefElem *defel = (DefElem *) lfirst(seq_lc); + DefElem *defel = (DefElem *) lfirst(seq_lc); if (strcmp(defel->defname, "start") == 0) { @@ -219,8 +220,8 @@ get_identity_current(PG_FUNCTION_ARGS) static Oid get_table_identity(Oid tableOid) { - Relation rel; - TupleDesc tupdesc; + Relation rel; + TupleDesc tupdesc; AttrNumber attnum; Oid seqid = InvalidOid; @@ -230,9 +231,10 @@ get_table_identity(Oid tableOid) for (attnum = 0; attnum < tupdesc->natts; attnum++) { Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum); + if (attr->attidentity) { - seqid = getIdentitySequence(tableOid, attnum+1, false); + seqid = getIdentitySequence(tableOid, attnum + 1, false); break; } } @@ -248,8 +250,8 @@ get_table_identity(Oid tableOid) void pltsql_update_last_identity(Oid seqid, int64 val) { - SeqTableIdentityData *elm; - bool found; + SeqTableIdentityData *elm; + bool found; if (seqhashtabidentity == NULL) { @@ -304,7 +306,10 @@ last_scope_identity_value(void) { SeqTableIdentityData *curr_seq_identity = NULL; - /* scope_identity is not defined or defined but it is not on the same level as the current scope */ + /* + * scope_identity is not defined or defined but it is not on the same + * level as the current scope + */ if (last_used_scope_seq_identity == NULL || last_used_scope_seq_identity->nest_level != PltsqlScopeIdentityNestLevel) { @@ -312,7 +317,7 @@ last_scope_identity_value(void) (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("last scope identity not yet defined in this session"))); } - + /* Check the current identity in the scope */ curr_seq_identity = &last_used_scope_seq_identity->last_used_seq_identity_in_scope; if (!curr_seq_identity->relid || @@ -344,7 +349,8 @@ pltsql_nextval_identity(Oid seqid, int64 val) pltsql_update_last_identity(seqid, val); } -void pltsql_resetcache_identity() +void +pltsql_resetcache_identity() { if (prev_pltsql_resetcache_hook) prev_pltsql_resetcache_hook(); @@ -357,8 +363,10 @@ void pltsql_resetcache_identity() last_used_seq_identity = NULL; - while (last_used_scope_seq_identity) { + while (last_used_scope_seq_identity) + { ScopeIdentityStack *prev = last_used_scope_seq_identity->prev; + pfree(last_used_scope_seq_identity); last_used_scope_seq_identity = prev; @@ -379,15 +387,15 @@ pltsql_setval_identity(Oid seqid, int64 val, int64 last_val) { if (sql_dialect == SQL_DIALECT_TSQL && pltsql_setval_identity_mode) { - ListCell *seq_lc; - List *seq_options; - int64 seq_incr = 0; + ListCell *seq_lc; + List *seq_options; + int64 seq_incr = 0; seq_options = sequence_options(seqid); - foreach (seq_lc, seq_options) + foreach(seq_lc, seq_options) { - DefElem *defel = (DefElem *) lfirst(seq_lc); + DefElem *defel = (DefElem *) lfirst(seq_lc); if (strcmp(defel->defname, "increment") == 0) seq_incr = defGetInt64(defel); @@ -404,20 +412,22 @@ pltsql_setval_identity(Oid seqid, int64 val, int64 last_val) } -static void update_scope_identity_stack(SeqTableIdentityData *elm) +static void +update_scope_identity_stack(SeqTableIdentityData *elm) { ScopeIdentityStack *scope_identity = NULL; /* - * If current elm is in the same scope (same nest_level) as the current top element in the stack, - * then update the top element to point to elm. Otherwise, push elm to the stack and make - * it the new scope identity value in the new scope. - */ + * If current elm is in the same scope (same nest_level) as the current + * top element in the stack, then update the top element to point to elm. + * Otherwise, push elm to the stack and make it the new scope identity + * value in the new scope. + */ if (last_used_scope_seq_identity && last_used_scope_seq_identity->nest_level == PltsqlScopeIdentityNestLevel) { /* Make a deep copy of elm. We do not know where elm came from */ memcpy((void *) &last_used_scope_seq_identity->last_used_seq_identity_in_scope, - (void *) elm, sizeof(SeqTableIdentityData)); + (void *) elm, sizeof(SeqTableIdentityData)); return; } @@ -425,24 +435,26 @@ static void update_scope_identity_stack(SeqTableIdentityData *elm) Assert(!last_used_scope_seq_identity || last_used_scope_seq_identity->nest_level < PltsqlScopeIdentityNestLevel); scope_identity = (ScopeIdentityStack *) MemoryContextAllocZero(TopMemoryContext, - sizeof(ScopeIdentityStack)); + sizeof(ScopeIdentityStack)); scope_identity->prev = last_used_scope_seq_identity; scope_identity->nest_level = PltsqlScopeIdentityNestLevel; /* Make a deep copy of elm. We do not know where elm came from */ memcpy((void *) &scope_identity->last_used_seq_identity_in_scope, - (void *) elm, sizeof(SeqTableIdentityData)); + (void *) elm, sizeof(SeqTableIdentityData)); last_used_scope_seq_identity = scope_identity; } -int pltsql_new_scope_identity_nest_level(void) +int +pltsql_new_scope_identity_nest_level(void) { return ++PltsqlScopeIdentityNestLevel; } -void pltsql_revert_last_scope_identity(int nest_level) +void +pltsql_revert_last_scope_identity(int nest_level) { ScopeIdentityStack *old_top = NULL; @@ -457,4 +469,4 @@ void pltsql_revert_last_scope_identity(int nest_level) old_top = last_used_scope_seq_identity; last_used_scope_seq_identity = old_top->prev; pfree(old_top); -} \ No newline at end of file +} diff --git a/contrib/babelfishpg_tsql/src/pltsql_instr.h b/contrib/babelfishpg_tsql/src/pltsql_instr.h index 9bd99421dc..ae16a39b5a 100644 --- a/contrib/babelfishpg_tsql/src/pltsql_instr.h +++ b/contrib/babelfishpg_tsql/src/pltsql_instr.h @@ -11,7 +11,8 @@ #define METRIC_TYPE int -typedef enum PgTsqlInstrMetricType { +typedef enum PgTsqlInstrMetricType +{ INSTR_START = -1, INSTR_TSQL_ALTER_COLUMN, @@ -495,7 +496,7 @@ typedef enum PgTsqlInstrMetricType { INSTR_TSQL_BINARYFLOAT4, INSTR_TSQL_BINARYFLOAT8, INSTR_TSQL_VARBINARY_COMPARE, - + INSTR_TSQL_SMALLDATETIMEIN, INSTR_TSQL_TIME2SMALLDATETIME, INSTR_TSQL_DATE2SMALLDATETIME, @@ -604,7 +605,7 @@ typedef enum PgTsqlInstrMetricType { INSTR_UNSUPPORTED_TSQL_PROCID, INSTR_TSQL_VERSION, INSTR_TSQL_SERVERNAME, - + INSTR_UNSUPPORTED_TSQL_OPTION_ROWCOUNT, INSTR_TSQL_FETCH_STATUS, @@ -638,6 +639,6 @@ typedef enum PgTsqlInstrMetricType { INSTR_UNSUPPORTED_TSQL_SELECT_COL_ALIAS, INSTR_UNSUPPORTED_TSQL_SERVERNAME_IN_NAME, INSTR_UNSUPPORTED_TSQL_OPTION_NO_BROWSETABLE, - + INSTR_TSQL_COUNT } PgTsqlInstrMetricType; diff --git a/contrib/babelfishpg_tsql/src/pltsql_ruleutils.c b/contrib/babelfishpg_tsql/src/pltsql_ruleutils.c index 8b2036e362..5ae29053e9 100644 --- a/contrib/babelfishpg_tsql/src/pltsql_ruleutils.c +++ b/contrib/babelfishpg_tsql/src/pltsql_ruleutils.c @@ -341,20 +341,20 @@ static Plan *find_recursive_union(deparse_namespace *dpns, WorkTableScan *wtscan); static text *string_to_text(char *str); static char *tsql_get_constraintdef_worker(Oid constraintId, bool fullCommand, - int prettyFlags, bool missing_ok); + int prettyFlags, bool missing_ok); static text *tsql_get_expr_worker(text *expr, Oid relid, const char *relname, - int prettyFlags); + int prettyFlags); static char *tsql_printTypmod(const char *typname, int32 typmod, Oid typmodout); static char *tsql_format_type_extended(Oid type_oid, int32 typemod, bits16 flags); -int tsql_print_function_arguments(StringInfo buf, HeapTuple proctup, - bool print_table_args, bool print_defaults, int** typmod_arr_arg, bool* has_tvp); -char *tsql_quote_qualified_identifier(const char *qualifier, const char *ident); +int tsql_print_function_arguments(StringInfo buf, HeapTuple proctup, + bool print_table_args, bool print_defaults, int **typmod_arr_arg, bool *has_tvp); +char *tsql_quote_qualified_identifier(const char *qualifier, const char *ident); const char *tsql_quote_identifier(const char *ident); -char* generate_tsql_collation_name(Oid collOid); -int adjustTypmod(Oid oid, int typmod); +char *generate_tsql_collation_name(Oid collOid); +int adjustTypmod(Oid oid, int typmod); static void tsql_print_function_rettype(StringInfo buf, HeapTuple proctup, - int** typmod_arr_ret, int number_args); -extern void probin_json_reader(text* probin, int** typmod_arr_p, int typmod_arr_len); + int **typmod_arr_ret, int number_args); +extern void probin_json_reader(text *probin, int **typmod_arr_p, int typmod_arr_len); PG_FUNCTION_INFO_V1(tsql_get_constraintdef); /* @@ -399,56 +399,57 @@ PG_FUNCTION_INFO_V1(tsql_get_expr); Datum tsql_get_expr(PG_FUNCTION_ARGS) { - text *expr = PG_GETARG_TEXT_PP(0); - Oid relid = PG_GETARG_OID(1); - int prettyFlags; - char *relname; - - prettyFlags = PRETTYFLAG_INDENT; - - if (OidIsValid(relid)) - { - /* Get the name for the relation */ - relname = get_rel_name(relid); - } - else - { - relname = NULL; - } - /* - * If the relname is NULL, don't throw an error, just return - * NULL. This is a bit questionable, but it's what we've done - * historically, and it can help avoid unwanted failures when - * examining catalog entries for just-deleted relations. - */ - if (relname == NULL) - PG_RETURN_NULL(); - - PG_RETURN_TEXT_P(tsql_get_expr_worker(expr, relid, relname, prettyFlags)); + text *expr = PG_GETARG_TEXT_PP(0); + Oid relid = PG_GETARG_OID(1); + int prettyFlags; + char *relname; + + prettyFlags = PRETTYFLAG_INDENT; + + if (OidIsValid(relid)) + { + /* Get the name for the relation */ + relname = get_rel_name(relid); + } + else + { + relname = NULL; + } + + /* + * If the relname is NULL, don't throw an error, just return NULL. This + * is a bit questionable, but it's what we've done historically, and it + * can help avoid unwanted failures when examining catalog entries for + * just-deleted relations. + */ + if (relname == NULL) + PG_RETURN_NULL(); + + PG_RETURN_TEXT_P(tsql_get_expr_worker(expr, relid, relname, prettyFlags)); } static text * tsql_get_expr_worker(text *expr, Oid relid, const char *relname, int prettyFlags) { - Node *node; - List *context; - char *exprstr; + Node *node; + List *context; + char *exprstr; - /* Convert input TEXT object to C string */ - exprstr = text_to_cstring(expr); + /* Convert input TEXT object to C string */ + exprstr = text_to_cstring(expr); - /* Convert expression to node tree */ - node = (Node *) stringToNode(exprstr); + /* Convert expression to node tree */ + node = (Node *) stringToNode(exprstr); - pfree(exprstr); + pfree(exprstr); - /* Prepare deparse context if needed */ - if (OidIsValid(relid)) - context = deparse_context_for(relname, relid); - else - context = NIL; - /* Deparse */ - return string_to_text(deparse_expression_pretty(node, context, false, false,prettyFlags, 0)); + /* Prepare deparse context if needed */ + if (OidIsValid(relid)) + context = deparse_context_for(relname, relid); + else + context = NIL; + /* Deparse */ + return string_to_text(deparse_expression_pretty(node, context, false, false, prettyFlags, 0)); } /* @@ -468,19 +469,19 @@ tsql_get_functiondef(PG_FUNCTION_ARGS) { Oid funcid = PG_GETARG_OID(0); StringInfoData buf; - HeapTuple proctup; + HeapTuple proctup; Form_pg_proc proc; bool isfunction; Datum tmp; - bool isnull; + bool isnull; const char *prosrc; const char *name; const char *nsp; const char *nnsp; - bool has_tvp = false; - int* typmod_arr = NULL; - int number_args; - char *probin_c = NULL; + bool has_tvp = false; + int *typmod_arr = NULL; + int number_args; + char *probin_c = NULL; /* Look up the function */ proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); @@ -490,7 +491,7 @@ tsql_get_functiondef(PG_FUNCTION_ARGS) initStringInfo(&buf); proc = (Form_pg_proc) GETSTRUCT(proctup); - if(strcmp(get_language_name(proc->prolang, false), "pltsql") != 0) + if (strcmp(get_language_name(proc->prolang, false), "pltsql") != 0) { ReleaseSysCache(proctup); PG_RETURN_NULL(); @@ -504,16 +505,18 @@ tsql_get_functiondef(PG_FUNCTION_ARGS) * replaced. */ nsp = get_namespace_name(proc->pronamespace); - nnsp = get_logical_schema_name(nsp,true); + nnsp = get_logical_schema_name(nsp, true); appendStringInfo(&buf, "CREATE %s %s", isfunction ? "FUNCTION" : "PROCEDURE", tsql_quote_qualified_identifier(nnsp, name)); - if(isfunction || proc->pronargs > 0) + if (isfunction || proc->pronargs > 0) appendStringInfoString(&buf, "("); - - /* we will not pfree name because as we can see name = NameStr(proc->proname) - * here we are not allocating extra space for name, we’re just using proc-> proname. - * also at the end, we’re releasing proctup (that will free proc->proname). + + /* + * we will not pfree name because as we can see name = + * NameStr(proc->proname) here we are not allocating extra space for name, + * we’re just using proc-> proname. also at the end, we’re releasing + * proctup (that will free proc->proname). */ pfree((char *) nsp); if (nnsp) @@ -523,9 +526,9 @@ tsql_get_functiondef(PG_FUNCTION_ARGS) if (!isnull) probin_c = TextDatumGetCString(tmp); - if(!probin_c || probin_c[0] != '{') + if (!probin_c || probin_c[0] != '{') PG_RETURN_NULL(); - + number_args = proc->pronargs; if (isfunction) number_args++; @@ -537,16 +540,16 @@ tsql_get_functiondef(PG_FUNCTION_ARGS) if (has_tvp) PG_RETURN_NULL(); - if(isfunction || proc->pronargs > 0) + if (isfunction || proc->pronargs > 0) appendStringInfoString(&buf, ")"); if (isfunction) { appendStringInfoString(&buf, " RETURNS "); tsql_print_function_rettype(&buf, proctup, &typmod_arr, number_args); } - if(typmod_arr) + if (typmod_arr) pfree(typmod_arr); - + /* Emit some miscellaneous options on one line */ if (proc->proisstrict) appendStringInfoString(&buf, " WITH RETURNS NULL ON NULL INPUT"); @@ -556,7 +559,7 @@ tsql_get_functiondef(PG_FUNCTION_ARGS) appendStringInfoString(&buf, " AS "); tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_prosrc, &isnull); - prosrc = TextDatumGetCString(tmp); + prosrc = TextDatumGetCString(tmp); appendStringInfoString(&buf, prosrc); ReleaseSysCache(proctup); @@ -569,50 +572,51 @@ tsql_get_functiondef(PG_FUNCTION_ARGS) PG_FUNCTION_INFO_V1(tsql_get_returnTypmodValue); /* * function that will return the typmod value of return type - */ -Datum -tsql_get_returnTypmodValue(PG_FUNCTION_ARGS){ - Oid funcid = PG_GETARG_OID(0); - HeapTuple proctup; - Form_pg_proc proc; - bool isfunction; - Datum tmp; - bool isnull; - char *probin_c = NULL; - int* typmod_arr = NULL; - int number_args; - - proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); - if (!HeapTupleIsValid(proctup)) - PG_RETURN_INT32(-1); - - proc = (Form_pg_proc) GETSTRUCT(proctup); - - isfunction = (proc->prokind != PROKIND_PROCEDURE); - - if (!isfunction) - { - ReleaseSysCache(proctup); - PG_RETURN_INT32(-1) ; - } - - tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_probin, &isnull); - - if (!isnull) - probin_c = TextDatumGetCString(tmp); - if(!probin_c || probin_c[0] != '{') - PG_RETURN_INT32(-1); - - number_args = proc->pronargs; - number_args++; - - probin_json_reader(cstring_to_text(probin_c), &typmod_arr, number_args); - pfree(probin_c); - if (typmod_arr[number_args-1] != -1) - typmod_arr[number_args-1] += adjustTypmod(proc->prorettype, typmod_arr[number_args-1]); - - ReleaseSysCache(proctup); - PG_RETURN_INT32(typmod_arr[number_args-1]); + */ +Datum +tsql_get_returnTypmodValue(PG_FUNCTION_ARGS) +{ + Oid funcid = PG_GETARG_OID(0); + HeapTuple proctup; + Form_pg_proc proc; + bool isfunction; + Datum tmp; + bool isnull; + char *probin_c = NULL; + int *typmod_arr = NULL; + int number_args; + + proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); + if (!HeapTupleIsValid(proctup)) + PG_RETURN_INT32(-1); + + proc = (Form_pg_proc) GETSTRUCT(proctup); + + isfunction = (proc->prokind != PROKIND_PROCEDURE); + + if (!isfunction) + { + ReleaseSysCache(proctup); + PG_RETURN_INT32(-1); + } + + tmp = SysCacheGetAttr(PROCOID, proctup, Anum_pg_proc_probin, &isnull); + + if (!isnull) + probin_c = TextDatumGetCString(tmp); + if (!probin_c || probin_c[0] != '{') + PG_RETURN_INT32(-1); + + number_args = proc->pronargs; + number_args++; + + probin_json_reader(cstring_to_text(probin_c), &typmod_arr, number_args); + pfree(probin_c); + if (typmod_arr[number_args - 1] != -1) + typmod_arr[number_args - 1] += adjustTypmod(proc->prorettype, typmod_arr[number_args - 1]); + + ReleaseSysCache(proctup); + PG_RETURN_INT32(typmod_arr[number_args - 1]); } @@ -621,7 +625,7 @@ tsql_get_returnTypmodValue(PG_FUNCTION_ARGS){ */ static char * tsql_get_constraintdef_worker(Oid constraintId, bool fullCommand, - int prettyFlags, bool missing_ok) + int prettyFlags, bool missing_ok) { HeapTuple tup; Form_pg_constraint conForm; @@ -762,12 +766,12 @@ tsql_get_constraintdef_worker(Oid constraintId, bool fullCommand, * to the specified buffer. */ static void -tsql_print_function_rettype(StringInfo buf, HeapTuple proctup, int** typmod_arr_ret, int number_args) +tsql_print_function_rettype(StringInfo buf, HeapTuple proctup, int **typmod_arr_ret, int number_args) { Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup); int ntabargs = 0; StringInfoData rbuf; - bool has_tvp = false; + bool has_tvp = false; initStringInfo(&rbuf); @@ -787,13 +791,13 @@ tsql_print_function_rettype(StringInfo buf, HeapTuple proctup, int** typmod_arr_ /* Not a table function, so do the normal thing */ if (proc->proretset) appendStringInfoString(&rbuf, "SETOF "); - if ((*typmod_arr_ret)[number_args-1] != -1) - (*typmod_arr_ret)[number_args-1] += adjustTypmod(proc->prorettype, (*typmod_arr_ret)[number_args-1]); - appendStringInfoString(&rbuf, tsql_format_type_extended(proc->prorettype, (*typmod_arr_ret)[number_args-1], FORMAT_TYPE_TYPEMOD_GIVEN)); + if ((*typmod_arr_ret)[number_args - 1] != -1) + (*typmod_arr_ret)[number_args - 1] += adjustTypmod(proc->prorettype, (*typmod_arr_ret)[number_args - 1]); + appendStringInfoString(&rbuf, tsql_format_type_extended(proc->prorettype, (*typmod_arr_ret)[number_args - 1], FORMAT_TYPE_TYPEMOD_GIVEN)); } appendBinaryStringInfo(buf, rbuf.data, rbuf.len); - pfree(rbuf.data); + pfree(rbuf.data); } /* @@ -804,7 +808,7 @@ tsql_print_function_rettype(StringInfo buf, HeapTuple proctup, int** typmod_arr_ */ int tsql_print_function_arguments(StringInfo buf, HeapTuple proctup, - bool print_table_args, bool print_defaults, int** typmod_arr_arg, bool* has_tvp) + bool print_table_args, bool print_defaults, int **typmod_arr_arg, bool *has_tvp) { Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup); HeapTuple bbffunctuple = NULL; @@ -925,20 +929,20 @@ tsql_print_function_arguments(StringInfo buf, HeapTuple proctup, appendStringInfoString(buf, ", "); if (argname && argname[0]) - appendStringInfo(buf,"%s ", tsql_quote_identifier(argname)); - if ((*typmod_arr_arg)[i] != -1) - (*typmod_arr_arg)[i] += adjustTypmod(argtype, (*typmod_arr_arg)[i]); + appendStringInfo(buf, "%s ", tsql_quote_identifier(argname)); + if ((*typmod_arr_arg)[i] != -1) + (*typmod_arr_arg)[i] += adjustTypmod(argtype, (*typmod_arr_arg)[i]); appendStringInfoString(buf, tsql_format_type_extended(argtype, (*typmod_arr_arg)[i], FORMAT_TYPE_TYPEMOD_GIVEN)); if (modename && strcmp(modename, "") != 0) - appendStringInfo(buf," %s", modename); + appendStringInfo(buf, " %s", modename); if (print_defaults && isinput && default_positions_available) { if (nextdefaultposition != NULL) { - int position = intVal((Node *) lfirst(nextdefaultposition)); - Node *expr; + int position = intVal((Node *) lfirst(nextdefaultposition)); + Node *expr; Assert(nextargdefault != NULL); expr = (Node *) lfirst(nextargdefault); @@ -1041,7 +1045,7 @@ generate_operator_name(Oid operid, Oid arg1, Oid arg2) operform = (Form_pg_operator) GETSTRUCT(opertup); oprname = NameStr(operform->oprname); - if(strcmp(oprname,"~~") == 0) + if (strcmp(oprname, "~~") == 0) oprname = "LIKE"; @@ -1277,16 +1281,16 @@ get_rule_expr(Node *node, deparse_context *context, List *args = expr->args; Node *arg1 = (Node *) linitial(args); Node *arg2 = (Node *) lsecond(args); - char *opername; + char *opername; if (!PRETTY_PAREN(context)) appendStringInfoChar(buf, '('); get_rule_expr_paren(arg1, context, true, node); opername = generate_operator_name(expr->opno, exprType(arg1), - get_base_element_type(exprType(arg2))); - if (strcmp(opername,"=")==0) + get_base_element_type(exprType(arg2))); + if (strcmp(opername, "=") == 0) appendStringInfoString(buf, " IN ("); - else if (strcmp(opername,"<>")==0) + else if (strcmp(opername, "<>") == 0) appendStringInfoString(buf, " NOT IN ("); get_rule_expr_paren(arg2, context, true, node); @@ -1462,6 +1466,7 @@ string_to_text(char *str) text *result; result = cstring_to_text(str); + pfree(str); return result; } @@ -1702,9 +1707,9 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context) appendStringInfoChar(buf, '*'); if (istoplevel) appendStringInfo(buf, " AS %s)", - tsql_format_type_extended(var->vartype, - var->vartypmod, - FORMAT_TYPE_TYPEMOD_GIVEN)); + tsql_format_type_extended(var->vartype, + var->vartypmod, + FORMAT_TYPE_TYPEMOD_GIVEN)); } return attname; @@ -1748,8 +1753,8 @@ get_const_expr(Const *constval, deparse_context *context, int showtype) { appendStringInfo(buf, "CAST(%s AS %s)", valbuf->data, tsql_format_type_extended(constval->consttype, - constval->consttypmod, - FORMAT_TYPE_TYPEMOD_GIVEN)); + constval->consttypmod, + FORMAT_TYPE_TYPEMOD_GIVEN)); get_const_collation(constval, context); } else @@ -1827,7 +1832,8 @@ get_const_expr(Const *constval, deparse_context *context, int showtype) return; } - /* XXX this code has to be kept in sync with the behavior of the parser, + /* + * XXX this code has to be kept in sync with the behavior of the parser, * especially make_const. */ switch (constval->consttype) @@ -1859,8 +1865,8 @@ get_const_expr(Const *constval, deparse_context *context, int showtype) { appendStringInfo(buf, "CAST(%s AS %s)", valbuf->data, tsql_format_type_extended(constval->consttype, - constval->consttypmod, - FORMAT_TYPE_TYPEMOD_GIVEN)); + constval->consttypmod, + FORMAT_TYPE_TYPEMOD_GIVEN)); } else { @@ -2054,10 +2060,10 @@ get_func_expr(FuncExpr *expr, deparse_context *context, context->special_exprkind); /* - * AT TIMEZONE from TSQL is parsed to timezone function internally. - * While de-parsing, convert it to AT TIME ZONE explicitly. + * AT TIMEZONE from TSQL is parsed to timezone function internally. While + * de-parsing, convert it to AT TIME ZONE explicitly. */ - if (strcmp(funcname,"timezone") == 0) + if (strcmp(funcname, "timezone") == 0) { get_rule_expr((Node *) list_nth(expr->args, 1), context, false); appendStringInfoString(buf, " AT TIME ZONE "); @@ -2365,9 +2371,10 @@ const char * tsql_quote_identifier(const char *ident) { /* - * Can avoid quoting if ident starts with a lowercase letter, underscore or at the rate(@) - * and contains only lowercase letters, digits, at the rate or underscores, *and* is - * not any SQL keyword. Otherwise, supply quotes. + * Can avoid quoting if ident starts with a lowercase letter, underscore + * or at the rate(@) and contains only lowercase letters, digits, at the + * rate or underscores, *and* is not any SQL keyword. Otherwise, supply + * quotes. */ int nquotes = 0; bool safe; @@ -2379,7 +2386,7 @@ tsql_quote_identifier(const char *ident) * would like to use macros here, but they might yield unwanted * locale-specific results... */ - safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_' || ident[0] == '@' ); + safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_' || ident[0] == '@'); for (ptr = ident; *ptr; ptr++) { @@ -2387,7 +2394,7 @@ tsql_quote_identifier(const char *ident) if ((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || - (ch == '_') || (ch == '@') ) + (ch == '_') || (ch == '@')) { /* okay */ } @@ -2399,7 +2406,7 @@ tsql_quote_identifier(const char *ident) } } - if (quote_all_identifiers) + if (quote_all_identifiers) safe = false; if (safe) @@ -2419,11 +2426,12 @@ tsql_quote_identifier(const char *ident) } if (safe) - return ident; /* no change needed */ + return ident; /* no change needed */ result = (char *) palloc(strlen(ident) + nquotes + 2 + 1); optr = result; + *optr++ = '"'; for (ptr = ident; *ptr; ptr++) { @@ -2447,7 +2455,7 @@ tsql_quote_identifier(const char *ident) */ char * tsql_quote_qualified_identifier(const char *qualifier, - const char *ident) + const char *ident) { StringInfoData buf; @@ -2612,6 +2620,7 @@ get_coercion_expr(Node *arg, deparse_context *context, StringInfo buf = context->buf; appendStringInfoString(buf, "CAST("); + /* * Since parse_coerce.c doesn't immediately collapse application of * length-coercion functions to constants, what we'll typically see in @@ -2652,7 +2661,7 @@ get_coercion_expr(Node *arg, deparse_context *context, */ appendStringInfo(buf, " AS %s)", tsql_format_type_extended(resulttype, resulttypmod, - FORMAT_TYPE_TYPEMOD_GIVEN)); + FORMAT_TYPE_TYPEMOD_GIVEN)); } /* @@ -2787,12 +2796,13 @@ find_recursive_union(deparse_namespace *dpns, WorkTableScan *wtscan) static char * tsql_format_type_extended(Oid type_oid, int32 typemod, bits16 flags) { - HeapTuple tuple; - Form_pg_type typeform; - Datum tsql_typename; - char *buf; - char *nspname; - bool with_typemod; + HeapTuple tuple; + Form_pg_type typeform; + Datum tsql_typename; + char *buf; + char *nspname; + bool with_typemod; + LOCAL_FCINFO(fcinfo, 1); if (type_oid == InvalidOid && (flags & FORMAT_TYPE_ALLOW_INVALID) != 0) @@ -2812,7 +2822,7 @@ tsql_format_type_extended(Oid type_oid, int32 typemod, bits16 flags) * Assign -1 as typmod which is equivalent to not printing the typmod for * smalldatetime */ - if ((*common_utility_plugin_ptr->is_tsql_smalldatetime_datatype)(type_oid)) + if ((*common_utility_plugin_ptr->is_tsql_smalldatetime_datatype) (type_oid)) typemod = -1; with_typemod = (flags & FORMAT_TYPE_TYPEMOD_GIVEN) != 0 && (typemod >= 0); @@ -2854,25 +2864,25 @@ tsql_format_type_extended(Oid type_oid, int32 typemod, bits16 flags) * Assign correct typename in case of sys.binary, it gives bbf_binary * internally */ - if ((*common_utility_plugin_ptr->is_tsql_binary_datatype)(type_oid)) - buf = pstrdup("binary"); - if ((*common_utility_plugin_ptr->is_tsql_varbinary_datatype)(type_oid)) - buf = pstrdup("varbinary"); + if ((*common_utility_plugin_ptr->is_tsql_binary_datatype) (type_oid)) + buf = pstrdup("binary"); + if ((*common_utility_plugin_ptr->is_tsql_varbinary_datatype) (type_oid)) + buf = pstrdup("varbinary"); } if (with_typemod) { - int typmodout = typeform->typmodout; + int typmodout = typeform->typmodout; + /* - * In case of time, datetime2 or datetimeoffset print typmod - * info directly because it uses timestamp typmodout function - * which appends timezone data along with typmod which is not - * required. Directly print typename for smalldatetime as it - * doesn't support typmod. - */ + * In case of time, datetime2 or datetimeoffset print typmod info + * directly because it uses timestamp typmodout function which appends + * timezone data along with typmod which is not required. Directly + * print typename for smalldatetime as it doesn't support typmod. + */ if (type_oid == TIMEOID || - (*common_utility_plugin_ptr->is_tsql_datetime2_datatype)(type_oid) || - (*common_utility_plugin_ptr->is_tsql_datetimeoffset_datatype)(type_oid)) + (*common_utility_plugin_ptr->is_tsql_datetime2_datatype) (type_oid) || + (*common_utility_plugin_ptr->is_tsql_datetimeoffset_datatype) (type_oid)) { typmodout = InvalidOid; } @@ -2906,7 +2916,7 @@ tsql_printTypmod(const char *typname, int32 typmod, Oid typmodout) char *tmstr; tmstr = DatumGetCString(OidFunctionCall1(typmodout, - Int32GetDatum(typmod))); + Int32GetDatum(typmod))); res = psprintf("%s%s", typname, tmstr); } return res; @@ -2918,14 +2928,15 @@ tsql_printTypmod(const char *typname, int32 typmod, Oid typmodout) * name exists. If exists, it returns the TSQL collation name. Otherwise, * it returns the BBF collation name. */ -char* +char * generate_tsql_collation_name(Oid collOid) { - char* res = NULL; - char* translated_res = NULL; + char *res = NULL; + char *translated_res = NULL; + res = generate_collation_name(collOid); if (res) - translated_res = (char*)tsql_translate_bbf_collation_to_tsql_collation(res); + translated_res = (char *) tsql_translate_bbf_collation_to_tsql_collation(res); if (translated_res) { @@ -2934,4 +2945,3 @@ generate_tsql_collation_name(Oid collOid) } return res; } - diff --git a/contrib/babelfishpg_tsql/src/pltsql_utils.c b/contrib/babelfishpg_tsql/src/pltsql_utils.c index 5f0ee47912..e39b417766 100644 --- a/contrib/babelfishpg_tsql/src/pltsql_utils.c +++ b/contrib/babelfishpg_tsql/src/pltsql_utils.c @@ -5,7 +5,7 @@ #include "catalog/pg_type.h" #include "catalog/pg_trigger.h" #include "catalog/pg_constraint.h" -#include "parser/parser.h" /* only needed for GUC variables */ +#include "parser/parser.h" /* only needed for GUC variables */ #include "parser/parse_type.h" #include "mb/pg_wchar.h" #include "miscadmin.h" @@ -27,14 +27,15 @@ common_utility_plugin *common_utility_plugin_ptr = NULL; -bool suppress_string_truncation_error = false; +bool suppress_string_truncation_error = false; -bool pltsql_suppress_string_truncation_error(void); +bool pltsql_suppress_string_truncation_error(void); -bool is_tsql_any_char_datatype(Oid oid); /* sys.char / sys.nchar / sys.varchar / sys.nvarchar */ -bool is_tsql_text_ntext_or_image_datatype(Oid oid); +bool is_tsql_any_char_datatype(Oid oid); /* sys.char / sys.nchar / + * sys.varchar / sys.nvarchar */ +bool is_tsql_text_ntext_or_image_datatype(Oid oid); -/* +/* * Following the rule for locktag fields of advisory locks: * field1: MyDatabaseId ... ensures locks are local to each database * field2: high-order half of an int8 key @@ -66,8 +67,8 @@ const uint64 PLTSQL_LOCKTAG_OFFSET = 0xABCDEF; * Also, length should be restricted to 8000 for sys.varchar and sys.char datatypes. * And length should be restricted to 4000 for sys.varchar and sys.char datatypes */ -void -pltsql_check_or_set_default_typmod(TypeName * typeName, int32 *typmod, bool is_cast) +void +pltsql_check_or_set_default_typmod(TypeName *typeName, int32 *typmod, bool is_cast) { Assert(sql_dialect == SQL_DIALECT_TSQL); @@ -79,9 +80,9 @@ pltsql_check_or_set_default_typmod(TypeName * typeName, int32 *typmod, bool is_c else { /* Normal reference to a type name */ - char *schemaname; - char *typname; - bool is_sys_schema = false; + char *schemaname; + char *typname; + bool is_sys_schema = false; /* deconstruct the name list */ DeconstructQualifiedName(typeName->names, &schemaname, &typname); @@ -89,8 +90,8 @@ pltsql_check_or_set_default_typmod(TypeName * typeName, int32 *typmod, bool is_c is_sys_schema = strcmp("sys", schemaname) == 0; else { - Oid schema_oid; - Oid sys_oid = InvalidOid; + Oid schema_oid; + Oid sys_oid = InvalidOid; /* Unqualified type name, search the search path */ schema_oid = typenameGetSchemaOID(typname, true); @@ -100,9 +101,13 @@ pltsql_check_or_set_default_typmod(TypeName * typeName, int32 *typmod, bool is_c } if (is_sys_schema) { - int max_allowed_varchar_length = 8000; - int max_allowed_nvarchar_length = 4000; - /* sys types/domains without typmod specification, set the default accordingly */ + int max_allowed_varchar_length = 8000; + int max_allowed_nvarchar_length = 4000; + + /* + * sys types/domains without typmod specification, set the default + * accordingly + */ if (*typmod == -1) { if (strcmp(typname, "varchar") == 0 || @@ -114,7 +119,11 @@ pltsql_check_or_set_default_typmod(TypeName * typeName, int32 *typmod, bool is_c { /* Default length is 30 in cast and convert statement */ if (is_cast) - /* atttypmod is the declared length of the type plus VARHDRSZ. */ + + /* + * atttypmod is the declared length of the type plus + * VARHDRSZ. + */ *typmod = 30 + VARHDRSZ; else /* Default length is 1 in the general case */ @@ -123,7 +132,7 @@ pltsql_check_or_set_default_typmod(TypeName * typeName, int32 *typmod, bool is_c else if (strcmp(typname, "smalldatetime") == 0) *typmod = 0; else if (strcmp(typname, "decimal") == 0) - *typmod = 1179652; /* decimal(18,0) */ + *typmod = 1179652; /* decimal(18,0) */ } /* for sys.varchar/nvarchar/varbinary(MAX), set typmod back to -1 */ else if (*typmod == TSQLMaxTypmod) @@ -135,25 +144,26 @@ pltsql_check_or_set_default_typmod(TypeName * typeName, int32 *typmod, bool is_c else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("Incorrect syntax near the keyword '%s'.", typname))); + errmsg("Incorrect syntax near the keyword '%s'.", typname))); } else if (*typmod > (max_allowed_varchar_length + VARHDRSZ) && (strcmp(typname, "varchar") == 0 || strcmp(typname, "bpchar") == 0)) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("The size '%d' exceeds the maximum allowed (%d) for '%s' datatype.", - *typmod - VARHDRSZ, max_allowed_varchar_length, typname))); + errmsg("The size '%d' exceeds the maximum allowed (%d) for '%s' datatype.", + *typmod - VARHDRSZ, max_allowed_varchar_length, typname))); } else if (*typmod > (max_allowed_nvarchar_length + VARHDRSZ) && (strcmp(typname, "nvarchar") == 0 || strcmp(typname, "nchar") == 0)) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("The size '%d' exceeds the maximum allowed (%d) for '%s' datatype.", - *typmod - VARHDRSZ, max_allowed_nvarchar_length, typname))); + errmsg("The size '%d' exceeds the maximum allowed (%d) for '%s' datatype.", + *typmod - VARHDRSZ, max_allowed_nvarchar_length, typname))); } } } } + /* * Declare variable API * @@ -163,7 +173,7 @@ pltsql_check_or_set_default_typmod(TypeName * typeName, int32 *typmod, bool is_c * InlineCodeBlockAgs built here. * * Sample code for calling this function: - * + * * InlineCodeBlock *codeblock = ...; * InlineCodeBlockArgs *args = ...; * LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS); @@ -181,15 +191,16 @@ pltsql_check_or_set_default_typmod(TypeName * typeName, int32 *typmod, bool is_c * fcinfo->args[1].isnull = false; * fcinfo->nargs++; */ -void pltsql_declare_variable(Oid type, int32 typmod, char *name, char mode, Datum value, - bool isnull, int index, InlineCodeBlockArgs **args, - FunctionCallInfo *fcinfo) +void +pltsql_declare_variable(Oid type, int32 typmod, char *name, char mode, Datum value, + bool isnull, int index, InlineCodeBlockArgs **args, + FunctionCallInfo *fcinfo) { /* * In case of sp_execute, we don't need the following info. Hence, skip * filling InlineCodeBlockArgs if it's not provided. */ - if(args) + if (args) { (*args)->argtypes[index] = type; (*args)->argtypmods[index] = typmod; @@ -204,12 +215,12 @@ void pltsql_declare_variable(Oid type, int32 typmod, char *name, char mode, Datu (*fcinfo)->args[index + 2].isnull = isnull; (*fcinfo)->nargs++; - + /* Safety check */ if ((*fcinfo)->nargs - 2 > PREPARE_STMT_MAX_ARGS) ereport(ERROR, (errcode(ERRCODE_TOO_MANY_ARGUMENTS), - errmsg("cannot pass more than %d arguments to a procedure", - PREPARE_STMT_MAX_ARGS))); + errmsg("cannot pass more than %d arguments to a procedure", + PREPARE_STMT_MAX_ARGS))); } /* @@ -218,12 +229,13 @@ void pltsql_declare_variable(Oid type, int32 typmod, char *name, char mode, Datu * This function deconstruct the input composite Datum comp_value, and store the * info in values and nulls. */ -void pltsql_read_composite_out_param(Datum comp_value, Datum **values, bool **nulls) +void +pltsql_read_composite_out_param(Datum comp_value, Datum **values, bool **nulls) { - HeapTupleData tmptup; + HeapTupleData tmptup; TupleDesc tupdesc; HeapTupleHeader td; - Oid tupType; + Oid tupType; int32 tupTypmod; /* Get tuple body (note this could involve detoasting) */ @@ -243,7 +255,7 @@ void pltsql_read_composite_out_param(Datum comp_value, Datum **values, bool **nu if (tupdesc && HeapTupleIsValid(&tmptup)) { - int td_natts = tupdesc->natts; + int td_natts = tupdesc->natts; *values = (Datum *) palloc(sizeof(Datum) * td_natts); *nulls = (bool *) palloc(sizeof(bool) * td_natts); @@ -258,30 +270,32 @@ void pltsql_read_composite_out_param(Datum comp_value, Datum **values, bool **nu ReleaseTupleDesc(tupdesc); } -bool pltsql_suppress_string_truncation_error() +bool +pltsql_suppress_string_truncation_error() { return suppress_string_truncation_error; } -void pltsql_read_procedure_info(StringInfo inout_str, - bool *is_proc, - Oid *typid, - Oid *typmod, - int *collation) +void +pltsql_read_procedure_info(StringInfo inout_str, + bool *is_proc, + Oid *typid, + Oid *typmod, + int *collation) { - Oid func_oid = InvalidOid; - Oid atttypid; - Oid atttypmod; - int attcollation; - bool isStoredProcedure = true; - HeapTuple proctup = NULL; - Form_pg_proc proc = NULL; - List *parsetree; - CallStmt *cstmt; - FuncCall *funccall; + Oid func_oid = InvalidOid; + Oid atttypid; + Oid atttypmod; + int attcollation; + bool isStoredProcedure = true; + HeapTuple proctup = NULL; + Form_pg_proc proc = NULL; + List *parsetree; + CallStmt *cstmt; + FuncCall *funccall; FuncCandidateList clist; - const char *str1 = "EXECUTE "; - StringInfoData proc_stmt; + const char *str1 = "EXECUTE "; + StringInfoData proc_stmt; /* * Create a fake EXECUTE statement to get the function name @@ -290,7 +304,7 @@ void pltsql_read_procedure_info(StringInfo inout_str, appendStringInfoString(&proc_stmt, str1); appendStringInfoString(&proc_stmt, inout_str->data); parsetree = raw_parser(proc_stmt.data, RAW_PARSE_DEFAULT); - cstmt = (CallStmt *) ((RawStmt *) linitial(parsetree))->stmt; + cstmt = (CallStmt *) ((RawStmt *) linitial(parsetree))->stmt; Assert(cstmt); if (enable_schema_mapping()) @@ -299,29 +313,29 @@ void pltsql_read_procedure_info(StringInfo inout_str, funccall = cstmt->funccall; /* - * Parse the name into components and see if it matches any - * pg_proc entries in the current search path. + * Parse the name into components and see if it matches any pg_proc + * entries in the current search path. */ clist = FuncnameGetCandidates(funccall->funcname, -1, NIL, false, false, false, false); if (clist == NULL) { /* - * We don't store some system procedures in the catalog, ex: sp_executesql, - * sp_prepare etc. We can add a check for them here. But, let's skip - * the check from here because when we're going to execute the procedure, - * if it doesn't exist or it's not a system procedure, then anywaay - * we're going to throw an error. + * We don't store some system procedures in the catalog, ex: + * sp_executesql, sp_prepare etc. We can add a check for them here. + * But, let's skip the check from here because when we're going to + * execute the procedure, if it doesn't exist or it's not a system + * procedure, then anywaay we're going to throw an error. */ isStoredProcedure = true; } else { if (clist->next != NULL) - ereport(ERROR, - (errcode(ERRCODE_AMBIGUOUS_FUNCTION), - errmsg("more than one function named \"%s\"", - NameListToString(funccall->funcname)))); + ereport(ERROR, + (errcode(ERRCODE_AMBIGUOUS_FUNCTION), + errmsg("more than one function named \"%s\"", + NameListToString(funccall->funcname)))); func_oid = clist->oid; Assert(func_oid != InvalidOid); @@ -347,22 +361,22 @@ void pltsql_read_procedure_info(StringInfo inout_str, } else { - Type retType; + Type retType; Form_pg_type typtup; if (proc->proretset) ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("The request for procedure \"%s\" failed because \"%s\" is" - "a SET-returning function", NameStr(proc->proname), - NameStr(proc->proname)))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("The request for procedure \"%s\" failed because \"%s\" is" + "a SET-returning function", NameStr(proc->proname), + NameStr(proc->proname)))); if (proc->prorettype == RECORDOID || proc->prorettype == VOIDOID) ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("The request for procedure \"%s\" failed because \"%s\" is" - "not a scalar-valued function", NameStr(proc->proname), - NameStr(proc->proname)))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("The request for procedure \"%s\" failed because \"%s\" is" + "not a scalar-valued function", NameStr(proc->proname), + NameStr(proc->proname)))); retType = typeidType(proc->prorettype); typtup = (Form_pg_type) GETSTRUCT(retType); @@ -403,10 +417,10 @@ PLTsqlStartTransaction(char *txnName) { Assert(NestedTranCount == 0); BeginTransactionBlock(); + /* - * set transaction name in savepoint field. - * It is needed to distinguish rollback vs - * rollback to savepoint requests. + * set transaction name in savepoint field. It is needed to + * distinguish rollback vs rollback to savepoint requests. */ if (txnName != NULL) SetTopTransactionName(txnName); @@ -414,7 +428,7 @@ PLTsqlStartTransaction(char *txnName) ++NestedTranCount; if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->set_at_at_stat_var) - (*pltsql_protocol_plugin_ptr)->set_at_at_stat_var("trancount", NestedTranCount, 0); + (*pltsql_protocol_plugin_ptr)->set_at_at_stat_var("trancount", NestedTranCount, 0); } void @@ -438,7 +452,7 @@ PLTsqlCommitTransaction(QueryCompletion *qc, bool chain) } if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->set_at_at_stat_var) - (*pltsql_protocol_plugin_ptr)->set_at_at_stat_var("trancount", NestedTranCount, 0); + (*pltsql_protocol_plugin_ptr)->set_at_at_stat_var("trancount", NestedTranCount, 0); } void @@ -462,7 +476,7 @@ PLTsqlRollbackTransaction(char *txnName, QueryCompletion *qc, bool chain) RollbackToSavepoint(txnName); RollbackAndReleaseSavepoint(txnName); if (qc) - // strncpy(completionTag, "ROLLBACK TO SAVEPOINT"); + /* strncpy(completionTag, "ROLLBACK TO SAVEPOINT"); */ /* PG 13 merge: double check this line */ qc->commandTag = CMDTAG_SAVEPOINT; } @@ -516,12 +530,13 @@ is_sysname_column(ColumnDef *coldef) bool have_null_constr(List *constr_list) { - ListCell *lc; - bool isnull = false; + ListCell *lc; + bool isnull = false; foreach(lc, constr_list) { Constraint *c = lfirst_node(Constraint, lc); + if (c->contype == CONSTR_NULL) { isnull = true; @@ -537,14 +552,15 @@ parsetree_nth_stmt(List *parsetree, int n) return ((RawStmt *) list_nth(parsetree, n))->stmt; } -/* - * Functions to update parsed dummy statements with real values +/* + * Functions to update parsed dummy statements with real values */ void update_AlterTableStmt(Node *n, const char *tbl_schema, const char *newowner) { AlterTableStmt *stmt = (AlterTableStmt *) n; - ListCell *lc; + ListCell *lc; + if (!IsA(stmt, AlterTableStmt)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("query is not a AlterTableStmt"))); @@ -557,13 +573,14 @@ update_AlterTableStmt(Node *n, const char *tbl_schema, const char *newowner) foreach(lc, stmt->cmds) { AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lc); + switch (cmd->subtype) { case AT_ChangeOwner: - { - cmd->newowner->rolename = pstrdup(newowner); - break; - } + { + cmd->newowner->rolename = pstrdup(newowner); + break; + } default: break; } @@ -574,7 +591,8 @@ void update_CreateRoleStmt(Node *n, const char *role, const char *member, const char *addto) { CreateRoleStmt *stmt = (CreateRoleStmt *) n; - ListCell *option; + ListCell *option; + if (!IsA(stmt, CreateRoleStmt)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("query is not a CreateRoleStmt"))); @@ -586,16 +604,18 @@ update_CreateRoleStmt(Node *n, const char *role, const char *member, const char foreach(option, stmt->options) { - DefElem *defel = (DefElem *) lfirst(option); + DefElem *defel = (DefElem *) lfirst(option); if (member && defel->arg && strcmp(defel->defname, "rolemembers") == 0) { - RoleSpec *tmp = (RoleSpec *) llast((List *) defel->arg); + RoleSpec *tmp = (RoleSpec *) llast((List *) defel->arg); + tmp->rolename = pstrdup(member); } else if (addto && defel->arg && strcmp(defel->defname, "addroleto") == 0) { - RoleSpec *tmp = (RoleSpec *) llast((List *) defel->arg); + RoleSpec *tmp = (RoleSpec *) llast((List *) defel->arg); + tmp->rolename = pstrdup(addto); } } @@ -605,6 +625,7 @@ void update_AlterRoleStmt(Node *n, RoleSpec *role) { AlterRoleStmt *stmt = (AlterRoleStmt *) n; + if (!IsA(stmt, AlterRoleStmt)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), @@ -617,6 +638,7 @@ void update_CreateSchemaStmt(Node *n, const char *schemaname, const char *authrole) { CreateSchemaStmt *stmt = (CreateSchemaStmt *) n; + if (!IsA(stmt, CreateSchemaStmt)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("query is not a CreateSchemaStmt"))); @@ -630,19 +652,19 @@ update_CreateSchemaStmt(Node *n, const char *schemaname, const char *authrole) void update_DropOwnedStmt(Node *n, List *role_list) { - DropOwnedStmt *stmt = (DropOwnedStmt *) n; - List *rolespec_list = NIL; - ListCell *elem; + DropOwnedStmt *stmt = (DropOwnedStmt *) n; + List *rolespec_list = NIL; + ListCell *elem; if (!IsA(stmt, DropOwnedStmt)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("query is not a DropOwnedStmt"))); - foreach (elem, role_list) + foreach(elem, role_list) { - char *name = (char *) lfirst(elem); - RoleSpec *tmp = makeNode(RoleSpec); + char *name = (char *) lfirst(elem); + RoleSpec *tmp = makeNode(RoleSpec); tmp->roletype = ROLESPEC_CSTRING; tmp->location = -1; @@ -656,16 +678,17 @@ void update_DropRoleStmt(Node *n, const char *role) { DropRoleStmt *stmt = (DropRoleStmt *) n; + if (!IsA(stmt, DropRoleStmt)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("query is not a DropRoleStmt"))); if (role && stmt->roles) { - /* + /* * Delete the first element if it's is_role flag, in this way we won't * need to rewrite the role names during internal call. */ - RoleSpec *tmp = (RoleSpec *) linitial(stmt->roles); + RoleSpec *tmp = (RoleSpec *) linitial(stmt->roles); if (strcmp(tmp->rolename, "is_role") == 0) stmt->roles = list_delete_cell(stmt->roles, list_head(stmt->roles)); @@ -684,7 +707,8 @@ update_DropRoleStmt(Node *n, const char *role) void update_DropStmt(Node *n, const char *object) { - DropStmt *stmt = (DropStmt *) n; + DropStmt *stmt = (DropStmt *) n; + if (!IsA(stmt, DropStmt)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("query is not a DropStmt"))); @@ -696,6 +720,7 @@ void update_GrantRoleStmt(Node *n, List *privs, List *roles) { GrantRoleStmt *stmt = (GrantRoleStmt *) n; + if (!IsA(stmt, GrantRoleStmt)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("query is not a GrantRoleStmt"))); @@ -706,7 +731,8 @@ update_GrantRoleStmt(Node *n, List *privs, List *roles) void update_GrantStmt(Node *n, const char *object, const char *obj_schema, const char *grantee) { - GrantStmt *stmt = (GrantStmt *) n; + GrantStmt *stmt = (GrantStmt *) n; + if (!IsA(stmt, GrantStmt)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("query is not a GrantStmt"))); @@ -714,13 +740,15 @@ update_GrantStmt(Node *n, const char *object, const char *obj_schema, const char llast(stmt->objects) = makeString(pstrdup(object)); else if (obj_schema && stmt->objects) { - RangeVar *tmp = (RangeVar *) llast(stmt->objects); + RangeVar *tmp = (RangeVar *) llast(stmt->objects); + tmp->schemaname = pstrdup(obj_schema); } if (grantee && stmt->grantees) { - RoleSpec *tmp = (RoleSpec *) llast(stmt->grantees); + RoleSpec *tmp = (RoleSpec *) llast(stmt->grantees); + tmp->rolename = pstrdup(grantee); } } @@ -729,6 +757,7 @@ void update_RenameStmt(Node *n, const char *old_name, const char *new_name) { RenameStmt *stmt = (RenameStmt *) n; + if (!IsA(stmt, RenameStmt)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("query is not a RenameStmt"))); @@ -739,7 +768,8 @@ update_RenameStmt(Node *n, const char *old_name, const char *new_name) void update_ViewStmt(Node *n, const char *view_schema) { - ViewStmt *stmt = (ViewStmt *) n; + ViewStmt *stmt = (ViewStmt *) n; + if (!IsA(stmt, ViewStmt)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("query is not a ViewStmt"))); @@ -747,19 +777,21 @@ update_ViewStmt(Node *n, const char *view_schema) stmt->view->schemaname = pstrdup(view_schema); } -bool is_tsql_any_char_datatype(Oid oid) +bool +is_tsql_any_char_datatype(Oid oid) { - return (*common_utility_plugin_ptr->is_tsql_bpchar_datatype)(oid) || - (*common_utility_plugin_ptr->is_tsql_nchar_datatype)(oid) || - (*common_utility_plugin_ptr->is_tsql_varchar_datatype)(oid) || - (*common_utility_plugin_ptr->is_tsql_nvarchar_datatype)(oid); + return (*common_utility_plugin_ptr->is_tsql_bpchar_datatype) (oid) || + (*common_utility_plugin_ptr->is_tsql_nchar_datatype) (oid) || + (*common_utility_plugin_ptr->is_tsql_varchar_datatype) (oid) || + (*common_utility_plugin_ptr->is_tsql_nvarchar_datatype) (oid); } -bool is_tsql_text_ntext_or_image_datatype(Oid oid) +bool +is_tsql_text_ntext_or_image_datatype(Oid oid) { - return (*common_utility_plugin_ptr->is_tsql_text_datatype)(oid) || - (*common_utility_plugin_ptr->is_tsql_ntext_datatype)(oid) || - (*common_utility_plugin_ptr->is_tsql_image_datatype)(oid); + return (*common_utility_plugin_ptr->is_tsql_text_datatype) (oid) || + (*common_utility_plugin_ptr->is_tsql_ntext_datatype) (oid) || + (*common_utility_plugin_ptr->is_tsql_image_datatype) (oid); } /* @@ -768,9 +800,9 @@ bool is_tsql_text_ntext_or_image_datatype(Oid oid) bool TryLockLogicalDatabaseForSession(int16 dbid, LOCKMODE lockmode) { - LOCKTAG tag; + LOCKTAG tag; - SET_LOCKTAG_INT16(tag, dbid); + SET_LOCKTAG_INT16(tag, dbid); return LockAcquire(&tag, lockmode, true, true) != LOCKACQUIRE_NOT_AVAIL; } @@ -781,7 +813,7 @@ TryLockLogicalDatabaseForSession(int16 dbid, LOCKMODE lockmode) void UnlockLogicalDatabaseForSession(int16 dbid, LOCKMODE lockmode, bool force) { - LOCKTAG tag; + LOCKTAG tag; SET_LOCKTAG_INT16(tag, dbid); @@ -798,11 +830,12 @@ char * bpchar_to_cstring(const BpChar *bpchar) { const char *bp_data = VARDATA_ANY(bpchar); - int len = VARSIZE_ANY_EXHDR(bpchar); + int len = VARSIZE_ANY_EXHDR(bpchar); + + char *result = (char *) palloc(len + 1); - char *result = (char *) palloc(len + 1); memcpy(result, bp_data, len); - result[len] = '\0'; + result[ len] = '\0'; return result; } @@ -814,11 +847,12 @@ char * varchar_to_cstring(const VarChar *varchar) { const char *vc_data = VARDATA_ANY(varchar); - int len = VARSIZE_ANY_EXHDR(varchar); + int len = VARSIZE_ANY_EXHDR(varchar); + + char *result = (char *) palloc(len + 1); - char *result = (char *) palloc(len + 1); memcpy(result, vc_data, len); - result[len] = '\0'; + result[ len] = '\0'; return result; } @@ -839,6 +873,7 @@ flatten_search_path(List *oid_list) { Oid schema_oid = lfirst_oid(lc); char *schema_name = get_namespace_name(schema_oid); + appendStringInfo(&pathbuf, " %s,", quote_identifier(schema_name)); } pathbuf.data[strlen(pathbuf.data) - 1] = '\0'; @@ -847,7 +882,7 @@ flatten_search_path(List *oid_list) const char * get_pltsql_function_signature_internal(const char *funcname, - int nargs, const Oid *argtypes) + int nargs, const Oid *argtypes) { StringInfoData argbuf; int i; @@ -857,10 +892,13 @@ get_pltsql_function_signature_internal(const char *funcname, PG_TRY(); { - /* Temporarily set quote_all_identifiers to TRUE to generate quoted string */ + /* + * Temporarily set quote_all_identifiers to TRUE to generate quoted + * string + */ set_config_option("quote_all_identifiers", "true", - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); appendStringInfo(&argbuf, "%s(", funcname); for (i = 0; i < nargs; i++) @@ -874,8 +912,8 @@ get_pltsql_function_signature_internal(const char *funcname, PG_FINALLY(); { set_config_option("quote_all_identifiers", prev_quote_ident, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); } PG_END_TRY(); @@ -890,14 +928,15 @@ get_pltsql_function_signature(PG_FUNCTION_ARGS) Oid funcoid = PG_GETARG_OID(0); HeapTuple proctup; Form_pg_proc form_proctup; - const char *func_signature; + const char *func_signature; proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid)); - if (HeapTupleIsValid(proctup)){ + if (HeapTupleIsValid(proctup)) + { form_proctup = (Form_pg_proc) GETSTRUCT(proctup); func_signature = (char *) get_pltsql_function_signature_internal(NameStr(form_proctup->proname), - form_proctup->pronargs, - form_proctup->proargtypes.values); + form_proctup->pronargs, + form_proctup->proargtypes.values); ReleaseSysCache(proctup); PG_RETURN_TEXT_P(cstring_to_text(func_signature)); @@ -906,7 +945,7 @@ get_pltsql_function_signature(PG_FUNCTION_ARGS) } void -report_info_or_warning(int elevel, char* message) +report_info_or_warning(int elevel, char *message) { ereport(elevel, errmsg("%s", message)); @@ -914,19 +953,21 @@ report_info_or_warning(int elevel, char* message) ((*pltsql_protocol_plugin_ptr)->send_info) (0, 1, 0, message, 0); } -void init_and_check_common_utility(void) +void +init_and_check_common_utility(void) { if (!common_utility_plugin_ptr) { common_utility_plugin **utility_plugin; - utility_plugin = (common_utility_plugin **) find_rendezvous_variable("common_utility_plugin"); + + utility_plugin = (common_utility_plugin **) find_rendezvous_variable("common_utility_plugin"); common_utility_plugin_ptr = *utility_plugin; /* common_utility_plugin_ptr is still not initialised */ if (!common_utility_plugin_ptr) ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("Failed to find common utility plugin."))); + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("Failed to find common utility plugin."))); } } @@ -940,36 +981,37 @@ void init_and_check_common_utility(void) Oid tsql_get_constraint_oid(char *conname, Oid connamespace, Oid user_id) { - Relation tgrel; - ScanKeyData skey[2]; - SysScanDesc tgscan; - HeapTuple tuple; - Oid result = InvalidOid; + Relation tgrel; + ScanKeyData skey[2]; + SysScanDesc tgscan; + HeapTuple tuple; + Oid result = InvalidOid; /* search in pg_constraint by name and namespace */ tgrel = table_open(ConstraintRelationId, AccessShareLock); ScanKeyInit(&skey[0], - Anum_pg_constraint_conname, - BTEqualStrategyNumber, F_NAMEEQ, - CStringGetDatum(conname)); + Anum_pg_constraint_conname, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(conname)); ScanKeyInit(&skey[1], - Anum_pg_constraint_connamespace, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(connamespace)); + Anum_pg_constraint_connamespace, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(connamespace)); tgscan = systable_beginscan(tgrel, ConstraintNameNspIndexId, - true, NULL, 2, skey); + true, NULL, 2, skey); /* we are interested in the first row only */ if (HeapTupleIsValid(tuple = systable_getnext(tgscan))) { Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple); + if (OidIsValid(con->oid)) { if (OidIsValid(con->conrelid)) { - if(pg_class_aclcheck(con->conrelid, user_id, ACL_SELECT) == ACLCHECK_OK) + if (pg_class_aclcheck(con->conrelid, user_id, ACL_SELECT) == ACLCHECK_OK) result = con->oid; } else @@ -990,34 +1032,36 @@ tsql_get_constraint_oid(char *conname, Oid connamespace, Oid user_id) Oid tsql_get_trigger_oid(char *tgname, Oid tgnamespace, Oid user_id) { - Relation tgrel; - ScanKeyData key; - SysScanDesc tgscan; - HeapTuple tuple; - Oid result = InvalidOid; + Relation tgrel; + ScanKeyData key; + SysScanDesc tgscan; + HeapTuple tuple; + Oid result = InvalidOid; /* first search in pg_trigger by name */ tgrel = table_open(TriggerRelationId, AccessShareLock); ScanKeyInit(&key, - Anum_pg_trigger_tgname, - BTEqualStrategyNumber, F_NAMEEQ, - CStringGetDatum(tgname)); + Anum_pg_trigger_tgname, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(tgname)); tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, - true, NULL, 1, &key); - + true, NULL, 1, &key); + while (HeapTupleIsValid(tuple = systable_getnext(tgscan))) { Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple); - if(!OidIsValid(pg_trigger->tgrelid)) + + if (!OidIsValid(pg_trigger->tgrelid)) { break; } /* then consider only trigger in specified namespace */ - if (get_rel_namespace(pg_trigger->tgrelid) == tgnamespace && + if (get_rel_namespace(pg_trigger->tgrelid) == tgnamespace && pg_class_aclcheck(pg_trigger->tgrelid, user_id, ACL_SELECT) == ACLCHECK_OK) { result = pg_trigger->oid; + break; } } @@ -1035,15 +1079,16 @@ tsql_get_trigger_oid(char *tgname, Oid tgnamespace, Oid user_id) Oid tsql_get_proc_oid(char *proname, Oid pronamespace, Oid user_id) { - HeapTuple tuple; - CatCList *catlist; - Oid result = InvalidOid; + HeapTuple tuple; + CatCList *catlist; + Oid result = InvalidOid; /* first search in pg_proc by name */ catlist = SearchSysCacheList1(PROCNAMEARGSNSP, CStringGetDatum(proname)); for (int i = 0; i < catlist->n_members; i++) { Form_pg_proc procform; + tuple = &catlist->members[i]->tuple; procform = (Form_pg_proc) GETSTRUCT(tuple); /* then consider only procs in specified namespace */ @@ -1051,6 +1096,7 @@ tsql_get_proc_oid(char *proname, Oid pronamespace, Oid user_id) pg_proc_aclcheck(procform->oid, user_id, ACL_EXECUTE) == ACLCHECK_OK) { result = procform->oid; + break; } } @@ -1060,8 +1106,9 @@ tsql_get_proc_oid(char *proname, Oid pronamespace, Oid user_id) static int babelfish_get_delimiter_pos(char *str) -{ - char *ptr; +{ + char *ptr; + if (strlen(str) <= 2 && (strchr(str, '"') || strchr(str, '[') || strchr(str, ']'))) return -1; else if (str[0] == '[') @@ -1081,26 +1128,26 @@ babelfish_get_delimiter_pos(char *str) return (int) (ptr - str) + 1; } else - { + { ptr = strstr(str, "."); if (ptr == NULL) return -1; else return (int) (ptr - str); } - + return -1; } -/* +/* * Extract string from input of given length and remove delimited identifiers. */ -static char* +static char * remove_delimited_identifiers(char *str, int len) -{ - +{ + if (len >= 2 && ((str[0] == '[' && str[len - 1] == ']') || (str[0] == '"' && str[len - 1] == '"'))) - { + { if (len > 2) return pnstrdup(&str[1], len - 2); else @@ -1111,16 +1158,17 @@ remove_delimited_identifiers(char *str, int len) } /* - * Split multiple-part object-name into array of pointers, it also remove the delimited identifiers. + * Split multiple-part object-name into array of pointers, it also remove the delimited identifiers. */ -char** +char ** split_object_name(char *name) -{ - char **res = palloc(4 * sizeof(char *)); - char *temp[4]; - char *str; - int cur_pos, next_pos; - int count = 0; +{ + char **res = palloc(4 * sizeof(char *)); + char *temp[4]; + char *str; + int cur_pos, + next_pos; + int count = 0; /* extract and remove the delimited identifiers from input into temp array */ cur_pos = 0; @@ -1136,7 +1184,7 @@ split_object_name(char *name) temp[count++] = str; /* fill unspecified parts with empty strings */ - for(int i = 0; i < 4; i++) + for (int i = 0; i < 4; i++) { if (i < 4 - count) res[i] = pstrdup(""); @@ -1152,11 +1200,13 @@ split_object_name(char *name) * is_schema_from_db * Given schema_oid and db_id, check if schema belongs to provided database id. */ -bool is_schema_from_db(Oid schema_oid, Oid db_id) +bool +is_schema_from_db(Oid schema_oid, Oid db_id) { - Oid db_id_from_schema; - char *schema_name = get_namespace_name(schema_oid); - if(!schema_name) + Oid db_id_from_schema; + char *schema_name = get_namespace_name(schema_oid); + + if (!schema_name) return false; db_id_from_schema = get_dbid_from_physical_schema_name(schema_name, true); @@ -1168,9 +1218,11 @@ bool is_schema_from_db(Oid schema_oid, Oid db_id) * remove_trailing_spaces * Remove trailing spaces from a string */ -void remove_trailing_spaces(char *name) +void +remove_trailing_spaces(char *name) { - int len = strlen(name); + int len = strlen(name); + while (len > 0 && isspace((unsigned char) name[len - 1])) name[--len] = '\0'; } @@ -1180,12 +1232,12 @@ void remove_trailing_spaces(char *name) * Given Oid of pg_proc entry return namespace_oid * Returns InvalidOid if Oid is not found */ -Oid +Oid tsql_get_proc_nsp_oid(Oid object_id) { - Oid namespace_oid = InvalidOid; - HeapTuple tuple; - bool isnull; + Oid namespace_oid = InvalidOid; + HeapTuple tuple; + bool isnull; /* retrieve pronamespace in pg_proc by oid */ tuple = SearchSysCache1(PROCOID, CStringGetDatum(object_id)); @@ -1193,11 +1245,12 @@ tsql_get_proc_nsp_oid(Oid object_id) if (HeapTupleIsValid(tuple)) { (void) SysCacheGetAttr(PROCOID, tuple, - Anum_pg_proc_pronamespace, - &isnull); - if(!isnull) + Anum_pg_proc_pronamespace, + &isnull); + if (!isnull) { Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(tuple); + namespace_oid = proc->pronamespace; } ReleaseSysCache(tuple); @@ -1210,12 +1263,13 @@ tsql_get_proc_nsp_oid(Oid object_id) * Given Oid of pg_constraint entry return namespace_oid * Returns InvalidOid if Oid is not found */ -Oid -tsql_get_constraint_nsp_oid(Oid object_id, Oid user_id){ +Oid +tsql_get_constraint_nsp_oid(Oid object_id, Oid user_id) +{ - Oid namespace_oid = InvalidOid; - HeapTuple tuple; - bool isnull; + Oid namespace_oid = InvalidOid; + HeapTuple tuple; + bool isnull; /* retrieve connamespace in pg_constraint by oid */ tuple = SearchSysCache1(CONSTROID, CStringGetDatum(object_id)); @@ -1223,17 +1277,21 @@ tsql_get_constraint_nsp_oid(Oid object_id, Oid user_id){ if (HeapTupleIsValid(tuple)) { (void) SysCacheGetAttr(CONSTROID, tuple, - Anum_pg_constraint_connamespace, - &isnull); - if(!isnull) + Anum_pg_constraint_connamespace, + &isnull); + if (!isnull) { Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple); + if (OidIsValid(con->oid)) { - /* user should have permission of table associated with constraint */ + /* + * user should have permission of table associated with + * constraint + */ if (OidIsValid(con->conrelid)) { - if(pg_class_aclcheck(con->conrelid, user_id, ACL_SELECT) == ACLCHECK_OK) + if (pg_class_aclcheck(con->conrelid, user_id, ACL_SELECT) == ACLCHECK_OK) namespace_oid = con->connamespace; } } @@ -1242,6 +1300,7 @@ tsql_get_constraint_nsp_oid(Oid object_id, Oid user_id){ } return namespace_oid; } + /* * tsql_get_trigger_rel_oid * Given Oid of pg_trigger entry return Oid of table @@ -1249,13 +1308,14 @@ tsql_get_constraint_nsp_oid(Oid object_id, Oid user_id){ * Returns InvalidOid if Oid is not found */ Oid -tsql_get_trigger_rel_oid(Oid object_id){ +tsql_get_trigger_rel_oid(Oid object_id) +{ - Relation tgrel; - ScanKeyData key[1]; - SysScanDesc tgscan; - HeapTuple tuple; - Oid tgrelid = InvalidOid; + Relation tgrel; + ScanKeyData key[1]; + SysScanDesc tgscan; + HeapTuple tuple; + Oid tgrelid = InvalidOid; /* retrieve tgrelid in pg_trigger by oid */ tgrel = table_open(TriggerRelationId, AccessShareLock); @@ -1270,6 +1330,7 @@ tsql_get_trigger_rel_oid(Oid object_id){ if (HeapTupleIsValid(tuple = systable_getnext(tgscan))) { Form_pg_trigger trig = (Form_pg_trigger) GETSTRUCT(tuple); + tgrelid = trig->tgrelid; } systable_endscan(tgscan); diff --git a/contrib/babelfishpg_tsql/src/prepare.c b/contrib/babelfishpg_tsql/src/prepare.c index b0146d0b41..30291aa8bc 100644 --- a/contrib/babelfishpg_tsql/src/prepare.c +++ b/contrib/babelfishpg_tsql/src/prepare.c @@ -14,35 +14,36 @@ #include "iterative_exec.h" #include "multidb.h" -SPIPlanPtr prepare_stmt_execsql(PLtsql_execstate *estate, PLtsql_function *func, - PLtsql_stmt_execsql *stmt, bool keepplan); -SPIPlanPtr prepare_stmt_exec(PLtsql_execstate *estate, PLtsql_function *func, - PLtsql_stmt_exec *stmt, bool keepplan); +SPIPlanPtr prepare_stmt_execsql(PLtsql_execstate *estate, PLtsql_function *func, + PLtsql_stmt_execsql *stmt, bool keepplan); +SPIPlanPtr prepare_stmt_exec(PLtsql_execstate *estate, PLtsql_function *func, + PLtsql_stmt_exec *stmt, bool keepplan); -void exec_prepare_plan(PLtsql_execstate *estate, PLtsql_expr *expr, int cursorOptions, bool keepplan); -void exec_save_simple_expr(PLtsql_expr *expr, CachedPlan *cplan); -SPIPlanPtr prepare_exec_codes(PLtsql_function *func, ExecCodes *exec_codes); -void cleanup_temporal_plan(ExecCodes *exec_codes); +void exec_prepare_plan(PLtsql_execstate *estate, PLtsql_expr *expr, int cursorOptions, bool keepplan); +void exec_save_simple_expr(PLtsql_expr *expr, CachedPlan *cplan); +SPIPlanPtr prepare_exec_codes(PLtsql_function *func, ExecCodes *exec_codes); +void cleanup_temporal_plan(ExecCodes *exec_codes); static void prepare_select_plan_for_scalar_func(PLtsql_execstate *estate, PLtsql_expr *expr, int first_arg_location, const char *new_params); static bool is_exec_stmt_on_scalar_func(const char *stmt, int *first_arg_location, const char **new_params); static char *rewrite_exec_scalar_func_params(const char *stmt, List *raw_parsetree_list, int first_arg_location); -static List* get_func_info_from_raw_parsetree(List *raw_parsetree_list, int* nargs, - bool* func_variadic, int* first_arg_location); +static List *get_func_info_from_raw_parsetree(List *raw_parsetree_list, int *nargs, + bool *func_variadic, int *first_arg_location); static void exec_simple_check_plan(PLtsql_execstate *estate, PLtsql_expr *expr); extern void pltsql_estate_setup(PLtsql_execstate *estate, PLtsql_function *func, - ReturnSetInfo *rsi, EState *simple_eval_estate); + ReturnSetInfo *rsi, EState *simple_eval_estate); extern void pltsql_destroy_econtext(PLtsql_execstate *estate); extern void exec_eval_cleanup(PLtsql_execstate *estate); extern void copy_pltsql_datums(PLtsql_execstate *estate, PLtsql_function *func); extern void pltsql_estate_cleanup(void); + /* * On the first call for this statement generate the plan, and detect * whether the statement is INSERT/UPDATE/DELETE */ -SPIPlanPtr +SPIPlanPtr prepare_stmt_execsql(PLtsql_execstate *estate, PLtsql_function *func, PLtsql_stmt_execsql *stmt, bool keepplan) { PLtsql_expr *expr = stmt->sqlstmt; @@ -54,6 +55,7 @@ prepare_stmt_execsql(PLtsql_execstate *estate, PLtsql_function *func, PLtsql_stm foreach(l, SPI_plan_get_plan_sources(expr->plan)) { CachedPlanSource *plansource = (CachedPlanSource *) lfirst(l); + if (IsA(plansource->raw_parse_tree->stmt, TransactionStmt)) { pltsql_eval_txn_data(estate, stmt, plansource); @@ -61,47 +63,47 @@ prepare_stmt_execsql(PLtsql_execstate *estate, PLtsql_function *func, PLtsql_stm } /* - * We could look at the raw_parse_tree, but it seems simpler to - * check the command tag. Note we should *not* look at the Query - * tree(s), since those are the result of rewriting and could have - * been transmogrified into something else entirely. + * We could look at the raw_parse_tree, but it seems simpler to check + * the command tag. Note we should *not* look at the Query tree(s), + * since those are the result of rewriting and could have been + * transmogrified into something else entirely. */ if (plansource->commandTag && (plansource->commandTag == CMDTAG_INSERT || plansource->commandTag == CMDTAG_UPDATE || plansource->commandTag == CMDTAG_DELETE)) { - ListCell *lc; - int n; - PLtsql_tbl *tbl; - const char *relname; + ListCell *lc; + int n; + PLtsql_tbl *tbl; + const char *relname; stmt->mod_stmt = true; /* Check if the statement's relation is a table variable */ - switch(nodeTag(plansource->raw_parse_tree->stmt)) + switch (nodeTag(plansource->raw_parse_tree->stmt)) { case T_InsertStmt: - relname = ((InsertStmt *)plansource->raw_parse_tree->stmt)->relation->relname; + relname = ((InsertStmt *) plansource->raw_parse_tree->stmt)->relation->relname; break; case T_UpdateStmt: - relname = ((UpdateStmt *)plansource->raw_parse_tree->stmt)->relation->relname; + relname = ((UpdateStmt *) plansource->raw_parse_tree->stmt)->relation->relname; break; case T_DeleteStmt: - relname = ((DeleteStmt *)plansource->raw_parse_tree->stmt)->relation->relname; + relname = ((DeleteStmt *) plansource->raw_parse_tree->stmt)->relation->relname; break; default: ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("unexpected parse node type: %d", - (int) nodeTag(plansource->raw_parse_tree->stmt)))); + (int) nodeTag(plansource->raw_parse_tree->stmt)))); break; } /* estate not set up, or not a table variable */ if (!estate || strncmp(relname, "@", 1) != 0) break; - foreach (lc, estate->func->table_varnos) + foreach(lc, estate->func->table_varnos) { n = lfirst_int(lc); if (estate->datums[n]->dtype != PLTSQL_DTYPE_TBL) @@ -122,17 +124,18 @@ prepare_stmt_execsql(PLtsql_execstate *estate, PLtsql_function *func, PLtsql_stm return expr->plan; } -SPIPlanPtr +SPIPlanPtr prepare_stmt_exec(PLtsql_execstate *estate, PLtsql_function *func, PLtsql_stmt_exec *stmt, bool keepplan) { - int first_arg_location; + int first_arg_location; const char *new_params = NULL; PLtsql_expr *expr = stmt->expr; - bool is_stmt_scalar_func; + bool is_stmt_scalar_func; /* Do the query in local context to free memory at earliest */ MemoryContext oldcontext = MemoryContextSwitchTo(estate->eval_econtext->ecxt_per_tuple_memory); + is_stmt_scalar_func = is_exec_stmt_on_scalar_func(expr->query, &first_arg_location, &new_params); MemoryContextSwitchTo(oldcontext); @@ -143,18 +146,18 @@ prepare_stmt_exec(PLtsql_execstate *estate, PLtsql_function *func, PLtsql_stmt_e else { /* - * Don't save the plan if not in atomic context. Otherwise, - * transaction ends would cause errors about plancache leaks. - * - * XXX This would be fixable with some plancache/resowner surgery - * elsewhere, but for now we'll just work around this here. - */ + * Don't save the plan if not in atomic context. Otherwise, + * transaction ends would cause errors about plancache leaks. + * + * XXX This would be fixable with some plancache/resowner surgery + * elsewhere, but for now we'll just work around this here. + */ exec_prepare_plan(estate, expr, 0, keepplan); } /* - * Force target to be recalculated whenever the plan changes, in - * case the procedure's argument list has changed. + * Force target to be recalculated whenever the plan changes, in case the + * procedure's argument list has changed. */ stmt->target = NULL; @@ -164,21 +167,24 @@ prepare_stmt_exec(PLtsql_execstate *estate, PLtsql_function *func, PLtsql_stmt_e static bool is_exec_stmt_on_scalar_func(const char *stmt, int *first_arg_location, const char **new_params) { - List *raw_parsetree_list; - List *funcname; - int nargs; - bool func_variadic; - Oid arg_types[FUNC_MAX_ARGS]; + List *raw_parsetree_list; + List *funcname; + int nargs; + bool func_variadic; + Oid arg_types[FUNC_MAX_ARGS]; FuncDetailCode fdresult; - Oid funcid; - Oid rettype; /* not used */ - bool retset; /* not used */ - int nvargs; /* not used */ - Oid vatype; /* not used */ - Oid *typeids; /* not used */ - int i; - - /* Stmt should be syntactically vaild since it was verified during compiliation */ + Oid funcid; + Oid rettype; /* not used */ + bool retset; /* not used */ + int nvargs; /* not used */ + Oid vatype; /* not used */ + Oid *typeids; /* not used */ + int i; + + /* + * Stmt should be syntactically vaild since it was verified during + * compiliation + */ raw_parsetree_list = raw_parser(stmt, RAW_PARSE_DEFAULT); funcname = get_func_info_from_raw_parsetree(raw_parsetree_list, &nargs, &func_variadic, first_arg_location); @@ -188,9 +194,9 @@ is_exec_stmt_on_scalar_func(const char *stmt, int *first_arg_location, const cha /* safety check */ if (nargs > FUNC_MAX_ARGS) ereport(ERROR, (errcode(ERRCODE_TOO_MANY_ARGUMENTS), - errmsg("cannot pass more than %d arguments to a procedure", - FUNC_MAX_ARGS))); - + errmsg("cannot pass more than %d arguments to a procedure", + FUNC_MAX_ARGS))); + for (i = 0; i < nargs; ++i) { /* We really don't care of the exact argument datatypes */ @@ -198,12 +204,12 @@ is_exec_stmt_on_scalar_func(const char *stmt, int *first_arg_location, const cha } fdresult = func_get_detail(funcname, - NIL, NIL, - nargs, arg_types, - func_variadic, true, false, - &funcid, &rettype, &retset, - &nvargs, &vatype, - &typeids, NULL); + NIL, NIL, + nargs, arg_types, + func_variadic, true, false, + &funcid, &rettype, &retset, + &nvargs, &vatype, + &typeids, NULL); if (fdresult != FUNCDETAIL_NORMAL) return false; @@ -217,12 +223,12 @@ is_exec_stmt_on_scalar_func(const char *stmt, int *first_arg_location, const cha return true; } -static List* -get_func_info_from_raw_parsetree(List *raw_parsetree_list, int* nargs, bool* func_variadic, int* first_arg_location) +static List * +get_func_info_from_raw_parsetree(List *raw_parsetree_list, int *nargs, bool *func_variadic, int *first_arg_location) { - RawStmt *rstmt; - CallStmt *cstmt; - FuncCall *funccall; + RawStmt *rstmt; + CallStmt *cstmt; + FuncCall *funccall; if (!raw_parsetree_list) return NIL; @@ -274,12 +280,12 @@ get_func_info_from_raw_parsetree(List *raw_parsetree_list, int* nargs, bool* fun static char * rewrite_exec_scalar_func_params(const char *stmt, List *raw_parsetree_list, int first_arg_location) { - ListCell *lc; - RawStmt *rstmt; - CallStmt *cstmt; - FuncCall *funccall; - StringInfoData dest; - int prev = first_arg_location; + ListCell *lc; + RawStmt *rstmt; + CallStmt *cstmt; + FuncCall *funccall; + StringInfoData dest; + int prev = first_arg_location; if (first_arg_location == -1) return NULL; @@ -298,23 +304,23 @@ rewrite_exec_scalar_func_params(const char *stmt, List *raw_parsetree_list, int initStringInfo(&dest); funccall = cstmt->funccall; - foreach (lc, funccall->args) + foreach(lc, funccall->args) { - Node *expr = lfirst(lc); - switch(nodeTag(expr)) + Node *expr = lfirst(lc); + + switch (nodeTag(expr)) { case T_NamedArgExpr: { /* - * For NamedArgExpr we want to rewrite it from - * " = " - * to - * " => " + * For NamedArgExpr we want to rewrite it from " = + * " to " => " */ const NamedArgExpr *na = (const NamedArgExpr *) expr; + /* - * Append the part of stmt appearing before the NamedArgExpr - * that we haven't inserted already. + * Append the part of stmt appearing before the + * NamedArgExpr that we haven't inserted already. */ appendBinaryStringInfo(&dest, &(stmt[prev]), na->location - prev); @@ -338,7 +344,7 @@ static void prepare_select_plan_for_scalar_func(PLtsql_execstate *estate, PLtsql_expr *expr, int first_arg_location, const char *new_params) { StringInfoData new_query; - char *saved_expr_query; + char *saved_expr_query; const char *start_command = "EXEC"; /* expr->query should start with EXEC */ @@ -354,7 +360,10 @@ prepare_select_plan_for_scalar_func(PLtsql_execstate *estate, PLtsql_expr *expr, else appendStringInfo(&new_query, "SELECT %s ()", expr->query + strlen(start_command)); - /* Now we got SELECT statement. Replace query string temporarily and prepare a SELECT plan */ + /* + * Now we got SELECT statement. Replace query string temporarily and + * prepare a SELECT plan + */ saved_expr_query = expr->query; expr->query = new_query.data; @@ -365,6 +374,7 @@ prepare_select_plan_for_scalar_func(PLtsql_execstate *estate, PLtsql_expr *expr, pfree(new_query.data); } + /* ---------- * Generate a prepared plan * ---------- @@ -397,7 +407,11 @@ exec_prepare_plan(PLtsql_execstate *estate, expr->plan = plan; /* Check to see if it's a simple expression */ - /* Skip simple expression checking when estate is not available during SP_PREPARE call */ + + /* + * Skip simple expression checking when estate is not available during + * SP_PREPARE call + */ exec_simple_check_plan(estate, expr); /* @@ -564,8 +578,8 @@ exec_save_simple_expr(PLtsql_expr *expr, CachedPlan *cplan) if (IsA(tle_expr, Const)) break; /* Otherwise, it had better be a Param or an outer Var */ - Assert(IsA(tle_expr, Param) ||(IsA(tle_expr, Var) && - ((Var *) tle_expr)->varno == OUTER_VAR)); + Assert(IsA(tle_expr, Param) || (IsA(tle_expr, Var) && + ((Var *) tle_expr)->varno == OUTER_VAR)); /* Descend to the child node */ plan = plan->lefttree; } @@ -586,16 +600,17 @@ exec_save_simple_expr(PLtsql_expr *expr, CachedPlan *cplan) /* Also stash away the expression result type */ expr->expr_simple_type = exprType((Node *) tle_expr); expr->expr_simple_typmod = exprTypmod((Node *) tle_expr); - /* We also want to remember if it is immutable or not */ - expr->expr_simple_mutable = contain_mutable_functions((Node *) tle_expr); + /* We also want to remember if it is immutable or not */ + expr->expr_simple_mutable = contain_mutable_functions((Node *) tle_expr); } -SPIPlanPtr prepare_exec_codes(PLtsql_function *func, ExecCodes *exec_codes) +SPIPlanPtr +prepare_exec_codes(PLtsql_function *func, ExecCodes *exec_codes) { PLtsql_stmt *stmt; PLtsql_execstate estate; - SPIPlanPtr plan = NULL; - + SPIPlanPtr plan = NULL; + if (vec_size(exec_codes->codes) != 3) return false; @@ -611,84 +626,88 @@ SPIPlanPtr prepare_exec_codes(PLtsql_function *func, ExecCodes *exec_codes) /* stmt 1 */ stmt = *(PLtsql_stmt **) vec_at(exec_codes->codes, 0); - switch(stmt->cmd_type) + switch (stmt->cmd_type) { case PLTSQL_STMT_EXECSQL: - { - pltsql_estate_setup(&estate, func, NULL, NULL); - copy_pltsql_datums(&estate, func); - PG_TRY(); - { - plan = prepare_stmt_execsql(&estate, func, (PLtsql_stmt_execsql *) stmt, true); - /* Clean up any leftover temporary memory */ - pltsql_destroy_econtext(&estate); - exec_eval_cleanup(&estate); - } - PG_CATCH(); { + pltsql_estate_setup(&estate, func, NULL, NULL); + copy_pltsql_datums(&estate, func); + PG_TRY(); + { + plan = prepare_stmt_execsql(&estate, func, (PLtsql_stmt_execsql *) stmt, true); + /* Clean up any leftover temporary memory */ + pltsql_destroy_econtext(&estate); + exec_eval_cleanup(&estate); + } + PG_CATCH(); + { + pltsql_estate_cleanup(); + PG_RE_THROW(); + } + PG_END_TRY(); pltsql_estate_cleanup(); - PG_RE_THROW(); + break; } - PG_END_TRY(); - pltsql_estate_cleanup(); - break; - } case PLTSQL_STMT_EXEC: - { - pltsql_estate_setup(&estate, func, NULL, NULL); - copy_pltsql_datums(&estate, func); - PG_TRY(); - { - plan = prepare_stmt_exec(&estate, func, (PLtsql_stmt_exec *) stmt, false); - /* Clean up any leftover temporary memory */ - pltsql_destroy_econtext(&estate); - exec_eval_cleanup(&estate); - } - PG_CATCH(); { + pltsql_estate_setup(&estate, func, NULL, NULL); + copy_pltsql_datums(&estate, func); + PG_TRY(); + { + plan = prepare_stmt_exec(&estate, func, (PLtsql_stmt_exec *) stmt, false); + /* Clean up any leftover temporary memory */ + pltsql_destroy_econtext(&estate); + exec_eval_cleanup(&estate); + } + PG_CATCH(); + { + pltsql_estate_cleanup(); + PG_RE_THROW(); + } + PG_END_TRY(); pltsql_estate_cleanup(); - PG_RE_THROW(); + break; } - PG_END_TRY(); - pltsql_estate_cleanup(); - break; - } case PLTSQL_STMT_PUSH_RESULT: - { - PLtsql_stmt_push_result *push_result = (PLtsql_stmt_push_result *) stmt; - pltsql_estate_setup(&estate, func, NULL, NULL); - copy_pltsql_datums(&estate, func); - PG_TRY(); - { - exec_prepare_plan(&estate, push_result->query, 0, true); - plan = push_result->query->plan; - /* Clean up any leftover temporary memory */ - pltsql_destroy_econtext(&estate); - exec_eval_cleanup(&estate); - } - PG_CATCH(); { + PLtsql_stmt_push_result *push_result = (PLtsql_stmt_push_result *) stmt; + + pltsql_estate_setup(&estate, func, NULL, NULL); + copy_pltsql_datums(&estate, func); + PG_TRY(); + { + exec_prepare_plan(&estate, push_result->query, 0, true); + plan = push_result->query->plan; + /* Clean up any leftover temporary memory */ + pltsql_destroy_econtext(&estate); + exec_eval_cleanup(&estate); + } + PG_CATCH(); + { + pltsql_estate_cleanup(); + PG_RE_THROW(); + } + PG_END_TRY(); + pltsql_estate_cleanup(); - PG_RE_THROW(); + break; } - PG_END_TRY(); - - pltsql_estate_cleanup(); - break; - } default: break; } return plan; } -void cleanup_temporal_plan(ExecCodes *exec_codes) +void +cleanup_temporal_plan(ExecCodes *exec_codes) { PLtsql_stmt *stmt; + stmt = *(PLtsql_stmt **) vec_at(exec_codes->codes, 0); if (stmt->cmd_type == PLTSQL_STMT_EXEC) { PLtsql_stmt_exec *stmt_exec = (PLtsql_stmt_exec *) stmt; + if (stmt_exec->expr->plan && !stmt_exec->expr->plan->saved) stmt_exec->expr->plan = NULL; } diff --git a/contrib/babelfishpg_tsql/src/procedures.c b/contrib/babelfishpg_tsql/src/procedures.c index 952ffdb7dd..86851f42b4 100644 --- a/contrib/babelfishpg_tsql/src/procedures.c +++ b/contrib/babelfishpg_tsql/src/procedures.c @@ -1,7 +1,7 @@ /*------------------------------------------------------------------------- * * procedures.c - * Built-in Procedures for Babel + * Built-in Procedures for Babel * *------------------------------------------------------------------------- */ @@ -34,7 +34,7 @@ #include "parser/parse_relation.h" #include "parser/parse_target.h" #include "parser/parse_relation.h" -#include "parser/scansup.h" +#include "parser/scansup.h" #include "tcop/pquery.h" #include "tcop/tcopprot.h" #include "tcop/utility.h" @@ -68,8 +68,8 @@ PG_FUNCTION_INFO_V1(sp_rename_internal); extern void delete_cached_batch(int handle); extern InlineCodeBlockArgs *create_args(int numargs); -extern void read_param_def(InlineCodeBlockArgs * args, const char *paramdefstr); -extern int execute_batch(PLtsql_execstate *estate, char *batch, InlineCodeBlockArgs *args, List *params); +extern void read_param_def(InlineCodeBlockArgs *args, const char *paramdefstr); +extern int execute_batch(PLtsql_execstate *estate, char *batch, InlineCodeBlockArgs *args, List *params); extern PLtsql_execstate *get_current_tsql_estate(void); static List *gen_sp_addrole_subcmds(const char *user); static List *gen_sp_droprole_subcmds(const char *user); @@ -78,50 +78,52 @@ static List *gen_sp_droprolemember_subcmds(const char *user, const char *member) static List *gen_sp_rename_subcmds(const char *objname, const char *newname, const char *schemaname, ObjectType objtype); static void exec_utility_cmd_helper(char *query_str); -List *handle_bool_expr_rec(BoolExpr *expr, List *list); -List *handle_where_clause_attnums(ParseState *pstate, Node *w_clause, List *target_attnums); -List *handle_where_clause_restargets_left(ParseState *pstate, Node *w_clause, List *extra_restargets); -List *handle_where_clause_restargets_right(ParseState *pstate, Node *w_clause, List *extra_restargets); +List *handle_bool_expr_rec(BoolExpr *expr, List *list); +List *handle_where_clause_attnums(ParseState *pstate, Node *w_clause, List *target_attnums); +List *handle_where_clause_restargets_left(ParseState *pstate, Node *w_clause, List *extra_restargets); +List *handle_where_clause_restargets_right(ParseState *pstate, Node *w_clause, List *extra_restargets); -char *sp_describe_first_result_set_view_name = NULL; +char *sp_describe_first_result_set_view_name = NULL; -bool sp_describe_first_result_set_inprogress = false; -char *orig_proc_funcname = NULL; +bool sp_describe_first_result_set_inprogress = false; +char *orig_proc_funcname = NULL; Datum sp_unprepare(PG_FUNCTION_ARGS) { - int32_t handle; + int32_t handle; + TSQLInstrumentation(INSTR_TSQL_SP_UNPREPARE); - if (PG_ARGISNULL(0)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("expect handle as integer"))); + if (PG_ARGISNULL(0)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("expect handle as integer"))); - handle = PG_GETARG_INT32(0); + handle = PG_GETARG_INT32(0); delete_cached_batch(handle); - PG_RETURN_VOID(); + PG_RETURN_VOID(); } Datum sp_prepare(PG_FUNCTION_ARGS) { - char *params = PG_ARGISNULL(1) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(1)); - char *batch = PG_ARGISNULL(2) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(2)); - /*int options = PG_GETARG_INT32(3); */ - InlineCodeBlockArgs *args; - HeapTuple tuple; - HeapTupleHeader result; - TupleDesc tupdesc; - bool isnull = false; - Datum values[1]; + char *params = PG_ARGISNULL(1) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(1)); + char *batch = PG_ARGISNULL(2) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(2)); + + /* int options = PG_GETARG_INT32(3); */ + InlineCodeBlockArgs *args; + HeapTuple tuple; + HeapTupleHeader result; + TupleDesc tupdesc; + bool isnull = false; + Datum values[1]; const char *old_dialect; if (!batch) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("query argument of sp_prepare is null"))); + errmsg("query argument of sp_prepare is null"))); old_dialect = GetConfigOption("babelfishpg_tsql.sql_dialect", true, true); set_config_option("babelfishpg_tsql.sql_dialect", "tsql", @@ -136,14 +138,15 @@ sp_prepare(PG_FUNCTION_ARGS) if (params) read_param_def(args, params); - args->options = (BATCH_OPTION_CACHE_PLAN | - BATCH_OPTION_PREPARE_PLAN | - BATCH_OPTION_SEND_METADATA | - BATCH_OPTION_NO_EXEC); + args->options = (BATCH_OPTION_CACHE_PLAN | + BATCH_OPTION_PREPARE_PLAN | + BATCH_OPTION_SEND_METADATA | + BATCH_OPTION_NO_EXEC); PG_TRY(); { PLtsql_execstate *estate = get_current_tsql_estate(); + execute_batch(estate, batch, args, NULL); } PG_CATCH(); @@ -171,34 +174,35 @@ sp_prepare(PG_FUNCTION_ARGS) /* 5. Return back handle */ tupdesc = CreateTemplateTupleDesc(1); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "prep_handle", INT4OID, -1, 0); - tupdesc = BlessTupleDesc(tupdesc); - tuple = heap_form_tuple(tupdesc, values, &isnull); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "prep_handle", INT4OID, -1, 0); + tupdesc = BlessTupleDesc(tupdesc); + tuple = heap_form_tuple(tupdesc, values, &isnull); - result = (HeapTupleHeader) palloc(tuple->t_len); - memcpy(result, tuple->t_data, tuple->t_len); + result = (HeapTupleHeader) palloc(tuple->t_len); - heap_freetuple(tuple); - ReleaseTupleDesc(tupdesc); + memcpy(result, tuple->t_data, tuple->t_len); - PG_RETURN_HEAPTUPLEHEADER(result); + heap_freetuple(tuple); + ReleaseTupleDesc(tupdesc); + + PG_RETURN_HEAPTUPLEHEADER(result); } Datum sp_babelfish_configure(PG_FUNCTION_ARGS) { - int rc; - int nargs; + int rc; + int nargs; MemoryContext savedPortalCxt; /* SPI call input */ - const char* query = "SELECT name, setting, short_desc FROM sys.babelfish_configurations_view WHERE name like $1"; - Datum arg; - Oid argoid = TEXTOID; - char nulls = 0; + const char *query = "SELECT name, setting, short_desc FROM sys.babelfish_configurations_view WHERE name like $1"; + Datum arg; + Oid argoid = TEXTOID; + char nulls = 0; - SPIPlanPtr plan; - Portal portal; + SPIPlanPtr plan; + Portal portal; DestReceiver *receiver; nargs = PG_NARGS(); @@ -208,14 +212,16 @@ sp_babelfish_configure(PG_FUNCTION_ARGS) } else if (nargs == 1) { - const char* common_prefix = "babelfishpg_tsql."; + const char *common_prefix = "babelfishpg_tsql."; + + char *arg0 = PG_ARGISNULL(0) ? "%" : TextDatumGetCString(PG_GETARG_TEXT_PP(0)); - char *arg0 = PG_ARGISNULL(0) ? "%" : TextDatumGetCString(PG_GETARG_TEXT_PP(0)); if (strncmp(arg0, common_prefix, strlen(common_prefix)) == 0) arg = PointerGetDatum(cstring_to_text(arg0)); else { - char buf[1024]; + char buf[1024]; + snprintf(buf, 1024, "%s%s", common_prefix, arg0); arg = PointerGetDatum(cstring_to_text(buf)); } @@ -239,9 +245,10 @@ sp_babelfish_configure(PG_FUNCTION_ARGS) elog(ERROR, "SPI_cursor_open(\"%s\") failed", query); /* - * According to specifictation, sp_babelfish_configure returns a result-set. - * If there is no destination, it will send the result-set to client, which is not allowed behavior of PG procedures. - * To implement this behavior, we added a code to push the result. + * According to specifictation, sp_babelfish_configure returns a + * result-set. If there is no destination, it will send the result-set to + * client, which is not allowed behavior of PG procedures. To implement + * this behavior, we added a code to push the result. */ receiver = CreateDestReceiver(DestRemote); SetRemoteDestReceiverParams(receiver, portal); @@ -256,7 +263,7 @@ sp_babelfish_configure(PG_FUNCTION_ARGS) if ((rc = SPI_finish()) != SPI_OK_FINISH) elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc)); - PG_RETURN_VOID(); + PG_RETURN_VOID(); } /* @@ -266,108 +273,108 @@ sp_babelfish_configure(PG_FUNCTION_ARGS) typedef struct UndeclaredParams { /* Names of the undeclared parameters */ - char **paramnames; + char **paramnames; /* Indexes of the undeclared parameters in the targetattnums array */ - int *paramindexes; + int *paramindexes; /* - * The relevant attnums in the target table. - * For 'INSERT INTO t1 ...' it is all the attnums in the target table t1; - * for 'INSERT INTO t1 (a, c) ...' it is the attnums of columns a and c in - * the target table t1. + * The relevant attnums in the target table. For 'INSERT INTO t1 ...' it + * is all the attnums in the target table t1; for 'INSERT INTO t1 (a, c) + * ...' it is the attnums of columns a and c in the target table t1. */ - int *targetattnums; + int *targetattnums; /* The relevant colume names in the target table. */ - char **targetcolnames; + char **targetcolnames; /* Name of the target table */ - char *tablename; + char *tablename; /* The Oid of the table's schema */ - Oid schemaoid; + Oid schemaoid; } UndeclaredParams; -static char *sp_describe_first_result_set_query(char *viewName) +static char * +sp_describe_first_result_set_query(char *viewName) { return - psprintf( - "SELECT " - "CAST(0 AS sys.bit) AS is_hidden, " - "CAST(t3.\"ORDINAL_POSITION\" AS int) AS column_ordinal, " - "CAST(t3.\"COLUMN_NAME\" AS sys.sysname) AS name, " - "case " - "when t1.is_nullable collate sys.database_default = \'YES\' AND t3.\"DATA_TYPE\" collate sys.database_default <> \'timestamp\' then CAST(1 AS sys.bit) " - "else CAST(0 AS sys.bit) " - "end as is_nullable, " - "t4.system_type_id::int as system_type_id, " - "CAST(t3.\"DATA_TYPE\" as sys.nvarchar(256)) as system_type_name, " - "CAST(CASE WHEN t3.\"DATA_TYPE\" collate sys.database_default IN (\'text\', \'ntext\', \'image\') THEN -1 ELSE t4.max_length END AS smallint) AS max_length, " - "CAST(t4.precision AS sys.tinyint) AS precision, " - "CAST(t4.scale AS sys.tinyint) AS scale, " - "CAST(t4.collation_name AS sys.sysname) as collation_name, " - "CAST(CASE WHEN t4.system_type_id = t4.user_type_id THEN NULL " - "ELSE t4.user_type_id END as int) as user_type_id, " - "CAST(NULL as sys.sysname) as user_type_database, " - "CAST(NULL as sys.sysname) as user_type_schema, " - "CAST(CASE WHEN t4.system_type_id = t4.user_type_id THEN NULL " - "ELSE sys.OBJECT_NAME(t4.user_type_id::int) END as sys.sysname) as user_type_name, " - "CAST(NULL as sys.nvarchar(4000)) as assembly_qualified_type_name, " - "CAST(NULL as int) as xml_collection_id, " - "CAST(NULL as sys.sysname) as xml_collection_database, " - "CAST(NULL as sys.sysname) as xml_collection_schema, " - "CAST(NULL as sys.sysname) as xml_collection_name, " - "case " - "when t3.\"DATA_TYPE\" collate sys.database_default = \'xml\' then CAST(1 AS sys.bit) " - "else CAST(0 AS sys.bit) " - "end as is_xml_document, " - "0::sys.bit as is_case_sensitive, " - "CAST(0 as sys.bit) as is_fixed_length_clr_type, " - "CAST(NULL as sys.sysname) as source_server, " - "CAST(NULL as sys.sysname) as source_database, " - "CAST(NULL as sys.sysname) as source_schema, " - "CAST(NULL as sys.sysname) as source_table, " - "CAST(NULL as sys.sysname) as source_column, " - "case " - "when t1.is_identity collate sys.database_default = \'YES\' then CAST(1 AS sys.bit) " - "else CAST(0 AS sys.bit) " - "end as is_identity_column, " - "CAST(NULL as sys.bit) as is_part_of_unique_key, " /* pg_constraint */ - "case " - "when t1.is_updatable collate sys.database_default = \'YES\' AND t1.is_generated collate sys.database_default = \'NEVER\' AND t1.is_identity collate sys.database_default = \'NO\' AND t3.\"DATA_TYPE\" collate sys.database_default <> \'timestamp\' then CAST(1 AS sys.bit) " - "else CAST(0 AS sys.bit) " - "end as is_updateable, " - "case " - "when t1.is_generated collate sys.database_default = \'NEVER\' then CAST(0 AS sys.bit) " - "else CAST(1 AS sys.bit) " - "end as is_computed_column, " - "CAST(0 as sys.bit) as is_sparse_column_set, " - "CAST(NULL as smallint) ordinal_in_order_by_list, " - "CAST(NULL as smallint) order_by_list_length, " - "CAST(NULL as smallint) order_by_is_descending, " - /* below are for internal usage */ - "CAST(sys.get_tds_id(t3.\"DATA_TYPE\") as int) as tds_type_id, " - "CAST( " - "CASE " - "WHEN t3.\"DATA_TYPE\" collate sys.database_default = \'xml\' THEN 8100 " - "WHEN t3.\"DATA_TYPE\" collate sys.database_default = \'sql_variant\' THEN 8009 " - "WHEN t3.\"DATA_TYPE\" collate sys.database_default = \'numeric\' THEN 17 " - "WHEN t3.\"DATA_TYPE\" collate sys.database_default = \'decimal\' THEN 17 " - "ELSE t4.max_length END as int) " - "as tds_length, " - "CAST(COLLATIONPROPERTY(t4.collation_name, 'CollationId') as int) as tds_collation_id, " - "CAST(COLLATIONPROPERTY(t4.collation_name, 'SortId') as int) AS tds_collation_sort_id " - "FROM information_schema.columns t1, information_schema_tsql.columns t3, " - "sys.columns t4, pg_class t5 " - "LEFT OUTER JOIN (sys.babelfish_namespace_ext ext JOIN sys.pg_namespace_ext t6 ON t6.nspname = ext.nspname collate sys.database_default) " - "on t5.relnamespace = t6.oid " - "WHERE (t1.table_name = \'%s\' collate sys.database_default AND t1.table_schema = ext.nspname collate sys.database_default) " - "AND (t3.\"TABLE_NAME\" = t1.table_name collate sys.database_default AND t3.\"TABLE_SCHEMA\" = ext.orig_name collate sys.database_default) " - "AND t5.relname = t1.table_name collate sys.database_default " - "AND (t5.oid = t4.object_id AND t3.\"ORDINAL_POSITION\" = t4.column_id) " - "AND ext.dbid = cast(sys.db_id() as oid) " - "AND t1.dtd_identifier::int = t3.\"ORDINAL_POSITION\";", viewName); + psprintf( + "SELECT " + "CAST(0 AS sys.bit) AS is_hidden, " + "CAST(t3.\"ORDINAL_POSITION\" AS int) AS column_ordinal, " + "CAST(t3.\"COLUMN_NAME\" AS sys.sysname) AS name, " + "case " + "when t1.is_nullable collate sys.database_default = \'YES\' AND t3.\"DATA_TYPE\" collate sys.database_default <> \'timestamp\' then CAST(1 AS sys.bit) " + "else CAST(0 AS sys.bit) " + "end as is_nullable, " + "t4.system_type_id::int as system_type_id, " + "CAST(t3.\"DATA_TYPE\" as sys.nvarchar(256)) as system_type_name, " + "CAST(CASE WHEN t3.\"DATA_TYPE\" collate sys.database_default IN (\'text\', \'ntext\', \'image\') THEN -1 ELSE t4.max_length END AS smallint) AS max_length, " + "CAST(t4.precision AS sys.tinyint) AS precision, " + "CAST(t4.scale AS sys.tinyint) AS scale, " + "CAST(t4.collation_name AS sys.sysname) as collation_name, " + "CAST(CASE WHEN t4.system_type_id = t4.user_type_id THEN NULL " + "ELSE t4.user_type_id END as int) as user_type_id, " + "CAST(NULL as sys.sysname) as user_type_database, " + "CAST(NULL as sys.sysname) as user_type_schema, " + "CAST(CASE WHEN t4.system_type_id = t4.user_type_id THEN NULL " + "ELSE sys.OBJECT_NAME(t4.user_type_id::int) END as sys.sysname) as user_type_name, " + "CAST(NULL as sys.nvarchar(4000)) as assembly_qualified_type_name, " + "CAST(NULL as int) as xml_collection_id, " + "CAST(NULL as sys.sysname) as xml_collection_database, " + "CAST(NULL as sys.sysname) as xml_collection_schema, " + "CAST(NULL as sys.sysname) as xml_collection_name, " + "case " + "when t3.\"DATA_TYPE\" collate sys.database_default = \'xml\' then CAST(1 AS sys.bit) " + "else CAST(0 AS sys.bit) " + "end as is_xml_document, " + "0::sys.bit as is_case_sensitive, " + "CAST(0 as sys.bit) as is_fixed_length_clr_type, " + "CAST(NULL as sys.sysname) as source_server, " + "CAST(NULL as sys.sysname) as source_database, " + "CAST(NULL as sys.sysname) as source_schema, " + "CAST(NULL as sys.sysname) as source_table, " + "CAST(NULL as sys.sysname) as source_column, " + "case " + "when t1.is_identity collate sys.database_default = \'YES\' then CAST(1 AS sys.bit) " + "else CAST(0 AS sys.bit) " + "end as is_identity_column, " + "CAST(NULL as sys.bit) as is_part_of_unique_key, " /* pg_constraint */ + "case " + "when t1.is_updatable collate sys.database_default = \'YES\' AND t1.is_generated collate sys.database_default = \'NEVER\' AND t1.is_identity collate sys.database_default = \'NO\' AND t3.\"DATA_TYPE\" collate sys.database_default <> \'timestamp\' then CAST(1 AS sys.bit) " + "else CAST(0 AS sys.bit) " + "end as is_updateable, " + "case " + "when t1.is_generated collate sys.database_default = \'NEVER\' then CAST(0 AS sys.bit) " + "else CAST(1 AS sys.bit) " + "end as is_computed_column, " + "CAST(0 as sys.bit) as is_sparse_column_set, " + "CAST(NULL as smallint) ordinal_in_order_by_list, " + "CAST(NULL as smallint) order_by_list_length, " + "CAST(NULL as smallint) order_by_is_descending, " + /* below are for internal usage */ + "CAST(sys.get_tds_id(t3.\"DATA_TYPE\") as int) as tds_type_id, " + "CAST( " + "CASE " + "WHEN t3.\"DATA_TYPE\" collate sys.database_default = \'xml\' THEN 8100 " + "WHEN t3.\"DATA_TYPE\" collate sys.database_default = \'sql_variant\' THEN 8009 " + "WHEN t3.\"DATA_TYPE\" collate sys.database_default = \'numeric\' THEN 17 " + "WHEN t3.\"DATA_TYPE\" collate sys.database_default = \'decimal\' THEN 17 " + "ELSE t4.max_length END as int) " + "as tds_length, " + "CAST(COLLATIONPROPERTY(t4.collation_name, 'CollationId') as int) as tds_collation_id, " + "CAST(COLLATIONPROPERTY(t4.collation_name, 'SortId') as int) AS tds_collation_sort_id " + "FROM information_schema.columns t1, information_schema_tsql.columns t3, " + "sys.columns t4, pg_class t5 " + "LEFT OUTER JOIN (sys.babelfish_namespace_ext ext JOIN sys.pg_namespace_ext t6 ON t6.nspname = ext.nspname collate sys.database_default) " + "on t5.relnamespace = t6.oid " + "WHERE (t1.table_name = \'%s\' collate sys.database_default AND t1.table_schema = ext.nspname collate sys.database_default) " + "AND (t3.\"TABLE_NAME\" = t1.table_name collate sys.database_default AND t3.\"TABLE_SCHEMA\" = ext.orig_name collate sys.database_default) " + "AND t5.relname = t1.table_name collate sys.database_default " + "AND (t5.oid = t4.object_id AND t3.\"ORDINAL_POSITION\" = t4.column_id) " + "AND ext.dbid = cast(sys.db_id() as oid) " + "AND t1.dtd_identifier::int = t3.\"ORDINAL_POSITION\";", viewName); } /* @@ -378,27 +385,32 @@ sp_describe_first_result_set_internal(PG_FUNCTION_ARGS) { /* SRF related things to keep enough state between calls */ FuncCallContext *funcctx; - int call_cntr = 0; - int max_calls = 0; - TupleDesc tupdesc; + int call_cntr = 0; + int max_calls = 0; + TupleDesc tupdesc; AttInMetadata *attinmeta; SPITupleTable *tuptable; - char *batch; - char *query; - int rc; + char *batch; + char *query; + int rc; ANTLR_result result; - char *parsedbatch = NULL; + char *parsedbatch = NULL; /* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL()) { - MemoryContext oldcontext; + MemoryContext oldcontext; + funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - - batch = PG_ARGISNULL(0) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(0)); - /* TODO: params and browseMode has to be still implemented in this C-type function */ + + batch = PG_ARGISNULL(0) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(0)); + + /* + * TODO: params and browseMode has to be still implemented in this + * C-type function + */ sp_describe_first_result_set_view_name = psprintf("sp_describe_first_result_set_view_%d", rand()); get_call_result_type(fcinfo, NULL, &tupdesc); @@ -409,41 +421,51 @@ sp_describe_first_result_set_internal(PG_FUNCTION_ARGS) if (batch) { result = antlr_parser_cpp(batch); + if (!result.success) report_antlr_error(result); /* Skip if NULL query was passed. */ if (pltsql_parse_result->body) - parsedbatch = ((PLtsql_stmt_execsql *)lsecond(pltsql_parse_result->body))->sqlstmt->query; + parsedbatch = ((PLtsql_stmt_execsql *) lsecond(pltsql_parse_result->body))->sqlstmt->query; } - /* If TSQL Query is NULL string or a non-select query then send no rows. */ + /* + * If TSQL Query is NULL string or a non-select query then send no + * rows. + */ if (parsedbatch && strncasecmp(parsedbatch, "select", 6) == 0) { sp_describe_first_result_set_inprogress = true; query = psprintf("CREATE VIEW %s as %s", sp_describe_first_result_set_view_name, parsedbatch); - - /* Switch Dialect so that SPI_execute creates a TSQL View, obeying TSQL Syntax. */ + + /* + * Switch Dialect so that SPI_execute creates a TSQL View, obeying + * TSQL Syntax. + */ set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); if ((rc = SPI_execute(query, false, 1)) < 0) { sp_describe_first_result_set_inprogress = false; set_config_option("babelfishpg_tsql.sql_dialect", "postgres", - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); elog(ERROR, "SPI_execute failed: %s", SPI_result_code_string(rc)); } sp_describe_first_result_set_inprogress = false; set_config_option("babelfishpg_tsql.sql_dialect", "postgres", - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); pfree(query); - /* Execute the Select statement in try/catch so that we drop the view in case of an error. */ + /* + * Execute the Select statement in try/catch so that we drop the + * view in case of an error. + */ PG_TRY(); { /* Now execute the actual query which fetches us the result. */ @@ -479,27 +501,27 @@ sp_describe_first_result_set_internal(PG_FUNCTION_ARGS) MemoryContextSwitchTo(oldcontext); } - + funcctx = SRF_PERCALL_SETUP(); call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; attinmeta = funcctx->attinmeta; - tuptable = funcctx->user_fctx; + tuptable = funcctx->user_fctx; if (call_cntr < max_calls) { - char **values; - HeapTuple tuple; + char **values; + HeapTuple tuple; Datum result; - int col; - int numCols = 39; + int col; + int numCols = 39; values = (char **) palloc(numCols * sizeof(char *)); for (col = 0; col < numCols; col++) values[col] = SPI_getvalue(tuptable->vals[call_cntr], - tuptable->tupdesc, col+1); + tuptable->tupdesc, col + 1); tuple = BuildTupleFromCStrings(attinmeta, values); result = HeapTupleGetDatum(tuple); @@ -525,19 +547,22 @@ sp_describe_first_result_set_internal(PG_FUNCTION_ARGS) * Recurse down the BoolExpr if needed, and append all relevant ColumnRef->fields * to the list. */ -List *handle_bool_expr_rec(BoolExpr *expr, List *list) +List * +handle_bool_expr_rec(BoolExpr *expr, List *list) { - List *args = expr->args; - ListCell *lc; - A_Expr *xpr; - ColumnRef *ref; + List *args = expr->args; + ListCell *lc; + A_Expr *xpr; + ColumnRef *ref; + foreach(lc, args) { - Expr *arg = (Expr *) lfirst(lc); - switch(arg->type) + Expr *arg = (Expr *) lfirst(lc); + + switch (arg->type) { case T_A_Expr: - xpr = (A_Expr *)arg; + xpr = (A_Expr *) arg; if (nodeTag(xpr->rexpr) != T_ColumnRef) { @@ -549,7 +574,7 @@ List *handle_bool_expr_rec(BoolExpr *expr, List *list) list = list_concat(list, ref->fields); break; case T_BoolExpr: - list = handle_bool_expr_rec((BoolExpr *)arg, list); + list = handle_bool_expr_rec((BoolExpr *) arg, list); break; default: break; @@ -562,19 +587,21 @@ List *handle_bool_expr_rec(BoolExpr *expr, List *list) * Returns a list of attnums constructed from the where clause provided, using * the column names given on the left hand side of the assignments */ -List *handle_where_clause_attnums(ParseState *pstate, Node *w_clause, List *target_attnums) +List * +handle_where_clause_attnums(ParseState *pstate, Node *w_clause, List *target_attnums) { /* * Append attnos from WHERE clause into target_attnums */ - ColumnRef *ref; - String *field; - char *name; - int attrno; - + ColumnRef *ref; + String *field; + char *name; + int attrno; + if (nodeTag(w_clause) == T_A_Expr) { - A_Expr *where_clause = (A_Expr *)w_clause; + A_Expr *where_clause = (A_Expr *) w_clause; + if (nodeTag(where_clause->lexpr) != T_ColumnRef) { ereport(ERROR, @@ -588,49 +615,51 @@ List *handle_where_clause_attnums(ParseState *pstate, Node *w_clause, List *targ if (attrno == InvalidAttrNumber) { ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_COLUMN), - errmsg("column \"%s\" of relation \"%s\" does not exist", - name, - RelationGetRelationName(pstate->p_target_relation)))); + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" of relation \"%s\" does not exist", + name, + RelationGetRelationName(pstate->p_target_relation)))); } return lappend_int(target_attnums, attrno); } else if (nodeTag(w_clause) == T_BoolExpr) { - BoolExpr *where_clause = (BoolExpr *)w_clause; - ListCell *lc; + BoolExpr *where_clause = (BoolExpr *) w_clause; + ListCell *lc; + foreach(lc, where_clause->args) { - Expr *arg = (Expr *) lfirst(lc); - A_Expr *xpr; - switch(arg->type) + Expr *arg = (Expr *) lfirst(lc); + A_Expr *xpr; + + switch (arg->type) { case T_A_Expr: - { - xpr = (A_Expr *)arg; - - if (nodeTag(xpr->lexpr) != T_ColumnRef) - { - ereport(WARNING, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Unsupported use case in sp_describe_undeclared_parameters"))); - } - ref = (ColumnRef *) xpr->lexpr; - field = linitial(ref->fields); - name = field->sval; - attrno = attnameAttNum(pstate->p_target_relation, name, false); - if (attrno == InvalidAttrNumber) { - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_COLUMN), - errmsg("column \"%s\" of relation \"%s\" does not exist", - name, - RelationGetRelationName(pstate->p_target_relation)))); + xpr = (A_Expr *) arg; + + if (nodeTag(xpr->lexpr) != T_ColumnRef) + { + ereport(WARNING, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Unsupported use case in sp_describe_undeclared_parameters"))); + } + ref = (ColumnRef *) xpr->lexpr; + field = linitial(ref->fields); + name = field->sval; + attrno = attnameAttNum(pstate->p_target_relation, name, false); + if (attrno == InvalidAttrNumber) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" of relation \"%s\" does not exist", + name, + RelationGetRelationName(pstate->p_target_relation)))); + } + target_attnums = lappend_int(target_attnums, attrno); + break; } - target_attnums = lappend_int(target_attnums, attrno); - break; - } case T_BoolExpr: target_attnums = handle_where_clause_attnums(pstate, (Node *) arg, target_attnums); break; @@ -653,19 +682,22 @@ List *handle_where_clause_attnums(ParseState *pstate, Node *w_clause, List *targ * Returns a list of ResTargets constructed from the where clause provided, using * the left hand side of the assignment (assumed to be intended as column names). */ -List *handle_where_clause_restargets_left(ParseState *pstate, Node *w_clause, List *extra_restargets) +List * +handle_where_clause_restargets_left(ParseState *pstate, Node *w_clause, List *extra_restargets) { /* * Construct a ResTarget and append it to the list. */ - ColumnRef *ref; - String *field; - char *name; - int attrno; + ColumnRef *ref; + String *field; + char *name; + int attrno; + if (nodeTag(w_clause) == T_A_Expr) { - A_Expr *where_clause = (A_Expr *)w_clause; - ResTarget *res; + A_Expr *where_clause = (A_Expr *) w_clause; + ResTarget *res; + if (nodeTag(where_clause->lexpr) != T_ColumnRef) { ereport(ERROR, @@ -679,63 +711,66 @@ List *handle_where_clause_restargets_left(ParseState *pstate, Node *w_clause, Li if (attrno == InvalidAttrNumber) { ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_COLUMN), - errmsg("column \"%s\" of relation \"%s\" does not exist", - name, - RelationGetRelationName(pstate->p_target_relation)))); + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" of relation \"%s\" does not exist", + name, + RelationGetRelationName(pstate->p_target_relation)))); } res = (ResTarget *) palloc(sizeof(ResTarget)); res->type = ref->type; res->name = field->sval; res->indirection = NIL; /* Unused for now */ - res->val = (Node *) ref; /* Store the ColumnRef here if needed */ + res->val = (Node *) ref; /* Store the ColumnRef here if needed */ res->location = ref->location; return lappend(extra_restargets, res); } else if (nodeTag(w_clause) == T_BoolExpr) { - BoolExpr *where_clause = (BoolExpr *)w_clause; - ListCell *lc; + BoolExpr *where_clause = (BoolExpr *) w_clause; + ListCell *lc; + foreach(lc, where_clause->args) { - Expr *arg = (Expr *) lfirst(lc); - A_Expr *xpr; - ResTarget *res; - switch(arg->type) + Expr *arg = (Expr *) lfirst(lc); + A_Expr *xpr; + ResTarget *res; + + switch (arg->type) { case T_A_Expr: - { - xpr = (A_Expr *)arg; - - if (nodeTag(xpr->lexpr) != T_ColumnRef) { - ereport(WARNING, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Unsupported use case in sp_describe_undeclared_parameters"))); - } - ref = (ColumnRef *) xpr->lexpr; - field = linitial(ref->fields); - name = field->sval; - attrno = attnameAttNum(pstate->p_target_relation, name, false); - if (attrno == InvalidAttrNumber) - { - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_COLUMN), - errmsg("column \"%s\" of relation \"%s\" does not exist", - name, - RelationGetRelationName(pstate->p_target_relation)))); + xpr = (A_Expr *) arg; + + if (nodeTag(xpr->lexpr) != T_ColumnRef) + { + ereport(WARNING, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Unsupported use case in sp_describe_undeclared_parameters"))); + } + ref = (ColumnRef *) xpr->lexpr; + field = linitial(ref->fields); + name = field->sval; + attrno = attnameAttNum(pstate->p_target_relation, name, false); + if (attrno == InvalidAttrNumber) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" of relation \"%s\" does not exist", + name, + RelationGetRelationName(pstate->p_target_relation)))); + } + res = (ResTarget *) palloc(sizeof(ResTarget)); + res->type = ref->type; + res->name = field->sval; + res->indirection = NIL; /* Unused for now */ + res->val = (Node *) ref; /* Store the ColumnRef + * here if needed */ + res->location = ref->location; + + extra_restargets = lappend(extra_restargets, res); + break; } - res = (ResTarget *) palloc(sizeof(ResTarget)); - res->type = ref->type; - res->name = field->sval; - res->indirection = NIL; /* Unused for now */ - res->val = (Node *) ref; /* Store the ColumnRef here if needed */ - res->location = ref->location; - - extra_restargets = lappend(extra_restargets, res); - break; - } case T_BoolExpr: extra_restargets = handle_where_clause_restargets_left(pstate, (Node *) arg, extra_restargets); break; @@ -758,17 +793,20 @@ List *handle_where_clause_restargets_left(ParseState *pstate, Node *w_clause, Li * Returns a list of ResTargets constructed from the where clause provided, using * the right hand side of the assignment (assumed to be values/parameters). */ -List *handle_where_clause_restargets_right(ParseState *pstate, Node *w_clause, List *extra_restargets) +List * +handle_where_clause_restargets_right(ParseState *pstate, Node *w_clause, List *extra_restargets) { /* * Construct a ResTarget and append it to the list. */ - ColumnRef *ref; - String *field; - ResTarget *res; + ColumnRef *ref; + String *field; + ResTarget *res; + if (nodeTag(w_clause) == T_A_Expr) { - A_Expr *where_clause = (A_Expr *)w_clause; + A_Expr *where_clause = (A_Expr *) w_clause; + if (nodeTag(where_clause->rexpr) != T_ColumnRef) { ereport(ERROR, @@ -781,43 +819,46 @@ List *handle_where_clause_restargets_right(ParseState *pstate, Node *w_clause, L res->type = ref->type; res->name = field->sval; res->indirection = NIL; /* Unused for now */ - res->val = (Node *) ref; /* Store the ColumnRef here if needed */ + res->val = (Node *) ref; /* Store the ColumnRef here if needed */ res->location = ref->location; return lappend(extra_restargets, res); } else if (nodeTag(w_clause) == T_BoolExpr) { - BoolExpr *where_clause = (BoolExpr *)w_clause; - ListCell *lc; + BoolExpr *where_clause = (BoolExpr *) w_clause; + ListCell *lc; + foreach(lc, where_clause->args) { - Expr *arg = (Expr *) lfirst(lc); - A_Expr *xpr; - switch(arg->type) + Expr *arg = (Expr *) lfirst(lc); + A_Expr *xpr; + + switch (arg->type) { case T_A_Expr: - { - xpr = (A_Expr *)arg; - - if (nodeTag(xpr->rexpr) != T_ColumnRef) { - ereport(WARNING, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Unsupported use case in sp_describe_undeclared_parameters"))); + xpr = (A_Expr *) arg; + + if (nodeTag(xpr->rexpr) != T_ColumnRef) + { + ereport(WARNING, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Unsupported use case in sp_describe_undeclared_parameters"))); + } + ref = (ColumnRef *) xpr->rexpr; + field = linitial(ref->fields); + res = (ResTarget *) palloc(sizeof(ResTarget)); + res->type = ref->type; + res->name = field->sval; + res->indirection = NIL; /* Unused for now */ + res->val = (Node *) ref; /* Store the ColumnRef + * here if needed */ + res->location = ref->location; + + extra_restargets = lappend(extra_restargets, res); + break; } - ref = (ColumnRef *) xpr->rexpr; - field = linitial(ref->fields); - res = (ResTarget *) palloc(sizeof(ResTarget)); - res->type = ref->type; - res->name = field->sval; - res->indirection = NIL; /* Unused for now */ - res->val = (Node *) ref; /* Store the ColumnRef here if needed */ - res->location = ref->location; - - extra_restargets = lappend(extra_restargets, res); - break; - } case T_BoolExpr: extra_restargets = handle_where_clause_restargets_right(pstate, (Node *) arg, extra_restargets); break; @@ -845,49 +886,49 @@ sp_describe_undeclared_parameters_internal(PG_FUNCTION_ARGS) { /* SRF related things to keep enough state between calls */ FuncCallContext *funcctx; - int call_cntr; - int max_calls; - TupleDesc tupdesc; + int call_cntr; + int max_calls; + TupleDesc tupdesc; AttInMetadata *attinmeta; ANTLR_result result; - List *raw_parsetree_list; - ListCell *list_item; - InlineCodeBlockArgs *args; + List *raw_parsetree_list; + ListCell *list_item; + InlineCodeBlockArgs *args; UndeclaredParams *undeclaredparams; if (SRF_IS_FIRSTCALL()) { /* - * In the first call of the SRF, we do all the processing, and store the - * result and state information in a UndeclaredParams struct in + * In the first call of the SRF, we do all the processing, and store + * the result and state information in a UndeclaredParams struct in * funcctx->user_fctx */ MemoryContext oldcontext; - char *batch; - char *parsedbatch; - char *params; - int sql_dialect_value_old; + char *batch; + char *parsedbatch; + char *params; + int sql_dialect_value_old; SelectStmt *select_stmt; - List *values_list; - ListCell *lc; - int numresults = 0; - int num_target_attnums = 0; + List *values_list; + ListCell *lc; + int numresults = 0; + int num_target_attnums = 0; RawStmt *parsetree; InsertStmt *insert_stmt = NULL; UpdateStmt *update_stmt = NULL; DeleteStmt *delete_stmt = NULL; - RangeVar *relation; - Oid relid; - Relation r; - List *target_attnums = NIL; - List *extra_restargets = NIL; + RangeVar *relation; + Oid relid; + Relation r; + List *target_attnums = NIL; + List *extra_restargets = NIL; ParseState *pstate; - int relname_len; - List *cols; - int target_attnum_i; - int target_attnums_len; + int relname_len; + List *cols; + int target_attnum_i; + int target_attnums_len; funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); @@ -904,22 +945,24 @@ sp_describe_undeclared_parameters_internal(PG_FUNCTION_ARGS) /* First, pass the batch to the ANTLR parser */ result = antlr_parser_cpp(batch); + if (!result.success) report_antlr_error(result); + /* - * For the currently supported use case, the parse result should contain - * two statements, INIT and EXECSQL. The EXECSQL statement should be an - * INSERT statement with VALUES clause. + * For the currently supported use case, the parse result should + * contain two statements, INIT and EXECSQL. The EXECSQL statement + * should be an INSERT statement with VALUES clause. */ if (!pltsql_parse_result || list_length(pltsql_parse_result->body) != 2 || - ((PLtsql_stmt *)lsecond(pltsql_parse_result->body))->cmd_type != PLTSQL_STMT_EXECSQL) + ((PLtsql_stmt *) lsecond(pltsql_parse_result->body))->cmd_type != PLTSQL_STMT_EXECSQL) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Unsupported use case in sp_describe_undeclared_parameters"))); } - parsedbatch = ((PLtsql_stmt_execsql *)lsecond(pltsql_parse_result->body))->sqlstmt->query; + parsedbatch = ((PLtsql_stmt_execsql *) lsecond(pltsql_parse_result->body))->sqlstmt->query; args = create_args(0); if (params) @@ -942,12 +985,12 @@ sp_describe_undeclared_parameters_internal(PG_FUNCTION_ARGS) * Analyze the parsed statement to suggest types for undeclared * parameters */ - switch(nodeTag(parsetree->stmt)) + switch (nodeTag(parsetree->stmt)) { case T_InsertStmt: rewrite_object_refs(parsetree->stmt); sql_dialect = sql_dialect_value_old; - insert_stmt = (InsertStmt *)parsetree->stmt; + insert_stmt = (InsertStmt *) parsetree->stmt; relation = insert_stmt->relation; relid = RangeVarGetRelid(relation, NoLock, false); r = relation_open(relid, AccessShareLock); @@ -958,7 +1001,7 @@ sp_describe_undeclared_parameters_internal(PG_FUNCTION_ARGS) case T_UpdateStmt: rewrite_object_refs(parsetree->stmt); sql_dialect = sql_dialect_value_old; - update_stmt = (UpdateStmt *)parsetree->stmt; + update_stmt = (UpdateStmt *) parsetree->stmt; relation = update_stmt->relation; relid = RangeVarGetRelid(relation, NoLock, false); r = relation_open(relid, AccessShareLock); @@ -979,10 +1022,10 @@ sp_describe_undeclared_parameters_internal(PG_FUNCTION_ARGS) if (attrno == InvalidAttrNumber) { ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_COLUMN), - errmsg("column \"%s\" of relation \"%s\" does not exist", - name, - RelationGetRelationName(pstate->p_target_relation)))); + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" of relation \"%s\" does not exist", + name, + RelationGetRelationName(pstate->p_target_relation)))); } target_attnums = lappend_int(target_attnums, attrno); } @@ -994,7 +1037,7 @@ sp_describe_undeclared_parameters_internal(PG_FUNCTION_ARGS) case T_DeleteStmt: rewrite_object_refs(parsetree->stmt); sql_dialect = sql_dialect_value_old; - delete_stmt = (DeleteStmt *)parsetree->stmt; + delete_stmt = (DeleteStmt *) parsetree->stmt; relation = delete_stmt->relation; relid = RangeVarGetRelid(relation, NoLock, false); r = relation_open(relid, AccessShareLock); @@ -1015,10 +1058,10 @@ sp_describe_undeclared_parameters_internal(PG_FUNCTION_ARGS) if (attrno == InvalidAttrNumber) { ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_COLUMN), - errmsg("column \"%s\" of relation \"%s\" does not exist", - name, - RelationGetRelationName(pstate->p_target_relation)))); + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" of relation \"%s\" does not exist", + name, + RelationGetRelationName(pstate->p_target_relation)))); } target_attnums = lappend_int(target_attnums, attrno); } @@ -1029,8 +1072,8 @@ sp_describe_undeclared_parameters_internal(PG_FUNCTION_ARGS) break; default: ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Unsupported use case in sp_describe_undeclared_parameters"))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Unsupported use case in sp_describe_undeclared_parameters"))); break; } @@ -1047,14 +1090,14 @@ sp_describe_undeclared_parameters_internal(PG_FUNCTION_ARGS) target_attnums_len = list_length(target_attnums); while (target_attnum_i < target_attnums_len) { - ListCell *lc; - ResTarget *col; - int colname_len; + ListCell *lc; + ResTarget *col; + int colname_len; lc = list_nth_cell(target_attnums, target_attnum_i); undeclaredparams->targetattnums[num_target_attnums] = lfirst_int(lc); - col = (ResTarget *)list_nth(cols, target_attnum_i); + col = (ResTarget *) list_nth(cols, target_attnum_i); colname_len = strlen(col->name); undeclaredparams->targetcolnames[num_target_attnums] = (char *) palloc(NAMEDATALEN); strncpy(undeclaredparams->targetcolnames[num_target_attnums], col->name, NAMEDATALEN); @@ -1067,17 +1110,22 @@ sp_describe_undeclared_parameters_internal(PG_FUNCTION_ARGS) relation_close(r, AccessShareLock); pfree(pstate); - /* Parse the list of parameters, and determine which and how many are undeclared. */ - switch(nodeTag(parsetree->stmt)) + /* + * Parse the list of parameters, and determine which and how many are + * undeclared. + */ + switch (nodeTag(parsetree->stmt)) { case T_InsertStmt: - select_stmt = (SelectStmt *)insert_stmt->selectStmt; + select_stmt = (SelectStmt *) insert_stmt->selectStmt; values_list = select_stmt->valuesLists; break; case T_UpdateStmt: - /* - * In an UPDATE statement, we could have both SET and WHERE with undeclared parameters. - * That's targetList (SET ...) and whereClause (WHERE ...) + + /* + * In an UPDATE statement, we could have both SET and WHERE + * with undeclared parameters. That's targetList (SET ...) and + * whereClause (WHERE ...) */ values_list = list_make1(handle_where_clause_restargets_right(pstate, update_stmt->whereClause, update_stmt->targetList)); break; @@ -1086,40 +1134,44 @@ sp_describe_undeclared_parameters_internal(PG_FUNCTION_ARGS) break; default: ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Unsupported use case in sp_describe_undeclared_parameters"))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Unsupported use case in sp_describe_undeclared_parameters"))); break; } - if (list_length(values_list) > 1) { + if (list_length(values_list) > 1) + { ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Unsupported use case in sp_describe_undeclared_parameters"))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Unsupported use case in sp_describe_undeclared_parameters"))); } foreach(lc, values_list) { - List *sublist = lfirst(lc); - ListCell *sublc; - int numvalues = 0; - int numtotalvalues = list_length(sublist); + List *sublist = lfirst(lc); + ListCell *sublc; + int numvalues = 0; + int numtotalvalues = list_length(sublist); + undeclaredparams->paramnames = (char **) palloc(sizeof(char *) * numtotalvalues); undeclaredparams->paramindexes = (int *) palloc(sizeof(int) * numtotalvalues); - if (list_length(sublist) != num_target_attnums) { + if (list_length(sublist) != num_target_attnums) + { ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Column name or number of supplied values does not match table definition."))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Column name or number of supplied values does not match table definition."))); } foreach(sublc, sublist) { - ColumnRef *columnref = NULL; - ResTarget *res; - List *fields; - ListCell *fieldcell; + ColumnRef *columnref = NULL; + ResTarget *res; + List *fields; + ListCell *fieldcell; + /* - * Tack on WHERE clause for the same as above, for - * UPDATE and DELETE statements. + * Tack on WHERE clause for the same as above, for UPDATE and + * DELETE statements. */ - switch(nodeTag(parsetree->stmt)) + switch (nodeTag(parsetree->stmt)) { case T_InsertStmt: columnref = lfirst(sublc); @@ -1133,7 +1185,7 @@ sp_describe_undeclared_parameters_internal(PG_FUNCTION_ARGS) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Unsupported use case in sp_describe_undeclared_parameters"))); } - columnref = (ColumnRef *)res->val; + columnref = (ColumnRef *) res->val; break; default: break; @@ -1148,12 +1200,14 @@ sp_describe_undeclared_parameters_internal(PG_FUNCTION_ARGS) foreach(fieldcell, fields) { - String *field = lfirst(fieldcell); + String *field = lfirst(fieldcell); + /* Make sure it's a parameter reference */ if (field->sval && field->sval[0] == '@') { - int i; - bool undeclared = true; + int i; + bool undeclared = true; + /* Make sure it is not declared in @params */ for (i = 0; i < args->numargs; ++i) { @@ -1166,7 +1220,8 @@ sp_describe_undeclared_parameters_internal(PG_FUNCTION_ARGS) } if (undeclared) { - int paramname_len = strlen(field->sval); + int paramname_len = strlen(field->sval); + undeclaredparams->paramnames[numresults] = (char *) palloc(NAMEDATALEN); strncpy(undeclaredparams->paramnames[numresults], field->sval, NAMEDATALEN); undeclaredparams->paramnames[numresults][paramname_len] = '\0'; @@ -1189,19 +1244,24 @@ sp_describe_undeclared_parameters_internal(PG_FUNCTION_ARGS) attinmeta = funcctx->attinmeta; undeclaredparams = funcctx->user_fctx; - /* This is the main recursive work, to determine the appropriate parameter type for each parameter. */ + /* + * This is the main recursive work, to determine the appropriate parameter + * type for each parameter. + */ if (call_cntr < max_calls) { - char **values; - HeapTuple tuple; + char **values; + HeapTuple tuple; Datum result; - int col; - int numresultcols = 24; - char *tempq = -" SELECT " - "CAST( 0 AS INT ) " /* AS "parameter_ordinal" -- Need to get correct ordinal number in code. */ - ", CAST( NULL AS sysname ) " /* AS "name" -- Need to get correct parameter name in code. */ - ", CASE " + int col; + int numresultcols = 24; + char *tempq = + " SELECT " + "CAST( 0 AS INT ) " /* AS "parameter_ordinal" -- Need to get + * correct ordinal number in code. */ + ", CAST( NULL AS sysname ) " /* AS "name" -- Need to get correct + * parameter name in code. */ + ", CASE " "WHEN T2.name COLLATE sys.database_default = \'bigint\' THEN 127 " "WHEN T2.name COLLATE sys.database_default = \'binary\' THEN 173 " "WHEN T2.name COLLATE sys.database_default = \'bit\' THEN 104 " @@ -1231,8 +1291,8 @@ sp_describe_undeclared_parameters_internal(PG_FUNCTION_ARGS) "WHEN T2.name COLLATE sys.database_default = \'varchar\' THEN 167 " "WHEN T2.name COLLATE sys.database_default = \'xml\' THEN 241 " "ELSE C.system_type_id " - "END " /* AS "suggested_system_type_id" */ - ", CASE " + "END " /* AS "suggested_system_type_id" */ + ", CASE " "WHEN T2.name COLLATE sys.database_default = \'decimal\' THEN \'decimal(\' + CAST( C.precision AS sys.VARCHAR(10) ) + \',\' + CAST( C.scale AS sys.VARCHAR(10) ) + \')\' " "WHEN T2.name COLLATE sys.database_default = \'numeric\' THEN \'numeric(\' + CAST( C.precision AS sys.VARCHAR(10) ) + \',\' + CAST( C.scale AS sys.VARCHAR(10) ) + \')\' " "WHEN T2.name COLLATE sys.database_default = \'char\' THEN \'char(\' + CAST( C.max_length AS sys.VARCHAR(10) ) + \')\' " @@ -1242,44 +1302,51 @@ sp_describe_undeclared_parameters_internal(PG_FUNCTION_ARGS) "WHEN T2.name COLLATE sys.database_default = \'datetimeoffset\' THEN \'datetimeoffset(\' + CAST( C.scale AS sys.VARCHAR(10) ) + \')\' " "WHEN T2.name COLLATE sys.database_default = \'time\' THEN \'time(\' + CAST( C.scale AS sys.VARCHAR(10) ) + \')\' " "WHEN T2.name COLLATE sys.database_default = \'varchar\' THEN " - "CASE WHEN C.max_length = -1 THEN \'varchar(max)\' " - "ELSE \'varchar(\' + CAST( C.max_length AS sys.VARCHAR(10) ) + \')\' " - "END " + "CASE WHEN C.max_length = -1 THEN \'varchar(max)\' " + "ELSE \'varchar(\' + CAST( C.max_length AS sys.VARCHAR(10) ) + \')\' " + "END " "WHEN T2.name COLLATE sys.database_default = \'nvarchar\' THEN " - "CASE WHEN C.max_length = -1 THEN \'nvarchar(max)\' " - "ELSE \'nvarchar(\' + CAST( C.max_length/2 AS sys.VARCHAR(10) ) + \')\' " - "END " + "CASE WHEN C.max_length = -1 THEN \'nvarchar(max)\' " + "ELSE \'nvarchar(\' + CAST( C.max_length/2 AS sys.VARCHAR(10) ) + \')\' " + "END " "WHEN T2.name COLLATE sys.database_default = \'varbinary\' THEN " "CASE WHEN C.max_length = -1 THEN \'varbinary(max)\' " - "ELSE \'varbinary(\' + CAST( C.max_length AS sys.VARCHAR(10) ) + \')\' " - "END " + "ELSE \'varbinary(\' + CAST( C.max_length AS sys.VARCHAR(10) ) + \')\' " + "END " "ELSE T2.name " - "END " /* AS "suggested_system_type_name" */ - ", CASE " + "END " /* AS "suggested_system_type_name" */ + ", CASE " "WHEN T2.name COLLATE sys.database_default IN (\'image\', \'ntext\',\'text\') THEN -1 " "ELSE C.max_length " - "END " /* AS "suggested_max_length" */ - ", C.precision " /* AS "suggested_precision" */ - ", C.scale " /* AS "suggested_scale" */ - ", CASE WHEN T.user_type_id = T.system_type_id THEN CAST( NULL AS INT ) ELSE T.user_type_id END " /* AS "suggested_user_type_id" */ - ", CASE WHEN T.user_type_id = T.system_type_id THEN CAST( NULL AS sysname) ELSE DB_NAME() END " /* AS "suggested_user_type_database" */ - ", CASE WHEN T.user_type_id = T.system_type_id THEN CAST( NULL AS sysname) ELSE SCHEMA_NAME( T.schema_id ) END " /* AS "suggested_user_type_schema" */ - ", CASE WHEN T.user_type_id = T.system_type_id THEN CAST( NULL AS sysname) ELSE T.name END " /* AS "suggested_user_type_name" */ - ", CAST( NULL AS NVARCHAR(4000) ) " /* AS "suggested_assembly_qualified_type_name" */ - ", CASE " + "END " /* AS "suggested_max_length" */ + ", C.precision " /* AS "suggested_precision" */ + ", C.scale " /* AS "suggested_scale" */ + ", CASE WHEN T.user_type_id = T.system_type_id THEN CAST( NULL AS INT ) ELSE T.user_type_id END " /* AS + * "suggested_user_type_id" */ + ", CASE WHEN T.user_type_id = T.system_type_id THEN CAST( NULL AS sysname) ELSE DB_NAME() END " /* AS + * "suggested_user_type_database" */ + ", CASE WHEN T.user_type_id = T.system_type_id THEN CAST( NULL AS sysname) ELSE SCHEMA_NAME( T.schema_id ) END " /* AS + * "suggested_user_type_schema" */ + ", CASE WHEN T.user_type_id = T.system_type_id THEN CAST( NULL AS sysname) ELSE T.name END " /* AS + * "suggested_user_type_name" */ + ", CAST( NULL AS NVARCHAR(4000) ) " /* AS + * "suggested_assembly_qualified_type_name" */ + ", CASE " "WHEN C.xml_collection_id = 0 THEN CAST( NULL AS INT ) " "ELSE C.xml_collection_id " - "END " /* AS "suggested_xml_collection_id" */ - ", CAST( NULL AS sysname ) " /* AS "suggested_xml_collection_database" */ - ", CAST( NULL AS sysname ) " /* AS "suggested_xml_collection_schema" */ - ", CAST( NULL AS sysname ) " /* AS "suggested_xml_collection_name" */ - ", C.is_xml_document " /* AS "suggested_is_xml_document" */ - ", CAST( 0 AS BIT ) " /* AS "suggested_is_case_sensitive" */ - ", CAST( 0 AS BIT ) " /* AS "suggested_is_fixed_length_clr_type" */ - ", CAST( 1 AS BIT ) " /* AS "suggested_is_input" */ - ", CAST( 0 AS BIT ) " /* AS "suggested_is_output" */ - ", CAST( NULL AS sysname ) " /* AS "formal_parameter_name" */ - ", CASE " + "END " /* AS "suggested_xml_collection_id" */ + ", CAST( NULL AS sysname ) " /* AS + * "suggested_xml_collection_database" */ + ", CAST( NULL AS sysname ) " /* AS + * "suggested_xml_collection_schema" */ + ", CAST( NULL AS sysname ) " /* AS "suggested_xml_collection_name" */ + ", C.is_xml_document " /* AS "suggested_is_xml_document" */ + ", CAST( 0 AS BIT ) " /* AS "suggested_is_case_sensitive" */ + ", CAST( 0 AS BIT ) " /* AS "suggested_is_fixed_length_clr_type" */ + ", CAST( 1 AS BIT ) " /* AS "suggested_is_input" */ + ", CAST( 0 AS BIT ) " /* AS "suggested_is_output" */ + ", CAST( NULL AS sysname ) " /* AS "formal_parameter_name" */ + ", CASE " "WHEN T2.name COLLATE sys.database_default IN (\'tinyint\', \'smallint\', \'int\', \'bigint\') THEN 38 " "WHEN T2.name COLLATE sys.database_default IN (\'float\', \'real\') THEN 109 " "WHEN T2.name COLLATE sys.database_default IN (\'smallmoney\', \'money\') THEN 110 " @@ -1303,8 +1370,8 @@ sp_describe_undeclared_parameters_internal(PG_FUNCTION_ARGS) "WHEN T2.name COLLATE sys.database_default = \'varchar\' THEN 167 " "WHEN T2.name COLLATE sys.database_default = \'xml\' THEN 241 " "ELSE C.system_type_id " - "END " /* AS "suggested_tds_type_id" */ - ", CASE " + "END " /* AS "suggested_tds_type_id" */ + ", CASE " "WHEN T2.name COLLATE sys.database_default = \'nvarchar\' AND C.max_length = -1 THEN 65535 " "WHEN T2.name COLLATE sys.database_default = \'varbinary\' AND C.max_length = -1 THEN 65535 " "WHEN T2.name COLLATE sys.database_default = \'varchar\' AND C.max_length = -1 THEN 65535 " @@ -1313,22 +1380,24 @@ sp_describe_undeclared_parameters_internal(PG_FUNCTION_ARGS) "WHEN T2.name COLLATE sys.database_default in (\'image\', \'text\') THEN 2147483647 " "WHEN T2.name COLLATE sys.database_default = \'ntext\' THEN 2147483646 " "ELSE CAST( C.max_length AS INT ) " - "END " /* AS "suggested_tds_length" */ -"FROM sys.objects O, sys.columns C, sys.types T, sys.types T2 " -"WHERE O.object_id = C.object_id " -"AND C.user_type_id = T.user_type_id " -"AND C.name = \'%s\' COLLATE sys.database_default " /* -- INPUT column name */ -"AND T.system_type_id = T2.user_type_id " /* -- To get system dt name. */ -"AND O.name = \'%s\' COLLATE sys.database_default " /* -- INPUT table name */ -"AND O.schema_id = %d " /* -- INPUT schema Oid */ -"AND O.type = \'U\'"; /* -- User tables only for the time being */ - - char *query = psprintf(tempq, - undeclaredparams->targetcolnames[undeclaredparams->paramindexes[call_cntr]], - undeclaredparams->tablename, - undeclaredparams->schemaoid); - - int rc = SPI_execute(query, true, 1); + "END " /* AS "suggested_tds_length" */ + "FROM sys.objects O, sys.columns C, sys.types T, sys.types T2 " + "WHERE O.object_id = C.object_id " + "AND C.user_type_id = T.user_type_id " + "AND C.name = \'%s\' COLLATE sys.database_default " /* -- INPUT column name */ + "AND T.system_type_id = T2.user_type_id " /* -- To get system dt + * name. */ + "AND O.name = \'%s\' COLLATE sys.database_default " /* -- INPUT table name */ + "AND O.schema_id = %d " /* -- INPUT schema Oid */ + "AND O.type = \'U\'"; /* -- User tables only for the time being */ + + char *query = psprintf(tempq, + undeclaredparams->targetcolnames[undeclaredparams->paramindexes[call_cntr]], + undeclaredparams->tablename, + undeclaredparams->schemaoid); + + int rc = SPI_execute(query, true, 1); + if (rc != SPI_OK_SELECT) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), @@ -1340,18 +1409,22 @@ sp_describe_undeclared_parameters_internal(PG_FUNCTION_ARGS) values = (char **) palloc(numresultcols * sizeof(char *)); - /* This sets the parameter ordinal attribute correctly, since the above query can't infer that information */ + /* + * This sets the parameter ordinal attribute correctly, since the + * above query can't infer that information + */ values[0] = psprintf("%d", call_cntr + 1); /* Then, pull the appropriate parameter name from the data type */ values[1] = undeclaredparams->paramnames[call_cntr]; for (col = 2; col < numresultcols; col++) { values[col] = SPI_getvalue(SPI_tuptable->vals[0], - SPI_tuptable->tupdesc, col+1); + SPI_tuptable->tupdesc, col + 1); } tuple = BuildTupleFromCStrings(attinmeta, values); result = HeapTupleGetDatum(tuple); + SPI_freetuptable(SPI_tuptable); SRF_RETURN_NEXT(funcctx, result); } @@ -1365,9 +1438,9 @@ sp_describe_undeclared_parameters_internal(PG_FUNCTION_ARGS) * Internal function used by procedure xp_qv. * The xp_qv procedure is called by SSMS. Only the minimum implementation is required. */ -Datum +Datum xp_qv_internal(PG_FUNCTION_ARGS) -{ +{ PG_RETURN_INT32(0); } @@ -1375,17 +1448,18 @@ xp_qv_internal(PG_FUNCTION_ARGS) * Internal function to create the xp_qv procedure in master.dbo schema. * Some applications invoke this referencing master.dbo.xp_qv */ -Datum +Datum create_xp_qv_in_master_dbo_internal(PG_FUNCTION_ARGS) -{ - char *query = NULL; - int rc = -1; +{ + char *query = NULL; + int rc = -1; + + char *tempq = "CREATE OR REPLACE PROCEDURE %s.xp_qv(IN SYS.NVARCHAR(256), IN SYS.NVARCHAR(256))" + "AS \'babelfishpg_tsql\', \'xp_qv_internal\' LANGUAGE C"; - char *tempq = "CREATE OR REPLACE PROCEDURE %s.xp_qv(IN SYS.NVARCHAR(256), IN SYS.NVARCHAR(256))" - "AS \'babelfishpg_tsql\', \'xp_qv_internal\' LANGUAGE C"; + const char *dbo_scm = get_dbo_schema_name("master"); - const char *dbo_scm = get_dbo_schema_name("master"); - if (dbo_scm == NULL) + if (dbo_scm == NULL) elog(ERROR, "Failed to retrieve dbo schema name"); query = psprintf(tempq, dbo_scm); @@ -1418,15 +1492,16 @@ create_xp_qv_in_master_dbo_internal(PG_FUNCTION_ARGS) Datum xp_instance_regread_internal(PG_FUNCTION_ARGS) { - int nargs = PG_NARGS() - 1; + int nargs = PG_NARGS() - 1; + /* Get data type OID of last parameter, which should be the OUT parameter. */ - Oid argtypeid = get_fn_expr_argtype(fcinfo->flinfo, nargs); + Oid argtypeid = get_fn_expr_argtype(fcinfo->flinfo, nargs); - HeapTuple tuple; - HeapTupleHeader result; - TupleDesc tupdesc; - bool isnull = true; - Datum values[1]; + HeapTuple tuple; + HeapTupleHeader result; + TupleDesc tupdesc; + bool isnull = true; + Datum values[1]; tupdesc = CreateTemplateTupleDesc(1); @@ -1441,38 +1516,40 @@ xp_instance_regread_internal(PG_FUNCTION_ARGS) values[0] = CStringGetDatum(NULL); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "out_param", CSTRINGOID, -1, 0); } - - tupdesc = BlessTupleDesc(tupdesc); - tuple = heap_form_tuple(tupdesc, values, &isnull); - result = (HeapTupleHeader) palloc(tuple->t_len); - memcpy(result, tuple->t_data, tuple->t_len); + tupdesc = BlessTupleDesc(tupdesc); + tuple = heap_form_tuple(tupdesc, values, &isnull); + + result = (HeapTupleHeader) palloc(tuple->t_len); + + memcpy(result, tuple->t_data, tuple->t_len); - heap_freetuple(tuple); - ReleaseTupleDesc(tupdesc); + heap_freetuple(tuple); + ReleaseTupleDesc(tupdesc); - PG_RETURN_HEAPTUPLEHEADER(result); + PG_RETURN_HEAPTUPLEHEADER(result); } /* * Internal function to create the xp_instance_regread procedure in master.dbo schema. * Some applications invoke this referencing master.dbo.xp_instance_regread */ -Datum +Datum create_xp_instance_regread_in_master_dbo_internal(PG_FUNCTION_ARGS) -{ - char *query = NULL; - char *query2 = NULL; - int rc = -1; +{ + char *query = NULL; + char *query2 = NULL; + int rc = -1; - char *tempq = "CREATE OR REPLACE PROCEDURE %s.xp_instance_regread(IN p1 sys.nvarchar(512), IN p2 sys.sysname, IN p3 sys.nvarchar(512), INOUT out_param int)" - "AS \'babelfishpg_tsql\', \'xp_instance_regread_internal\' LANGUAGE C"; + char *tempq = "CREATE OR REPLACE PROCEDURE %s.xp_instance_regread(IN p1 sys.nvarchar(512), IN p2 sys.sysname, IN p3 sys.nvarchar(512), INOUT out_param int)" + "AS \'babelfishpg_tsql\', \'xp_instance_regread_internal\' LANGUAGE C"; - char *tempq2 = "CREATE OR REPLACE PROCEDURE %s.xp_instance_regread(IN p1 sys.nvarchar(512), IN p2 sys.sysname, IN p3 sys.nvarchar(512), INOUT out_param sys.nvarchar(512))" - "AS \'babelfishpg_tsql\', \'xp_instance_regread_internal\' LANGUAGE C"; + char *tempq2 = "CREATE OR REPLACE PROCEDURE %s.xp_instance_regread(IN p1 sys.nvarchar(512), IN p2 sys.sysname, IN p3 sys.nvarchar(512), INOUT out_param sys.nvarchar(512))" + "AS \'babelfishpg_tsql\', \'xp_instance_regread_internal\' LANGUAGE C"; - const char *dbo_scm = get_dbo_schema_name("master"); - if (dbo_scm == NULL) + const char *dbo_scm = get_dbo_schema_name("master"); + + if (dbo_scm == NULL) elog(ERROR, "Failed to retrieve dbo schema name"); query = psprintf(tempq, dbo_scm); @@ -1502,21 +1579,24 @@ create_xp_instance_regread_in_master_dbo_internal(PG_FUNCTION_ARGS) PG_RETURN_INT32(0); } -Datum sp_addrole(PG_FUNCTION_ARGS) +Datum +sp_addrole(PG_FUNCTION_ARGS) { - char *rolname, *lowercase_rolname, *ownername; - size_t len; - char *physical_role_name; - Oid role_oid; - List *parsetree_list; - ListCell *parsetree_item; + char *rolname, + *lowercase_rolname, + *ownername; + size_t len; + char *physical_role_name; + Oid role_oid; + List *parsetree_list; + ListCell *parsetree_item; const char *saved_dialect = GetConfigOption("babelfishpg_tsql.sql_dialect", true, true); PG_TRY(); { set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); rolname = PG_ARGISNULL(0) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(0)); ownername = PG_ARGISNULL(1) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(1)); @@ -1524,47 +1604,51 @@ Datum sp_addrole(PG_FUNCTION_ARGS) /* Role name is not NULL */ if (rolname == NULL) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("Name cannot be NULL."))); + errmsg("Name cannot be NULL."))); - /* Ensure the database name input argument is lower-case, as all Babel role names are lower-case */ + /* + * Ensure the database name input argument is lower-case, as all Babel + * role names are lower-case + */ lowercase_rolname = lowerstr(rolname); /* Remove trailing whitespaces */ len = strlen(lowercase_rolname); - while(isspace(lowercase_rolname[len - 1])) + while (isspace(lowercase_rolname[len - 1])) lowercase_rolname[--len] = 0; - /* check if role name is empty after removing trailing spaces*/ + /* check if role name is empty after removing trailing spaces */ if (strlen(lowercase_rolname) == 0) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("Name cannot be NULL."))); + errmsg("Name cannot be NULL."))); /* - * @ownername is not yet supported in babelfish. - * Throw an error if @ownername is passed either as an empty string or contains value + * @ownername is not yet supported in babelfish. Throw an error if + * @ownername is passed either as an empty string or contains value */ - if(ownername) + if (ownername) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("The @ownername argument is not yet supported in Babelfish."))); + errmsg("The @ownername argument is not yet supported in Babelfish."))); /* Role name cannot contain '\' */ if (strchr(lowercase_rolname, '\\') != NULL) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("'%s' is not a valid name because it contains invalid characters.", rolname))); + errmsg("'%s' is not a valid name because it contains invalid characters.", rolname))); - /* Map the logical role name to its physical name in the database.*/ + /* Map the logical role name to its physical name in the database. */ physical_role_name = get_physical_user_name(get_cur_db_name(), lowercase_rolname); role_oid = get_role_oid(physical_role_name, true); /* Check if the user, group or role already exists */ if (role_oid) ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("User, group, or role '%s' already exists in the current database.", rolname))); + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("User, group, or role '%s' already exists in the current database.", rolname))); /* Remove trailing whitespaces */ len = strlen(rolname); - while(isspace(rolname[len - 1])) rolname[--len] = 0; + while (isspace(rolname[len - 1])) + rolname[--len] = 0; /* Advance cmd counter to make the delete visible */ CommandCounterIncrement(); @@ -1574,7 +1658,7 @@ Datum sp_addrole(PG_FUNCTION_ARGS) /* Run all subcommands */ foreach(parsetree_item, parsetree_list) { - Node *stmt = ((RawStmt *) lfirst(parsetree_item))->stmt; + Node *stmt = ((RawStmt *) lfirst(parsetree_item))->stmt; PlannedStmt *wrapper; /* need to make a wrapper PlannedStmt */ @@ -1587,13 +1671,13 @@ Datum sp_addrole(PG_FUNCTION_ARGS) /* do this step */ ProcessUtility(wrapper, - "(CREATE ROLE )", - false, - PROCESS_UTILITY_SUBCOMMAND, - NULL, - NULL, - None_Receiver, - NULL); + "(CREATE ROLE )", + false, + PROCESS_UTILITY_SUBCOMMAND, + NULL, + NULL, + None_Receiver, + NULL); /* make sure later steps can see the object created here */ CommandCounterIncrement(); @@ -1602,14 +1686,14 @@ Datum sp_addrole(PG_FUNCTION_ARGS) PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RE_THROW(); } PG_END_TRY(); set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_VOID(); } @@ -1617,10 +1701,10 @@ static List * gen_sp_addrole_subcmds(const char *user) { StringInfoData query; - List *res; - Node *stmt; + List *res; + Node *stmt; CreateRoleStmt *rolestmt; - List *user_options = NIL; + List *user_options = NIL; initStringInfo(&query); appendStringInfo(&query, "CREATE ROLE dummy; "); @@ -1628,8 +1712,8 @@ gen_sp_addrole_subcmds(const char *user) if (list_length(res) != 1) ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("Expected 1 statement but get %d statements after parsing", list_length(res)))); + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Expected 1 statement but get %d statements after parsing", list_length(res)))); stmt = parsetree_nth_stmt(res, 0); @@ -1641,64 +1725,68 @@ gen_sp_addrole_subcmds(const char *user) rewrite_object_refs(stmt); /* - * Add original_user_name before hand because placeholder - * query "(CREATE ROLE )" is being passed - * that doesn't contain the user name. + * Add original_user_name before hand because placeholder query "(CREATE + * ROLE )" is being passed that doesn't contain the user name. */ user_options = lappend(user_options, - makeDefElem("original_user_name", - (Node *) makeString((char *)user), - -1)); + makeDefElem("original_user_name", + (Node *) makeString((char *) user), + -1)); rolestmt->options = list_concat(rolestmt->options, user_options); - + return res; } -Datum sp_droprole(PG_FUNCTION_ARGS) +Datum +sp_droprole(PG_FUNCTION_ARGS) { - char *rolname, *lowercase_rolname; - size_t len; - char *physical_role_name; - Oid role_oid; - List *parsetree_list; - ListCell *parsetree_item; + char *rolname, + *lowercase_rolname; + size_t len; + char *physical_role_name; + Oid role_oid; + List *parsetree_list; + ListCell *parsetree_item; const char *saved_dialect = GetConfigOption("babelfishpg_tsql.sql_dialect", true, true); PG_TRY(); { set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); rolname = PG_ARGISNULL(0) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(0)); /* Role name is not NULL */ if (rolname == NULL) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("Name cannot be NULL."))); + errmsg("Name cannot be NULL."))); - /* Ensure the database name input argument is lower-case, as all Babel role names are lower-case */ + /* + * Ensure the database name input argument is lower-case, as all Babel + * role names are lower-case + */ lowercase_rolname = lowerstr(rolname); /* Remove trailing whitespaces */ len = strlen(lowercase_rolname); - while(isspace(lowercase_rolname[len - 1])) + while (isspace(lowercase_rolname[len - 1])) lowercase_rolname[--len] = 0; - /* check if role name is empty after removing trailing spaces*/ + /* check if role name is empty after removing trailing spaces */ if (strlen(lowercase_rolname) == 0) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("Name cannot be NULL."))); + errmsg("Name cannot be NULL."))); - /* Map the logical role name to its physical name in the database.*/ + /* Map the logical role name to its physical name in the database. */ physical_role_name = get_physical_user_name(get_cur_db_name(), lowercase_rolname); role_oid = get_role_oid(physical_role_name, true); - /* Check if the role does not exists*/ - if(role_oid == InvalidOid || !is_role(role_oid)) + /* Check if the role does not exists */ + if (role_oid == InvalidOid || !is_role(role_oid)) ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("Cannot drop the role '%s', because it does not exist or you do not have permission.", rolname))); + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("Cannot drop the role '%s', because it does not exist or you do not have permission.", rolname))); /* Advance cmd counter to make the delete visible */ CommandCounterIncrement(); @@ -1708,7 +1796,7 @@ Datum sp_droprole(PG_FUNCTION_ARGS) /* Run all subcommands */ foreach(parsetree_item, parsetree_list) { - Node *stmt = ((RawStmt *) lfirst(parsetree_item))->stmt; + Node *stmt = ((RawStmt *) lfirst(parsetree_item))->stmt; PlannedStmt *wrapper; /* need to make a wrapper PlannedStmt */ @@ -1721,13 +1809,13 @@ Datum sp_droprole(PG_FUNCTION_ARGS) /* do this step */ ProcessUtility(wrapper, - "(DROP ROLE )", - false, - PROCESS_UTILITY_SUBCOMMAND, - NULL, - NULL, - None_Receiver, - NULL); + "(DROP ROLE )", + false, + PROCESS_UTILITY_SUBCOMMAND, + NULL, + NULL, + None_Receiver, + NULL); /* make sure later steps can see the object created here */ CommandCounterIncrement(); @@ -1736,14 +1824,14 @@ Datum sp_droprole(PG_FUNCTION_ARGS) PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RE_THROW(); } PG_END_TRY(); set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_VOID(); } @@ -1751,8 +1839,8 @@ static List * gen_sp_droprole_subcmds(const char *user) { StringInfoData query; - List *res; - Node *stmt; + List *res; + Node *stmt; DropRoleStmt *dropstmt; initStringInfo(&query); @@ -1761,8 +1849,8 @@ gen_sp_droprole_subcmds(const char *user) if (list_length(res) != 1) ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("Expected 1 statement but get %d statements after parsing", list_length(res)))); + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Expected 1 statement but get %d statements after parsing", list_length(res)))); stmt = parsetree_nth_stmt(res, 0); dropstmt = (DropRoleStmt *) stmt; @@ -1772,7 +1860,7 @@ gen_sp_droprole_subcmds(const char *user) if (user && dropstmt->roles) { - RoleSpec *tmp; + RoleSpec *tmp; /* Update the statement with given role name */ tmp = (RoleSpec *) llast(dropstmt->roles); @@ -1781,80 +1869,93 @@ gen_sp_droprole_subcmds(const char *user) return res; } -Datum sp_addrolemember(PG_FUNCTION_ARGS) +Datum +sp_addrolemember(PG_FUNCTION_ARGS) { - char *rolname, *lowercase_rolname; - char *membername, *lowercase_membername; - size_t len; - char *physical_member_name; - char *physical_role_name; - Oid role_oid, member_oid; - List *parsetree_list; - ListCell *parsetree_item; + char *rolname, + *lowercase_rolname; + char *membername, + *lowercase_membername; + size_t len; + char *physical_member_name; + char *physical_role_name; + Oid role_oid, + member_oid; + List *parsetree_list; + ListCell *parsetree_item; const char *saved_dialect = GetConfigOption("babelfishpg_tsql.sql_dialect", true, true); PG_TRY(); { set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); rolname = PG_ARGISNULL(0) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(0)); membername = PG_ARGISNULL(1) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(1)); /* Role name, member name is not NULL */ - if (rolname == NULL || membername ==NULL) + if (rolname == NULL || membername == NULL) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("Name cannot be NULL."))); + errmsg("Name cannot be NULL."))); - /* Ensure the database name input argument is lower-case, as all Babel role names, user names are lower-case */ + /* + * Ensure the database name input argument is lower-case, as all Babel + * role names, user names are lower-case + */ lowercase_rolname = lowerstr(rolname); lowercase_membername = lowerstr(membername); - /* Remove trailing whitespaces in rolename and membername*/ + /* Remove trailing whitespaces in rolename and membername */ len = strlen(lowercase_rolname); - while(isspace(lowercase_rolname[len - 1])) + while (isspace(lowercase_rolname[len - 1])) lowercase_rolname[--len] = 0; len = strlen(lowercase_membername); - while(isspace(lowercase_membername[len - 1])) + while (isspace(lowercase_membername[len - 1])) lowercase_membername[--len] = 0; - /* check if rolename/membername is empty after removing trailing spaces*/ + /* + * check if rolename/membername is empty after removing trailing + * spaces + */ if (strlen(lowercase_rolname) == 0 || strlen(lowercase_membername) == 0) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("Name cannot be NULL."))); + errmsg("Name cannot be NULL."))); - /* Throws an error if role name and member name are same*/ - if(strcmp(lowercase_rolname,lowercase_membername)==0) + /* Throws an error if role name and member name are same */ + if (strcmp(lowercase_rolname, lowercase_membername) == 0) ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("Cannot make a role a member of itself."))); + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Cannot make a role a member of itself."))); - /* Map the logical member name to its physical name in the database.*/ + /* Map the logical member name to its physical name in the database. */ physical_member_name = get_physical_user_name(get_cur_db_name(), lowercase_membername); member_oid = get_role_oid(physical_member_name, true); - /* Check if the user, group or role does not exists and given member name is an role or user*/ - if(member_oid == InvalidOid || ( !is_role(member_oid) && !is_user(member_oid) )) + /* + * Check if the user, group or role does not exists and given member + * name is an role or user + */ + if (member_oid == InvalidOid || (!is_role(member_oid) && !is_user(member_oid))) ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("User or role '%s' does not exist in this database.", membername))); + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("User or role '%s' does not exist in this database.", membername))); - /* Map the logical role name to its physical name in the database.*/ + /* Map the logical role name to its physical name in the database. */ physical_role_name = get_physical_user_name(get_cur_db_name(), lowercase_rolname); role_oid = get_role_oid(physical_role_name, true); - /* Check if the role does not exists and given role name is an role*/ - if(role_oid == InvalidOid || !is_role(role_oid)) + /* Check if the role does not exists and given role name is an role */ + if (role_oid == InvalidOid || !is_role(role_oid)) ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("Cannot alter the role '%s', because it does not exist or you do not have permission.", rolname))); + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("Cannot alter the role '%s', because it does not exist or you do not have permission.", rolname))); - /* Check if the member oid is already a member of given role oid*/ - if(is_member_of_role_nosuper( role_oid, member_oid)) + /* Check if the member oid is already a member of given role oid */ + if (is_member_of_role_nosuper(role_oid, member_oid)) ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("Cannot make a role a member of itself."))); + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Cannot make a role a member of itself."))); /* Advance cmd counter to make the delete visible */ CommandCounterIncrement(); @@ -1864,7 +1965,7 @@ Datum sp_addrolemember(PG_FUNCTION_ARGS) /* Run all subcommands */ foreach(parsetree_item, parsetree_list) { - Node *stmt = ((RawStmt *) lfirst(parsetree_item))->stmt; + Node *stmt = ((RawStmt *) lfirst(parsetree_item))->stmt; PlannedStmt *wrapper; /* need to make a wrapper PlannedStmt */ @@ -1877,13 +1978,13 @@ Datum sp_addrolemember(PG_FUNCTION_ARGS) /* do this step */ ProcessUtility(wrapper, - "(ALTER ROLE )", - false, - PROCESS_UTILITY_SUBCOMMAND, - NULL, - NULL, - None_Receiver, - NULL); + "(ALTER ROLE )", + false, + PROCESS_UTILITY_SUBCOMMAND, + NULL, + NULL, + None_Receiver, + NULL); /* make sure later steps can see the object created here */ CommandCounterIncrement(); @@ -1892,14 +1993,14 @@ Datum sp_addrolemember(PG_FUNCTION_ARGS) PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RE_THROW(); } PG_END_TRY(); set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_VOID(); } @@ -1907,10 +2008,10 @@ static List * gen_sp_addrolemember_subcmds(const char *user, const char *member) { StringInfoData query; - List *res; - Node *stmt; + List *res; + Node *stmt; AccessPriv *granted; - RoleSpec *grantee; + RoleSpec *grantee; GrantRoleStmt *grant_role; initStringInfo(&query); @@ -1919,8 +2020,8 @@ gen_sp_addrolemember_subcmds(const char *user, const char *member) if (list_length(res) != 1) ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("Expected 1 statement but get %d statements after parsing", list_length(res)))); + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Expected 1 statement but get %d statements after parsing", list_length(res)))); stmt = parsetree_nth_stmt(res, 0); grant_role = (GrantRoleStmt *) stmt; @@ -1941,67 +2042,79 @@ gen_sp_addrolemember_subcmds(const char *user, const char *member) return res; } -Datum sp_droprolemember(PG_FUNCTION_ARGS) +Datum +sp_droprolemember(PG_FUNCTION_ARGS) { - char *rolname, *lowercase_rolname; - char *membername, *lowercase_membername; - size_t len; - char *physical_name; - Oid role_oid; - List *parsetree_list; - ListCell *parsetree_item; + char *rolname, + *lowercase_rolname; + char *membername, + *lowercase_membername; + size_t len; + char *physical_name; + Oid role_oid; + List *parsetree_list; + ListCell *parsetree_item; const char *saved_dialect = GetConfigOption("babelfishpg_tsql.sql_dialect", true, true); PG_TRY(); { set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); rolname = PG_ARGISNULL(0) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(0)); membername = PG_ARGISNULL(1) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(1)); /* Role name, member name is not NULL */ - if (rolname == NULL || membername ==NULL) + if (rolname == NULL || membername == NULL) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("Name cannot be NULL."))); + errmsg("Name cannot be NULL."))); - /* Ensure the database name input argument is lower-case, as all Babel role names, user names are lower-case */ + /* + * Ensure the database name input argument is lower-case, as all Babel + * role names, user names are lower-case + */ lowercase_rolname = lowerstr(rolname); lowercase_membername = lowerstr(membername); - /* Remove trailing whitespaces in rolename and membername*/ + /* Remove trailing whitespaces in rolename and membername */ len = strlen(lowercase_rolname); - while(isspace(lowercase_rolname[len - 1])) + while (isspace(lowercase_rolname[len - 1])) lowercase_rolname[--len] = 0; len = strlen(lowercase_membername); - while(isspace(lowercase_membername[len - 1])) + while (isspace(lowercase_membername[len - 1])) lowercase_membername[--len] = 0; - /* check if rolename/membername is empty after removing trailing spaces*/ + /* + * check if rolename/membername is empty after removing trailing + * spaces + */ if (strlen(lowercase_rolname) == 0 || strlen(lowercase_membername) == 0) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("Name cannot be NULL."))); + errmsg("Name cannot be NULL."))); - /* Map the logical role name to its physical name in the database.*/ + /* Map the logical role name to its physical name in the database. */ physical_name = get_physical_user_name(get_cur_db_name(), lowercase_rolname); role_oid = get_role_oid(physical_name, true); - /* Throw an error id the given role name doesn't exist or isn't a role*/ - if(role_oid == InvalidOid || !is_role(role_oid)) + /* Throw an error id the given role name doesn't exist or isn't a role */ + if (role_oid == InvalidOid || !is_role(role_oid)) ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("Cannot alter the role '%s', because it does not exist or you do not have permission.", rolname))); + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("Cannot alter the role '%s', because it does not exist or you do not have permission.", rolname))); - /* Map the logical member name to its physical name in the database.*/ + /* Map the logical member name to its physical name in the database. */ physical_name = get_physical_user_name(get_cur_db_name(), lowercase_membername); role_oid = get_role_oid(physical_name, true); - /* Throw an error id the given member name doesn't exist or isn't a role or user*/ - if(role_oid == InvalidOid || ( !is_role(role_oid) && !is_user(role_oid) )) + /* + * Throw an error id the given member name doesn't exist or isn't a + * role or user + */ + if (role_oid == InvalidOid || (!is_role(role_oid) && !is_user(role_oid))) ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("Cannot drop the principal '%s', because it does not exist or you do not have permission.", membername))); + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("Cannot drop the principal '%s', because it does not exist or you do not have permission.", membername))); /* Advance cmd counter to make the delete visible */ CommandCounterIncrement(); @@ -2011,7 +2124,7 @@ Datum sp_droprolemember(PG_FUNCTION_ARGS) /* Run all subcommands */ foreach(parsetree_item, parsetree_list) { - Node *stmt = ((RawStmt *) lfirst(parsetree_item))->stmt; + Node *stmt = ((RawStmt *) lfirst(parsetree_item))->stmt; PlannedStmt *wrapper; /* need to make a wrapper PlannedStmt */ @@ -2024,13 +2137,13 @@ Datum sp_droprolemember(PG_FUNCTION_ARGS) /* do this step */ ProcessUtility(wrapper, - "(ALTER ROLE )", - false, - PROCESS_UTILITY_SUBCOMMAND, - NULL, - NULL, - None_Receiver, - NULL); + "(ALTER ROLE )", + false, + PROCESS_UTILITY_SUBCOMMAND, + NULL, + NULL, + None_Receiver, + NULL); /* make sure later steps can see the object created here */ CommandCounterIncrement(); @@ -2039,14 +2152,14 @@ Datum sp_droprolemember(PG_FUNCTION_ARGS) PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RE_THROW(); } PG_END_TRY(); set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_VOID(); } @@ -2054,10 +2167,10 @@ static List * gen_sp_droprolemember_subcmds(const char *user, const char *member) { StringInfoData query; - List *res; - Node *stmt; + List *res; + Node *stmt; AccessPriv *granted; - RoleSpec *grantee; + RoleSpec *grantee; GrantRoleStmt *grant_role; initStringInfo(&query); @@ -2066,8 +2179,8 @@ gen_sp_droprolemember_subcmds(const char *user, const char *member) if (list_length(res) != 1) ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("Expected 1 statement but get %d statements after parsing", list_length(res)))); + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Expected 1 statement but get %d statements after parsing", list_length(res)))); stmt = parsetree_nth_stmt(res, 0); grant_role = (GrantRoleStmt *) stmt; @@ -2095,9 +2208,9 @@ gen_sp_droprolemember_subcmds(const char *user, const char *member) static void exec_utility_cmd_helper(char *query_str) { - List *parsetree_list; - Node *stmt; - PlannedStmt *wrapper; + List *parsetree_list; + Node *stmt; + PlannedStmt *wrapper; parsetree_list = raw_parser(query_str, RAW_PARSE_DEFAULT); @@ -2136,49 +2249,53 @@ exec_utility_cmd_helper(char *query_str) Datum sp_addlinkedserver_internal(PG_FUNCTION_ARGS) { - char *linked_server = PG_ARGISNULL(0) ? NULL : lowerstr(text_to_cstring(PG_GETARG_TEXT_P(0))); - char *srv_product = PG_ARGISNULL(1) ? NULL : lowerstr(text_to_cstring(PG_GETARG_TEXT_P(1))); - char *provider = PG_ARGISNULL(2) ? NULL : lowerstr(text_to_cstring(PG_GETARG_TEXT_P(2))); - char *data_src = PG_ARGISNULL(3) ? NULL : text_to_cstring(PG_GETARG_TEXT_P(3)); - char *provstr = PG_ARGISNULL(5) ? NULL : text_to_cstring(PG_GETARG_TEXT_P(5)); - char *catalog = PG_ARGISNULL(6) ? NULL : text_to_cstring(PG_GETARG_TEXT_P(6)); + char *linked_server = PG_ARGISNULL(0) ? NULL : lowerstr(text_to_cstring(PG_GETARG_TEXT_P(0))); + char *srv_product = PG_ARGISNULL(1) ? NULL : lowerstr(text_to_cstring(PG_GETARG_TEXT_P(1))); + char *provider = PG_ARGISNULL(2) ? NULL : lowerstr(text_to_cstring(PG_GETARG_TEXT_P(2))); + char *data_src = PG_ARGISNULL(3) ? NULL : text_to_cstring(PG_GETARG_TEXT_P(3)); + char *provstr = PG_ARGISNULL(5) ? NULL : text_to_cstring(PG_GETARG_TEXT_P(5)); + char *catalog = PG_ARGISNULL(6) ? NULL : text_to_cstring(PG_GETARG_TEXT_P(6)); StringInfoData query; - bool provider_warning = false, provstr_warning = false; + bool provider_warning = false, + provstr_warning = false; - if(!pltsql_enable_linked_servers) + if (!pltsql_enable_linked_servers) ereport(ERROR, - (errcode(ERRCODE_FDW_ERROR), - errmsg("'sp_addlinkedserver' is not currently supported in Babelfish"))); + (errcode(ERRCODE_FDW_ERROR), + errmsg("'sp_addlinkedserver' is not currently supported in Babelfish"))); if (linked_server == NULL) ereport(ERROR, (errcode(ERRCODE_FDW_ERROR), - errmsg("@server parameter cannot be NULL"))); - + errmsg("@server parameter cannot be NULL"))); + if (srv_product && (strlen(srv_product) == 10) && (strncmp(srv_product, "sql server", 10) == 0)) { /* - * if server product is "SQL Server", rest of the arguments need not be - * specified except the linked server name. The linked server name in - * such a case, also doubles up as the linked server data source. + * if server product is "SQL Server", rest of the arguments need not + * be specified except the linked server name. The linked server name + * in such a case, also doubles up as the linked server data source. */ data_src = pstrdup(linked_server); } else { if (provider && (((strlen(provider) == 7) && (strncmp(provider, "sqlncli", 7) == 0)) || - ((strlen(provider) == 10) && (strncmp(provider, "msoledbsql", 10) == 0)) || - ((strlen(provider) == 8) && (strncmp(provider, "sqloledb", 8) == 0)))) + ((strlen(provider) == 10) && (strncmp(provider, "msoledbsql", 10) == 0)) || + ((strlen(provider) == 8) && (strncmp(provider, "sqloledb", 8) == 0)))) { - /* if provider is a valid T-SQL provider, we throw a warning indicating internally, we will be using tds_fdw */ + /* + * if provider is a valid T-SQL provider, we throw a warning + * indicating internally, we will be using tds_fdw + */ provider_warning = true; } else if (!provider || (strlen(provider) != 7) || (strncmp(provider, "tds_fdw", 7) != 0)) ereport(ERROR, - (errcode(ERRCODE_FDW_ERROR), - errmsg("Unsupported provider '%s'. Supported provider is 'tds_fdw'", provider))); + (errcode(ERRCODE_FDW_ERROR), + errmsg("Unsupported provider '%s'. Supported provider is 'tds_fdw'", provider))); if (provstr != NULL) { @@ -2190,11 +2307,11 @@ sp_addlinkedserver_internal(PG_FUNCTION_ARGS) initStringInfo(&query); /* - * We prepare the following query to create a foreign server. This will - * be executed using ProcessUtility(): + * We prepare the following query to create a foreign server. This will be + * executed using ProcessUtility(): * - * CREATE SERVER FOREIGN DATA WRAPPER tds_fdw OPTIONS (servername - * '', database '') + * CREATE SERVER FOREIGN DATA WRAPPER tds_fdw OPTIONS + * (servername '', database '') * */ appendStringInfo(&query, "CREATE SERVER \"%s\" FOREIGN DATA WRAPPER tds_fdw ", linked_server); @@ -2205,8 +2322,8 @@ sp_addlinkedserver_internal(PG_FUNCTION_ARGS) appendStringInfoString(&query, "OPTIONS ( "); /* - * The servername option is required for foreign server creation, - * but we leave it to the FDW's validator function to check for that + * The servername option is required for foreign server creation, but + * we leave it to the FDW's validator function to check for that */ if (data_src) appendStringInfo(&query, "servername '%s' ", data_src); @@ -2233,10 +2350,10 @@ sp_addlinkedserver_internal(PG_FUNCTION_ARGS) if (linked_server) pfree(linked_server); - + if (srv_product) pfree(srv_product); - + if (provider) pfree(provider); @@ -2245,7 +2362,7 @@ sp_addlinkedserver_internal(PG_FUNCTION_ARGS) if (provstr) pfree(provstr); - + if (catalog) pfree(catalog); @@ -2257,43 +2374,44 @@ sp_addlinkedserver_internal(PG_FUNCTION_ARGS) Datum sp_addlinkedsrvlogin_internal(PG_FUNCTION_ARGS) { - char *servername = PG_ARGISNULL(0) ? NULL : lowerstr(text_to_cstring(PG_GETARG_VARCHAR_PP(0))); - char *useself = PG_ARGISNULL(1) ? NULL : lowerstr(text_to_cstring(PG_GETARG_VARCHAR_PP(1))); - char *locallogin = PG_ARGISNULL(2) ? NULL : text_to_cstring(PG_GETARG_VARCHAR_PP(2)); - char *username = PG_ARGISNULL(3) ? NULL : text_to_cstring(PG_GETARG_VARCHAR_PP(3)); - char *password = PG_ARGISNULL(4) ? NULL : text_to_cstring(PG_GETARG_VARCHAR_PP(4)); + char *servername = PG_ARGISNULL(0) ? NULL : lowerstr(text_to_cstring(PG_GETARG_VARCHAR_PP(0))); + char *useself = PG_ARGISNULL(1) ? NULL : lowerstr(text_to_cstring(PG_GETARG_VARCHAR_PP(1))); + char *locallogin = PG_ARGISNULL(2) ? NULL : text_to_cstring(PG_GETARG_VARCHAR_PP(2)); + char *username = PG_ARGISNULL(3) ? NULL : text_to_cstring(PG_GETARG_VARCHAR_PP(3)); + char *password = PG_ARGISNULL(4) ? NULL : text_to_cstring(PG_GETARG_VARCHAR_PP(4)); StringInfoData query; - if(!pltsql_enable_linked_servers) + if (!pltsql_enable_linked_servers) ereport(ERROR, - (errcode(ERRCODE_FDW_ERROR), - errmsg("'sp_addlinkedsrvlogin' is not currently supported in Babelfish"))); + (errcode(ERRCODE_FDW_ERROR), + errmsg("'sp_addlinkedsrvlogin' is not currently supported in Babelfish"))); if (servername == NULL) ereport(ERROR, (errcode(ERRCODE_FDW_ERROR), - errmsg("@rmtsrvname parameter cannot be NULL"))); + errmsg("@rmtsrvname parameter cannot be NULL"))); /* We do not support login using user's self credentials */ if ((useself == NULL) || (strlen(useself) != 5) || (strncmp(useself, "false", 5) != 0)) ereport(ERROR, (errcode(ERRCODE_FDW_ERROR), - errmsg("Only @useself = FALSE is supported. Remote login using user's self credentials is not supported."))); + errmsg("Only @useself = FALSE is supported. Remote login using user's self credentials is not supported."))); if (locallogin != NULL) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Only @locallogin = NULL is supported. Configuring remote server access specific to local login is not yet supported"))); - + errmsg("Only @locallogin = NULL is supported. Configuring remote server access specific to local login is not yet supported"))); + initStringInfo(&query); /* - * We prepare the following query to create a user mapping. This will - * be executed using ProcessUtility(): + * We prepare the following query to create a user mapping. This will be + * executed using ProcessUtility(): * - * CREATE USER MAPPING FOR CURRENT_USER SERVER OPTIONS (username - * '', password '') + * CREATE USER MAPPING FOR CURRENT_USER SERVER OPTIONS + * (username '', password '') * */ appendStringInfo(&query, "CREATE USER MAPPING FOR CURRENT_USER SERVER \"%s\" ", servername); @@ -2302,8 +2420,8 @@ sp_addlinkedsrvlogin_internal(PG_FUNCTION_ARGS) * Add the relevant options * * The username and password options are required for user mapping - * creation, (according to tds_fdw documentation) but we leave it - * to the FDW's validator function to check for that + * creation, (according to tds_fdw documentation) but we leave it to the + * FDW's validator function to check for that */ if (username || password) { @@ -2345,26 +2463,26 @@ sp_addlinkedsrvlogin_internal(PG_FUNCTION_ARGS) Datum sp_droplinkedsrvlogin_internal(PG_FUNCTION_ARGS) { - char *servername = PG_ARGISNULL(0) ? NULL : lowerstr(text_to_cstring(PG_GETARG_VARCHAR_PP(0))); - char *locallogin = PG_ARGISNULL(1) ? NULL : text_to_cstring(PG_GETARG_VARCHAR_PP(1)); + char *servername = PG_ARGISNULL(0) ? NULL : lowerstr(text_to_cstring(PG_GETARG_VARCHAR_PP(0))); + char *locallogin = PG_ARGISNULL(1) ? NULL : text_to_cstring(PG_GETARG_VARCHAR_PP(1)); StringInfoData query; - if(!pltsql_enable_linked_servers) + if (!pltsql_enable_linked_servers) ereport(ERROR, - (errcode(ERRCODE_FDW_ERROR), - errmsg("'sp_droplinkedsrvlogin' is not currently supported in Babelfish"))); + (errcode(ERRCODE_FDW_ERROR), + errmsg("'sp_droplinkedsrvlogin' is not currently supported in Babelfish"))); if (servername == NULL) ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("@servername cannot be NULL"))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("@servername cannot be NULL"))); if (locallogin != NULL) ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Only @locallogin = NULL is supported. Configuring remote server access specific to local login is not yet supported"))); - + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Only @locallogin = NULL is supported. Configuring remote server access specific to local login is not yet supported"))); + initStringInfo(&query); /* @@ -2378,43 +2496,43 @@ sp_droplinkedsrvlogin_internal(PG_FUNCTION_ARGS) exec_utility_cmd_helper(query.data); - if(locallogin) + if (locallogin) pfree(locallogin); - - if(servername) + + if (servername) pfree(servername); - - return (Datum) 0; + + return (Datum) 0; } Datum sp_dropserver_internal(PG_FUNCTION_ARGS) { - char *linked_srv = PG_ARGISNULL(0) ? NULL : lowerstr(text_to_cstring(PG_GETARG_VARCHAR_PP(0))); - char *droplogins = PG_ARGISNULL(1) ? NULL : lowerstr(text_to_cstring(PG_GETARG_BPCHAR_PP(1))); + char *linked_srv = PG_ARGISNULL(0) ? NULL : lowerstr(text_to_cstring(PG_GETARG_VARCHAR_PP(0))); + char *droplogins = PG_ARGISNULL(1) ? NULL : lowerstr(text_to_cstring(PG_GETARG_BPCHAR_PP(1))); StringInfoData query; - if(!pltsql_enable_linked_servers) + if (!pltsql_enable_linked_servers) ereport(ERROR, - (errcode(ERRCODE_FDW_ERROR), - errmsg("'sp_dropserver' is not currently supported in Babelfish"))); + (errcode(ERRCODE_FDW_ERROR), + errmsg("'sp_dropserver' is not currently supported in Babelfish"))); if (linked_srv == NULL) ereport(ERROR, (errcode(ERRCODE_FDW_ERROR), - errmsg("@server parameter cannot be NULL"))); - + errmsg("@server parameter cannot be NULL"))); + initStringInfo(&query); /* - * We prepare the following query to drop foreign server. This will - * be executed using ProcessUtility(): + * We prepare the following query to drop foreign server. This will be + * executed using ProcessUtility(): * * DROP SERVER CASCADE * - * linked logins along with server are dropped if @droplogins = 'NULL' - * or @droplogins = 'droplogins' so we add CASCADE. + * linked logins along with server are dropped if @droplogins = 'NULL' or + * @droplogins = 'droplogins' so we add CASCADE. */ if ((droplogins == NULL) || ((strlen(droplogins) == 10) && (strncmp(droplogins, "droplogins", 10) == 0))) { @@ -2441,89 +2559,90 @@ sp_dropserver_internal(PG_FUNCTION_ARGS) pfree(droplogins); ereport(ERROR, - (errcode(ERRCODE_FDW_ERROR), - errmsg("Invalid parameter value for @droplogins specified in procedure 'sys.sp_dropserver', acceptable values are 'droplogins' or NULL."))); + (errcode(ERRCODE_FDW_ERROR), + errmsg("Invalid parameter value for @droplogins specified in procedure 'sys.sp_dropserver', acceptable values are 'droplogins' or NULL."))); } return (Datum) 0; } -Datum sp_babelfish_volatility(PG_FUNCTION_ARGS) +Datum +sp_babelfish_volatility(PG_FUNCTION_ARGS) { - int rc; - int i; - char *db_name = get_cur_db_name(); - char *function_signature = NULL; - char *query = NULL; - char *function_name = PG_ARGISNULL(0) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(0)); - char *volatility = PG_ARGISNULL(1) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(1)); - Oid function_id; - Oid user_id = GetUserId(); - - if(function_name != NULL) - { + int rc; + int i; + char *db_name = get_cur_db_name(); + char *function_signature = NULL; + char *query = NULL; + char *function_name = PG_ARGISNULL(0) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(0)); + char *volatility = PG_ARGISNULL(1) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(1)); + Oid function_id; + Oid user_id = GetUserId(); + + if (function_name != NULL) + { /* strip trailing whitespace */ remove_trailing_spaces(function_name); /* if function name is empty */ i = strlen(function_name); - if(i == 0) + if (i == 0) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("function name is not valid"))); - + errmsg("function name is not valid"))); + /* length should be restricted to 4000 */ if (i > 4000) ereport(ERROR, - (errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH), - errmsg("input value is too long for function name"))); + (errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH), + errmsg("input value is too long for function name"))); } - if(volatility != NULL) + if (volatility != NULL) { /* strip trailing whitespace */ remove_trailing_spaces(volatility); - + /* if volatility is empty */ i = strlen(volatility); - if(i == 0) + if (i == 0) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("volatility is not valid"))); + errmsg("volatility is not valid"))); /* its length is greater than 9 (len of immutable) */ if (i > 9) ereport(ERROR, - (errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH), - errmsg("input value is too long for volatility"))); + (errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH), + errmsg("input value is too long for volatility"))); } - if(function_name == NULL && volatility != NULL) + if (function_name == NULL && volatility != NULL) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("function name cannot be NULL"))); + errmsg("function name cannot be NULL"))); - if(function_name != NULL) - { - List *function_name_list; + if (function_name != NULL) + { + List *function_name_list; FuncCandidateList candidates = NULL; - char *full_function_name = NULL; - char *logical_schema_name = NULL; - char *physical_schema_name = NULL; - char **splited_object_name; + char *full_function_name = NULL; + char *logical_schema_name = NULL; + char *physical_schema_name = NULL; + char **splited_object_name; /* get physical schema name */ splited_object_name = split_object_name(function_name); - if(strcmp(splited_object_name[0], "") || strcmp(splited_object_name[1], "")) + if (strcmp(splited_object_name[0], "") || strcmp(splited_object_name[1], "")) ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("function \"%s\" is not a valid two part name", function_name))); - + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("function \"%s\" is not a valid two part name", function_name))); + pfree(function_name); logical_schema_name = splited_object_name[2]; function_name = splited_object_name[3]; - + /* downcase identifier */ - if(pltsql_case_insensitive_identifiers) + if (pltsql_case_insensitive_identifiers) { logical_schema_name = downcase_identifier(logical_schema_name, strlen(logical_schema_name), false, false); function_name = downcase_identifier(function_name, strlen(function_name), false, false); @@ -2541,123 +2660,126 @@ Datum sp_babelfish_volatility(PG_FUNCTION_ARGS) truncate_tsql_identifier(logical_schema_name); truncate_tsql_identifier(function_name); - if(!strcmp(function_name, "")) + if (!strcmp(function_name, "")) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("function name is not valid"))); + errmsg("function name is not valid"))); /* find the default schema for current user */ if (!strcmp(logical_schema_name, "")) - { + { const char *user = get_user_for_database(db_name); const char *guest_role_name = get_guest_role_name(db_name); - if(!user) + + if (!user) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("user does not exist"))); + errmsg("user does not exist"))); pfree(logical_schema_name); if ((guest_role_name && strcmp(user, guest_role_name) == 0)) - { + { physical_schema_name = pstrdup(get_guest_schema_name(db_name)); } else { logical_schema_name = get_authid_user_ext_schema_name((const char *) db_name, user); - physical_schema_name = get_physical_schema_name(db_name,logical_schema_name); + physical_schema_name = get_physical_schema_name(db_name, logical_schema_name); pfree(logical_schema_name); } } else { - physical_schema_name = get_physical_schema_name(db_name,logical_schema_name); + physical_schema_name = get_physical_schema_name(db_name, logical_schema_name); pfree(logical_schema_name); } - /* get function id from function name*/ - function_name_list = list_make2(makeString(physical_schema_name),makeString(function_name)); + /* get function id from function name */ + function_name_list = list_make2(makeString(physical_schema_name), makeString(function_name)); candidates = FuncnameGetCandidates(function_name_list, -1, NIL, false, false, false, true); /* if no function is found */ - if(candidates == NULL) + if (candidates == NULL) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("function does not exist"))); + errmsg("function does not exist"))); /* check if the current user has priviledge on the function */ - if(pg_proc_aclcheck(candidates->oid, user_id, ACL_EXECUTE) != ACLCHECK_OK) + if (pg_proc_aclcheck(candidates->oid, user_id, ACL_EXECUTE) != ACLCHECK_OK) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("current user does not have priviledges on the function"))); - + errmsg("current user does not have priviledges on the function"))); + /* check if multiple function with same function name exits */ - if(candidates->next != NULL) + if (candidates->next != NULL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("multiple functions with same function name exits"))); + errmsg("multiple functions with same function name exits"))); function_id = candidates->oid; full_function_name = psprintf("\"%s\".\"%s\"", physical_schema_name, function_name); - function_signature = (char *)get_pltsql_function_signature_internal(full_function_name, candidates->nargs, candidates->args); + function_signature = (char *) get_pltsql_function_signature_internal(full_function_name, candidates->nargs, candidates->args); list_free(function_name_list); pfree(candidates); pfree(full_function_name); pfree(physical_schema_name); } - + /* - * If both volatility and function name is not provided then it will return a list of functions present in current database. - * else if only volatility is not provided the it will return the volatility of the specified function. - * If both volatility and function name is provided it will set the function volatility to the specified volatility + * If both volatility and function name is not provided then it will + * return a list of functions present in current database. else if only + * volatility is not provided the it will return the volatility of the + * specified function. If both volatility and function name is provided it + * will set the function volatility to the specified volatility */ - if(volatility == NULL) - { - if(function_name == NULL) - { + if (volatility == NULL) + { + if (function_name == NULL) + { query = psprintf( - "SELECT t3.orig_name as SchemaName, t1.proname as FunctionName, " - "CASE " - "WHEN t1.provolatile = 'v' THEN 'volatile' " - "WHEN t1.provolatile = 's' THEN 'stable' " - "ELSE 'immutable' " - "END AS Volatility " - "from pg_proc t1 " - "JOIN pg_namespace t2 ON t1.pronamespace = t2.oid " - "JOIN sys.babelfish_namespace_ext t3 ON t3.nspname = t2.nspname " - "where has_function_privilege(t1.oid, CAST('EXECUTE' as text)) " - "AND t3.dbid = sys.db_id() AND prokind = 'f' " - "ORDER BY t3.orig_name, t1.proname" + "SELECT t3.orig_name as SchemaName, t1.proname as FunctionName, " + "CASE " + "WHEN t1.provolatile = 'v' THEN 'volatile' " + "WHEN t1.provolatile = 's' THEN 'stable' " + "ELSE 'immutable' " + "END AS Volatility " + "from pg_proc t1 " + "JOIN pg_namespace t2 ON t1.pronamespace = t2.oid " + "JOIN sys.babelfish_namespace_ext t3 ON t3.nspname = t2.nspname " + "where has_function_privilege(t1.oid, CAST('EXECUTE' as text)) " + "AND t3.dbid = sys.db_id() AND prokind = 'f' " + "ORDER BY t3.orig_name, t1.proname" ); } else { query = psprintf( - "SELECT t3.orig_name as SchemaName, CAST('%s' as sys.varchar) as FunctionName, " - "CASE " - "WHEN provolatile = 'v' THEN 'volatile' " - "WHEN provolatile = 's' THEN 'stable' " - "ELSE 'immutable' " - "END AS Volatility from pg_proc t1 " - "JOIN pg_namespace t2 ON t1.pronamespace = t2.oid " - "JOIN sys.babelfish_namespace_ext t3 ON t3.nspname = t2.nspname " - "where t1.oid = %u", function_name, function_id + "SELECT t3.orig_name as SchemaName, CAST('%s' as sys.varchar) as FunctionName, " + "CASE " + "WHEN provolatile = 'v' THEN 'volatile' " + "WHEN provolatile = 's' THEN 'stable' " + "ELSE 'immutable' " + "END AS Volatility from pg_proc t1 " + "JOIN pg_namespace t2 ON t1.pronamespace = t2.oid " + "JOIN sys.babelfish_namespace_ext t3 ON t3.nspname = t2.nspname " + "where t1.oid = %u", function_name, function_id ); } PG_TRY(); - { - char nulls = 0; + { + char nulls = 0; MemoryContext savedPortalCxt; - SPIPlanPtr plan; - Portal portal; + SPIPlanPtr plan; + Portal portal; DestReceiver *receiver; savedPortalCxt = PortalContext; if (PortalContext == NULL) PortalContext = MessageContext; if ((rc = SPI_connect()) != SPI_OK_CONNECT) - { + { PortalContext = savedPortalCxt; elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc)); } @@ -2670,10 +2792,12 @@ Datum sp_babelfish_volatility(PG_FUNCTION_ARGS) elog(ERROR, "SPI_cursor_open(\"%s\") failed", query); /* - * According to specifictation, sp_babelfish_volatility returns a result-set. - * If there is no destination, it will send the result-set to client, which is not allowed behavior of PG procedures. - * To implement this behavior, we added a code to push the result. - */ + * According to specifictation, sp_babelfish_volatility returns a + * result-set. If there is no destination, it will send the + * result-set to client, which is not allowed behavior of PG + * procedures. To implement this behavior, we added a code to push + * the result. + */ receiver = CreateDestReceiver(DestRemote); SetRemoteDestReceiverParams(receiver, portal); @@ -2691,17 +2815,17 @@ Datum sp_babelfish_volatility(PG_FUNCTION_ARGS) SPI_finish(); PG_RE_THROW(); } - PG_END_TRY(); + PG_END_TRY(); } else - { + { /* downcase identifier if needed */ volatility = downcase_identifier(volatility, strlen(volatility), false, false); - - if(strcmp(volatility, "volatile") && strcmp(volatility, "stable") && strcmp(volatility, "immutable")) + + if (strcmp(volatility, "volatile") && strcmp(volatility, "stable") && strcmp(volatility, "immutable")) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("\"%s\" is not a valid volatility", volatility))); + errmsg("\"%s\" is not a valid volatility", volatility))); query = psprintf("ALTER FUNCTION %s %s;", function_signature, volatility); @@ -2724,125 +2848,150 @@ Datum sp_babelfish_volatility(PG_FUNCTION_ARGS) PG_END_TRY(); } - if(function_name) + if (function_name) { pfree(function_name); pfree(function_signature); } - if(volatility) + if (volatility) pfree(volatility); - if(query) + if (query) pfree(query); pfree(db_name); - PG_RETURN_VOID(); + PG_RETURN_VOID(); } -Datum sp_rename_internal(PG_FUNCTION_ARGS) +Datum +sp_rename_internal(PG_FUNCTION_ARGS) { - char *obj_name, *new_name, *schema_name, *objtype, *process_util_querystr; - ObjectType objtype_code; - size_t len; - List *parsetree_list; - ListCell *parsetree_item; + char *obj_name, + *new_name, + *schema_name, + *objtype, + *process_util_querystr; + ObjectType objtype_code; + size_t len; + List *parsetree_list; + ListCell *parsetree_item; const char *saved_dialect = GetConfigOption("babelfish_tsql.sql_dialect", true, true); PG_TRY(); { - //1. set dialect to TSQL + /* 1. set dialect to TSQL */ set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); - - //2. read the input arguments + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + + /* 2. read the input arguments */ obj_name = PG_ARGISNULL(0) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(0)); new_name = PG_ARGISNULL(1) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(1)); schema_name = PG_ARGISNULL(2) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(2)); - objtype = PG_ARGISNULL(3) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(3)); + objtype = PG_ARGISNULL(3) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(3)); - //3. check if the input arguments are valid, and parse the objname - // objname can have at most 3 parts + /* 3. check if the input arguments are valid, and parse the objname */ + /* objname can have at most 3 parts */ if (obj_name == NULL) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("Procedure or function 'sp_rename' expects parameter '@objname', which was not supplied."))); + errmsg("Procedure or function 'sp_rename' expects parameter '@objname', which was not supplied."))); if (new_name == NULL) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("Procedure or function 'sp_rename' expects parameter '@newname', which was not supplied."))); + errmsg("Procedure or function 'sp_rename' expects parameter '@newname', which was not supplied."))); if (objtype == NULL) objtype = "OBJECT"; - // remove trailing whitespaces for both input + /* remove trailing whitespaces for both input */ len = strlen(obj_name); - while(isspace(obj_name[len - 1])) + while (isspace(obj_name[len - 1])) obj_name[--len] = 0; len = strlen(schema_name); - while(isspace(schema_name[len - 1])) + while (isspace(schema_name[len - 1])) schema_name[--len] = 0; len = strlen(new_name); - while(isspace(new_name[len - 1])) + while (isspace(new_name[len - 1])) new_name[--len] = 0; len = strlen(objtype); - while(isspace(objtype[len - 1])) + while (isspace(objtype[len - 1])) objtype[--len] = 0; - // check if inputs are empty after removing trailing spaces + /* check if inputs are empty after removing trailing spaces */ if (obj_name == NULL) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("Procedure or function 'sp_rename' expects parameter '@objname', which was not supplied."))); + errmsg("Procedure or function 'sp_rename' expects parameter '@objname', which was not supplied."))); if (new_name == NULL || strlen(new_name) == 0) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("Procedure or function 'sp_rename' expects parameter '@newname', which was not supplied."))); - - //4. for each obj type, generate the corresponding RenameStmt - // update variables based on the target objtype + errmsg("Procedure or function 'sp_rename' expects parameter '@newname', which was not supplied."))); + + /* 4. for each obj type, generate the corresponding RenameStmt */ + /* update variables based on the target objtype */ if (strcmp(objtype, "U") == 0 || strcmp(objtype, "IT") == 0 || strcmp(objtype, "S") == 0 || - strcmp(objtype, "ET") == 0) { + strcmp(objtype, "ET") == 0) + { objtype_code = OBJECT_TABLE; process_util_querystr = "(ALTER TABLE )"; - } else if (strcmp(objtype, "V") == 0) { + } + else if (strcmp(objtype, "V") == 0) + { objtype_code = OBJECT_VIEW; process_util_querystr = "(ALTER VIEW )"; - } else if (strcmp(objtype, "P") == 0 || strcmp(objtype, "PC") == 0 || strcmp(objtype, "RF") == 0 || - strcmp(objtype, "X") == 0) { + } + else if (strcmp(objtype, "P") == 0 || strcmp(objtype, "PC") == 0 || strcmp(objtype, "RF") == 0 || + strcmp(objtype, "X") == 0) + { objtype_code = OBJECT_PROCEDURE; process_util_querystr = "(ALTER PROCEDURE )"; - } else if (strcmp(objtype, "AF") == 0 || strcmp(objtype, "FN") == 0 || strcmp(objtype, "FS") == 0 || - strcmp(objtype, "FT") == 0 || strcmp(objtype, "IF") == 0 || strcmp(objtype, "TF") == 0) { + } + else if (strcmp(objtype, "AF") == 0 || strcmp(objtype, "FN") == 0 || strcmp(objtype, "FS") == 0 || + strcmp(objtype, "FT") == 0 || strcmp(objtype, "IF") == 0 || strcmp(objtype, "TF") == 0) + { objtype_code = OBJECT_FUNCTION; process_util_querystr = "(ALTER FUNCTION )"; - } else if (strcmp(objtype, "SO") == 0) { + } + else if (strcmp(objtype, "SO") == 0) + { objtype_code = OBJECT_SEQUENCE; process_util_querystr = "(ALTER SEQUENCE )"; - } else if (strcmp(objtype, "TA") == 0 || strcmp(objtype, "TR") == 0) { - // TRIGGER + } + else if (strcmp(objtype, "TA") == 0 || strcmp(objtype, "TR") == 0) + { + /* TRIGGER */ ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Feature not supported: renaming object type Trigger"))); - } else if (strcmp(objtype, "C") == 0 || strcmp(objtype, "D") == 0 || strcmp(objtype, "PK") == 0 || - strcmp(objtype, "UQ") == 0 || strcmp(objtype, "EC") == 0) { - // CONSTRAINT + errmsg("Feature not supported: renaming object type Trigger"))); + } + else if (strcmp(objtype, "C") == 0 || strcmp(objtype, "D") == 0 || strcmp(objtype, "PK") == 0 || + strcmp(objtype, "UQ") == 0 || strcmp(objtype, "EC") == 0) + { + /* CONSTRAINT */ ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Feature not supported: renaming object type Constraint"))); - } else if (strcmp(objtype, "TT") == 0) { - // TABLE TYPE + errmsg("Feature not supported: renaming object type Constraint"))); + } + else if (strcmp(objtype, "TT") == 0) + { + /* TABLE TYPE */ ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Feature not supported: renaming object type Table-Type"))); - } else { + errmsg("Feature not supported: renaming object type Table-Type"))); + } + else + { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Provided '@objtype' is currently not supported in Babelfish."))); + errmsg("Provided '@objtype' is currently not supported in Babelfish."))); } /* Advance cmd counter to make the delete visible */ CommandCounterIncrement(); - // parsetree_list = gen_sp_rename_subcmds(obj_name, new_name, schema_name, objtype); + /* + * parsetree_list = gen_sp_rename_subcmds(obj_name, new_name, + * schema_name, objtype); + */ parsetree_list = gen_sp_rename_subcmds(obj_name, new_name, schema_name, objtype_code); - //5. run all commands + /* 5. run all commands */ foreach(parsetree_item, parsetree_list) - { - Node *stmt = ((RawStmt *) lfirst(parsetree_item))->stmt; + { + Node *stmt = ((RawStmt *) lfirst(parsetree_item))->stmt; PlannedStmt *wrapper; - + /* need to make a wrapper PlannedStmt */ wrapper = makeNode(PlannedStmt); wrapper->commandType = CMD_UTILITY; @@ -2853,30 +3002,30 @@ Datum sp_rename_internal(PG_FUNCTION_ARGS) /* do this step */ ProcessUtility(wrapper, - pstrdup(process_util_querystr), - // "(ALTER TABLE )", - false, - PROCESS_UTILITY_SUBCOMMAND, - NULL, - NULL, - None_Receiver, - NULL); + pstrdup(process_util_querystr), + /* "(ALTER TABLE )", */ + false, + PROCESS_UTILITY_SUBCOMMAND, + NULL, + NULL, + None_Receiver, + NULL); /* make sure later steps can see the object created here */ CommandCounterIncrement(); - } + } } PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RE_THROW(); } PG_END_TRY(); set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + (superuser() ? PGC_SUSET : PGC_USERSET), + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_VOID(); } @@ -2884,32 +3033,43 @@ static List * gen_sp_rename_subcmds(const char *objname, const char *newname, const char *schemaname, ObjectType objtype) { StringInfoData query; - List *res; - Node *stmt; + List *res; + Node *stmt; RenameStmt *renamestmt; initStringInfo(&query); - if (objtype == OBJECT_TABLE) { + if (objtype == OBJECT_TABLE) + { appendStringInfo(&query, "ALTER TABLE dummy RENAME TO dummy; "); - } else if (objtype == OBJECT_VIEW) { + } + else if (objtype == OBJECT_VIEW) + { appendStringInfo(&query, "ALTER VIEW dummy RENAME TO dummy; "); - } else if (objtype == OBJECT_PROCEDURE) { + } + else if (objtype == OBJECT_PROCEDURE) + { appendStringInfo(&query, "ALTER PROCEDURE dummy RENAME TO dummy; "); - } else if (objtype == OBJECT_FUNCTION) { + } + else if (objtype == OBJECT_FUNCTION) + { appendStringInfo(&query, "ALTER FUNCTION dummy RENAME TO dummy; "); - } else if (objtype == OBJECT_SEQUENCE) { + } + else if (objtype == OBJECT_SEQUENCE) + { appendStringInfo(&query, "ALTER SEQUENCE dummy RENAME TO dummy; "); - } else { + } + else + { ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Provided objtype is not supported for sp_rename"))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Provided objtype is not supported for sp_rename"))); } res = raw_parser(query.data, RAW_PARSE_DEFAULT); if (list_length(res) != 1) ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("Expected 1 statement but get %d statements after parsing", list_length(res)))); + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Expected 1 statement but get %d statements after parsing", list_length(res)))); stmt = parsetree_nth_stmt(res, 0); @@ -2917,22 +3077,29 @@ gen_sp_rename_subcmds(const char *objname, const char *newname, const char *sche if (!IsA(renamestmt, RenameStmt)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("query is not a RenameStmt"))); - if ((objtype == OBJECT_TABLE) || (objtype == OBJECT_VIEW) || (objtype == OBJECT_SEQUENCE)) { + if ((objtype == OBJECT_TABLE) || (objtype == OBJECT_VIEW) || (objtype == OBJECT_SEQUENCE)) + { renamestmt->renameType = objtype; renamestmt->subname = pstrdup(lowerstr(objname)); renamestmt->newname = pstrdup(lowerstr(newname)); renamestmt->relation->schemaname = pstrdup(lowerstr(schemaname)); renamestmt->relation->relname = pstrdup(lowerstr(objname)); - } else { - // } else if ((objtype == OBJECT_PROCEDURE) || (objtype == OBJECT_FUNCTION)) { + } + else + { + /* + * } else if ((objtype == OBJECT_PROCEDURE) || (objtype == + * OBJECT_FUNCTION)) { + */ ObjectWithArgs *objwargs = (ObjectWithArgs *) renamestmt->object; + renamestmt->renameType = objtype; objwargs->objname = list_make2(makeString(pstrdup(lowerstr(schemaname))), makeString(pstrdup(lowerstr(objname)))); orig_proc_funcname = pstrdup(newname); renamestmt->subname = pstrdup(lowerstr(objname)); renamestmt->newname = pstrdup(lowerstr(newname)); } - //name mapping + /* name mapping */ rewrite_object_refs(stmt); return res; diff --git a/contrib/babelfishpg_tsql/src/properties.c b/contrib/babelfishpg_tsql/src/properties.c index 7217e67b96..33f111a376 100644 --- a/contrib/babelfishpg_tsql/src/properties.c +++ b/contrib/babelfishpg_tsql/src/properties.c @@ -60,44 +60,50 @@ extern bool pltsql_numeric_roundabort; extern bool pltsql_quoted_identifier; extern char *bbf_servername; -static void* get_servername_helper(void); +static void *get_servername_helper(void); static VarChar *get_product_version_helper(int idx); static VarChar *get_product_level_helper(); -Datum connectionproperty(PG_FUNCTION_ARGS) { +Datum +connectionproperty(PG_FUNCTION_ARGS) +{ const char *property = text_to_cstring(PG_GETARG_TEXT_P(0)); - VarChar *vch; + VarChar *vch; if (strcasecmp(property, "net_transport") == 0) { const char *ret = "TCP"; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); } else if (strcasecmp(property, "protocol_type") == 0) { const char *ret = "TSQL"; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); } else if (strcasecmp(property, "auth_scheme") == 0) { const char *ret = "SQL"; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); } else if (strcasecmp(property, "local_net_address") == 0) { const char *ret = ""; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); } else if (strcasecmp(property, "local_tcp_port") == 0) { - PG_RETURN_BYTEA_P((*common_utility_plugin_ptr->convertIntToSQLVariantByteA)(1433)); + PG_RETURN_BYTEA_P((*common_utility_plugin_ptr->convertIntToSQLVariantByteA) (1433)); } else if (strcasecmp(property, "client_net_address") == 0) { - Port *port = MyProcPort; + Port *port = MyProcPort; char remote_host[NI_MAXHOST]; - const char *ret; - int rc; + const char *ret; + int rc; if (port == NULL) PG_RETURN_NULL(); @@ -125,12 +131,13 @@ Datum connectionproperty(PG_FUNCTION_ARGS) { clean_ipv6_addr(port->raddr.addr.ss_family, remote_host); ret = remote_host; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); } else if (strcasecmp(property, "physical_net_transport") == 0) { const char *ret = "TCP"; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); } else { @@ -138,44 +145,45 @@ Datum connectionproperty(PG_FUNCTION_ARGS) { PG_RETURN_NULL(); } - PG_RETURN_BYTEA_P((*common_utility_plugin_ptr->convertVarcharToSQLVariantByteA)(vch, PG_GET_COLLATION())); + PG_RETURN_BYTEA_P((*common_utility_plugin_ptr->convertVarcharToSQLVariantByteA) (vch, PG_GET_COLLATION())); } -void* get_servername_helper() +void * +get_servername_helper() { StringInfoData temp; - void* info; + void *info; - initStringInfo(&temp); - appendStringInfoString(&temp, bbf_servername); + initStringInfo(&temp); + appendStringInfoString(&temp, bbf_servername); - info = (*common_utility_plugin_ptr->tsql_varchar_input)(temp.data, temp.len, -1); - pfree(temp.data); - return info; + info = (*common_utility_plugin_ptr->tsql_varchar_input) (temp.data, temp.len, -1); + pfree(temp.data); + return info; } static char * -get_version_number(const char* version_string, int idx) +get_version_number(const char *version_string, int idx) { - int part = 0, - len = 0; - char *token; - char *copy_version_number; + int part = 0, + len = 0; + char *token; + char *copy_version_number; Assert(version_string != NULL); - if(idx == -1) - return (char *)version_string; + if (idx == -1) + return (char *) version_string; len = strlen(version_string); copy_version_number = palloc0(len + 1); memcpy(copy_version_number, version_string, len); for (token = strtok(copy_version_number, "."); token; token = strtok(NULL, ".")) - { - if(part == idx) + { + if (part == idx) return token; part++; } - + /* part should less than 3 */ Assert(part <= 2); return ""; @@ -184,91 +192,96 @@ get_version_number(const char* version_string, int idx) static VarChar * get_product_version_helper(int idx) { - StringInfoData temp; - void *info; - const char *product_version; + StringInfoData temp; + void *info; + const char *product_version; product_version = GetConfigOption("babelfishpg_tds.product_version", true, false); Assert(product_version != NULL); Assert(idx == -1 || idx == 0 || idx == 1); initStringInfo(&temp); - if(pg_strcasecmp(product_version,"default") == 0) + if (pg_strcasecmp(product_version, "default") == 0) { - appendStringInfoString(&temp, get_version_number(BABEL_COMPATIBILITY_VERSION,idx)); + appendStringInfoString(&temp, get_version_number(BABEL_COMPATIBILITY_VERSION, idx)); } else { - appendStringInfoString(&temp, get_version_number(product_version,idx)); + appendStringInfoString(&temp, get_version_number(product_version, idx)); } - - info = (*common_utility_plugin_ptr->tsql_varchar_input)(temp.data, temp.len, -1); - pfree(temp.data); - return (VarChar *)info; + + info = (*common_utility_plugin_ptr->tsql_varchar_input) (temp.data, temp.len, -1); + pfree(temp.data); + return (VarChar *) info; } static VarChar * get_product_level_helper() { - StringInfoData temp; - void *info; - int minor_version; - char* product_level_RTM = "RTM"; - char* product_level_prefix = "SP"; - + StringInfoData temp; + void *info; + int minor_version; + char *product_level_RTM = "RTM"; + char *product_level_prefix = "SP"; + initStringInfo(&temp); - + Assert(BABELFISH_VERSION_STR != NULL); - minor_version = atoi(get_version_number(BABELFISH_VERSION_STR,1)); - if(minor_version == 0) + minor_version = atoi(get_version_number(BABELFISH_VERSION_STR, 1)); + if (minor_version == 0) { appendStringInfoString(&temp, product_level_RTM); } else { appendStringInfoString(&temp, product_level_prefix); - appendStringInfoString(&temp, get_version_number(BABELFISH_VERSION_STR,1)); + appendStringInfoString(&temp, get_version_number(BABELFISH_VERSION_STR, 1)); appendStringInfoString(&temp, "."); - appendStringInfoString(&temp, get_version_number(BABELFISH_VERSION_STR,2)); + appendStringInfoString(&temp, get_version_number(BABELFISH_VERSION_STR, 2)); } - info = (*common_utility_plugin_ptr->tsql_varchar_input)(temp.data, temp.len, -1); + info = (*common_utility_plugin_ptr->tsql_varchar_input) (temp.data, temp.len, -1); pfree(temp.data); - return (VarChar *)info; + return (VarChar *) info; } -Datum serverproperty(PG_FUNCTION_ARGS) { +Datum +serverproperty(PG_FUNCTION_ARGS) +{ const char *property = text_to_cstring(PG_GETARG_TEXT_P(0)); - VarChar *vch = NULL; - int64_t intVal = 0; + VarChar *vch = NULL; + int64_t intVal = 0; if (strcasecmp(property, "BuildClrVersion") == 0) { const char *ret = ""; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); TSQLInstrumentation(INSTR_TSQL_SERVERPROPERTY_BUILDCLRVERSION); } - else if (strcasecmp(property, "Collation") == 0) - { + else if (strcasecmp(property, "Collation") == 0) + { const char *server_collation_name = GetConfigOption("babelfishpg_tsql.server_collation_name", false, false); + if (server_collation_name) - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(server_collation_name, strlen(server_collation_name), -1); + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (server_collation_name, strlen(server_collation_name), -1); } else if (strcasecmp(property, "CollationID") == 0) { - HeapTuple tuple; - char *collation_name; - Oid collation_oid; - List *list; - Oid dboid = get_database_oid("template1", true); + HeapTuple tuple; + char *collation_name; + Oid collation_oid; + List *list; + Oid dboid = get_database_oid("template1", true); + tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(dboid)); TSQLInstrumentation(INSTR_TSQL_SERVERPROPERTY_COLLATIONID); if (HeapTupleIsValid(tuple)) { - char datlocprovider; - Datum datum; - bool isnull; + char datlocprovider; + Datum datum; + bool isnull; datlocprovider = ((Form_pg_database) GETSTRUCT(tuple))->datlocprovider; datum = SysCacheGetAttr(DATABASEOID, tuple, datlocprovider == COLLPROVIDER_ICU ? Anum_pg_database_daticulocale : Anum_pg_database_datcollate, &isnull); @@ -277,7 +290,7 @@ Datum serverproperty(PG_FUNCTION_ARGS) { ReleaseSysCache(tuple); list = list_make1(makeString(collation_name)); collation_oid = get_collation_oid(list, true); - intVal = (int64_t)collation_oid; + intVal = (int64_t) collation_oid; } } else if (strcasecmp(property, "ComparisonStyle") == 0) @@ -288,26 +301,22 @@ Datum serverproperty(PG_FUNCTION_ARGS) { else if (strcasecmp(property, "ComputerNamePhysicalNetBIOS") == 0) { const char *ret = ""; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_COMPUTERNAME_PHYSICAL_NETBIOS); } else if (strcasecmp(property, "Edition") == 0) { /* - Edition can be one of the following: - 'Enterprise Edition' - 'Enterprise Edition: Core-based Licensing' - 'Enterprise Evaluation Edition' - 'Business Intelligence Edition' - 'Developer Edition' - 'Express Edition' - 'Express Edition with Advanced Services' - 'Standard Edition' - 'Web Edition' - 'SQL Azure' - */ + * Edition can be one of the following: 'Enterprise Edition' + * 'Enterprise Edition: Core-based Licensing' 'Enterprise Evaluation + * Edition' 'Business Intelligence Edition' 'Developer Edition' + * 'Express Edition' 'Express Edition with Advanced Services' + * 'Standard Edition' 'Web Edition' 'SQL Azure' + */ const char *ret = "Standard Edition"; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); TSQLInstrumentation(INSTR_TSQL_SERVERPROPERTY_EDITION); } else if (strcasecmp(property, "EditionID") == 0) @@ -331,26 +340,29 @@ Datum serverproperty(PG_FUNCTION_ARGS) { else if (strcasecmp(property, "InstanceDefaultDataPath") == 0) { const char *ret = ""; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_INSTANCE_DEFAULT_PATH); } else if (strcasecmp(property, "InstanceDefaultLogPath") == 0) { const char *ret = ""; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_INSTANCE_DEFAULT_LOG_PATH); } else if (strcasecmp(property, "InstanceName") == 0) { const char *ret = ""; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_INSTANCE_NAME); } - else if (strcasecmp(property, "IsAdvancedAnalyticsInstalled") == 0) - { + else if (strcasecmp(property, "IsAdvancedAnalyticsInstalled") == 0) + { intVal = 0; - TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_IS_ADVANCED_ANALYTICS_INSTALLED); - } + TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_IS_ADVANCED_ANALYTICS_INSTALLED); + } else if (strcasecmp(property, "IsBigDataCluster") == 0) { intVal = 0; @@ -389,32 +401,37 @@ Datum serverproperty(PG_FUNCTION_ARGS) { else if (strcasecmp(property, "IsSingleUser") == 0) { TSQLInstrumentation(INSTR_TSQL_SERVERPROPERTY_IS_SINGLE_USER); - if (IsUnderPostmaster) // not single-user mode + if (IsUnderPostmaster) + /* not single - user mode */ intVal = 0; - else // is single-user mode + else + /* is single - user mode */ intVal = 1; } else if (strcasecmp(property, "IsXTPSupported") == 0) { intVal = 0; - TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_IS_XTP_SUPPORTED); + TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_IS_XTP_SUPPORTED); } else if (strcasecmp(property, "LCID") == 0) { const char *ret = ""; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_LCID); } else if (strcasecmp(property, "LicenseType") == 0) { const char *ret = "DISABLED"; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_SERVERPROPERTY_LICENSE_TYPE); } else if (strcasecmp(property, "MachineName") == 0) { const char *ret = ""; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); } else if (strcasecmp(property, "NumLicenses") == 0) { @@ -427,12 +444,14 @@ Datum serverproperty(PG_FUNCTION_ARGS) { else if (strcasecmp(property, "ProductBuild") == 0) { const char *ret = ""; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); } else if (strcasecmp(property, "ProductBuildType") == 0) { const char *ret = ""; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); } else if (strcasecmp(property, "ProductLevel") == 0) { @@ -449,12 +468,14 @@ Datum serverproperty(PG_FUNCTION_ARGS) { else if (strcasecmp(property, "ProductUpdateLevel") == 0) { const char *ret = ""; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); } else if (strcasecmp(property, "ProductUpdateReference") == 0) { const char *ret = ""; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); } else if (strcasecmp(property, "ProductVersion") == 0) { @@ -463,16 +484,17 @@ Datum serverproperty(PG_FUNCTION_ARGS) { else if (strcasecmp(property, "ResourceLastUpdateDateTime") == 0) { /* We need a valid date in here */ - const char* date = "2021-01-01 00:00:00-08"; - Datum data = (*common_utility_plugin_ptr->datetime_in_str)((char*)date); - /* - bytea *result = gen_sqlvariant_bytea_from_type_datum(DATETIME_T, data); - svhdr_1B_t *svhdr; + const char *date = "2021-01-01 00:00:00-08"; + Datum data = (*common_utility_plugin_ptr->datetime_in_str) ((char *) date); - TSQLInstrumentation(INSTR_TSQL_DATETIME_SQLVARIANT); - svhdr = SV_HDR_1B(result); - SV_SET_METADATA(svhdr, DATETIME_T, HDR_VER); - */ + /* + * bytea *result = + * gen_sqlvariant_bytea_from_type_datum(DATETIME_T, data); svhdr_1B_t + * *svhdr; + * + * TSQLInstrumentation(INSTR_TSQL_DATETIME_SQLVARIANT); svhdr = + * SV_HDR_1B(result); SV_SET_METADATA(svhdr, DATETIME_T, HDR_VER); + */ Datum result = DirectFunctionCall1(common_utility_plugin_ptr->datetime2sqlvariant, data); @@ -481,24 +503,27 @@ Datum serverproperty(PG_FUNCTION_ARGS) { else if (strcasecmp(property, "ResourceVersion") == 0) { const char *ret = ""; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); } else if (strcasecmp(property, "ServerName") == 0) { - vch = (VarChar*) get_servername_helper(); + vch = (VarChar *) get_servername_helper(); } else if (strcasecmp(property, "SqlCharSet") == 0 || strcasecmp(property, "SqlSortOrder") == 0) { - Datum data = Int8GetDatum(0); - /* - bytea *result = gen_sqlvariant_bytea_from_type_datum(TINYINT_T, data); - svhdr_1B_t *svhdr; - - TSQLInstrumentation(INSTR_TSQL_TINYINT_SQLVARIANT); + Datum data = Int8GetDatum(0); - svhdr = SV_HDR_1B(result); - SV_SET_METADATA(svhdr, TINYINT_T, HDR_VER); - */ + /* + * bytea *result = + * gen_sqlvariant_bytea_from_type_datum(TINYINT_T, data); svhdr_1B_t + * *svhdr; + * + * TSQLInstrumentation(INSTR_TSQL_TINYINT_SQLVARIANT); + * + * svhdr = SV_HDR_1B(result); SV_SET_METADATA(svhdr, TINYINT_T, + * HDR_VER); + */ Datum result = DirectFunctionCall1(common_utility_plugin_ptr->tinyint2sqlvariant, data); @@ -507,17 +532,20 @@ Datum serverproperty(PG_FUNCTION_ARGS) { else if (strcasecmp(property, "SqlCharSetName") == 0) { const char *ret = ""; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); } else if (strcasecmp(property, "SqlSortOrderName") == 0) { const char *ret = ""; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); } else if (strcasecmp(property, "FilestreamShareName") == 0) { const char *ret = ""; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); } else if (strcasecmp(property, "FilestreamConfiguredLevel") == 0) { @@ -527,63 +555,72 @@ Datum serverproperty(PG_FUNCTION_ARGS) { { intVal = 0; } - else if (strcasecmp(property, "babelfish") == 0) - { - intVal = 1; - } + else if (strcasecmp(property, "babelfish") == 0) + { + intVal = 1; + } else if (strcasecmp(property, "BabelfishVersion") == 0) { - const char *ret = BABELFISH_VERSION_STR; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + const char *ret = BABELFISH_VERSION_STR; + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); } - else if (strcasecmp(property, "BabelfishInternalVersion") == 0) - { - const char *ret; - StringInfoData babelInternalVersion; + else if (strcasecmp(property, "BabelfishInternalVersion") == 0) + { + const char *ret; + StringInfoData babelInternalVersion; - initStringInfo(&babelInternalVersion); - appendStringInfoString(&babelInternalVersion, BABELFISH_INTERNAL_VERSION_STR); + initStringInfo(&babelInternalVersion); + appendStringInfoString(&babelInternalVersion, BABELFISH_INTERNAL_VERSION_STR); - ret = babelInternalVersion.data; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); - } + ret = babelInternalVersion.data; + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); + } else { const char *ret = ""; - vch = (*common_utility_plugin_ptr->tsql_varchar_input)(ret, strlen(ret), -1); + + vch = (*common_utility_plugin_ptr->tsql_varchar_input) (ret, strlen(ret), -1); } - if (vch != NULL) { - PG_RETURN_BYTEA_P((*common_utility_plugin_ptr->convertVarcharToSQLVariantByteA)(vch, PG_GET_COLLATION())); - } else { - PG_RETURN_BYTEA_P((*common_utility_plugin_ptr->convertIntToSQLVariantByteA)(intVal)); + if (vch != NULL) + { + PG_RETURN_BYTEA_P((*common_utility_plugin_ptr->convertVarcharToSQLVariantByteA) (vch, PG_GET_COLLATION())); + } + else + { + PG_RETURN_BYTEA_P((*common_utility_plugin_ptr->convertIntToSQLVariantByteA) (intVal)); } } -Datum sessionproperty(PG_FUNCTION_ARGS) { +Datum +sessionproperty(PG_FUNCTION_ARGS) +{ const char *property = text_to_cstring(PG_GETARG_TEXT_P(0)); - int64_t intVal = 0; + int64_t intVal = 0; if (strcasecmp(property, "ANSI_NULLS") == 0) intVal = (int) pltsql_ansi_nulls; - else if (strcasecmp(property, "ANSI_PADDING") == 0) + else if (strcasecmp(property, "ANSI_PADDING") == 0) intVal = (int) pltsql_ansi_padding; - else if (strcasecmp(property, "ANSI_WARNINGS") == 0) + else if (strcasecmp(property, "ANSI_WARNINGS") == 0) intVal = (int) pltsql_ansi_warnings; - else if (strcasecmp(property, "ARITHABORT") == 0) + else if (strcasecmp(property, "ARITHABORT") == 0) intVal = (int) pltsql_arithabort; - else if (strcasecmp(property, "CONCAT_NULL_YIELDS_NULL") == 0) + else if (strcasecmp(property, "CONCAT_NULL_YIELDS_NULL") == 0) intVal = (int) pltsql_concat_null_yields_null; - else if (strcasecmp(property, "NUMERIC_ROUNDABORT") == 0) + else if (strcasecmp(property, "NUMERIC_ROUNDABORT") == 0) intVal = (int) pltsql_numeric_roundabort; - else if (strcasecmp(property, "QUOTED_IDENTIFIER") == 0) + else if (strcasecmp(property, "QUOTED_IDENTIFIER") == 0) intVal = (int) pltsql_quoted_identifier; - else - PG_RETURN_NULL(); + else + PG_RETURN_NULL(); - PG_RETURN_BYTEA_P((*common_utility_plugin_ptr->convertIntToSQLVariantByteA)(intVal)); + PG_RETURN_BYTEA_P((*common_utility_plugin_ptr->convertIntToSQLVariantByteA) (intVal)); } -Datum fulltextserviceproperty(PG_FUNCTION_ARGS) { +Datum +fulltextserviceproperty(PG_FUNCTION_ARGS) +{ PG_RETURN_INT32(0); } diff --git a/contrib/babelfishpg_tsql/src/rolecmds.c b/contrib/babelfishpg_tsql/src/rolecmds.c index 068c75d297..6b31bfb51d 100644 --- a/contrib/babelfishpg_tsql/src/rolecmds.c +++ b/contrib/babelfishpg_tsql/src/rolecmds.c @@ -60,20 +60,20 @@ #include static void drop_bbf_authid_login_ext(ObjectAccessType access, - Oid classId, - Oid roleid, - int subId, - void *arg); + Oid classId, + Oid roleid, + int subId, + void *arg); static void drop_bbf_authid_user_ext(ObjectAccessType access, - Oid classId, - Oid roleid, - int subId, - void *arg); + Oid classId, + Oid roleid, + int subId, + void *arg); static void drop_bbf_authid_user_ext_by_rolname(const char *rolname); static void grant_guests_to_login(const char *login); static bool has_user_in_db(const char *login, char **db_name); -static void validateNetBIOS(char* netbios); -static void validateFQDN(char* fqdn); +static void validateNetBIOS(char *netbios); +static void validateFQDN(char *fqdn); void create_bbf_authid_login_ext(CreateRoleStmt *stmt) @@ -84,10 +84,10 @@ create_bbf_authid_login_ext(CreateRoleStmt *stmt) Datum new_record_login_ext[BBF_AUTHID_LOGIN_EXT_NUM_COLS]; bool new_record_nulls_login_ext[BBF_AUTHID_LOGIN_EXT_NUM_COLS]; Oid roleid; - ListCell *option; - char *default_database = NULL; - char *orig_loginname = NULL; - bool from_windows = false; + ListCell *option; + char *default_database = NULL; + char *orig_loginname = NULL; + bool from_windows = false; /* Extract options from the statement node tree */ foreach(option, stmt->options) @@ -112,7 +112,7 @@ create_bbf_authid_login_ext(CreateRoleStmt *stmt) } } - if(!orig_loginname) + if (!orig_loginname) orig_loginname = stmt->role; if (!default_database) @@ -144,8 +144,8 @@ create_bbf_authid_login_ext(CreateRoleStmt *stmt) else new_record_login_ext[LOGIN_EXT_TYPE] = CStringGetTextDatum("S"); - new_record_login_ext[LOGIN_EXT_CREDENTIAL_ID] = Int32GetDatum(-1); /* placeholder */ - new_record_login_ext[LOGIN_EXT_OWNING_PRINCIPAL_ID] = Int32GetDatum(-1); /* placeholder */ + new_record_login_ext[LOGIN_EXT_CREDENTIAL_ID] = Int32GetDatum(-1); /* placeholder */ + new_record_login_ext[LOGIN_EXT_OWNING_PRINCIPAL_ID] = Int32GetDatum(-1); /* placeholder */ new_record_login_ext[LOGIN_EXT_IS_FIXED_ROLE] = Int32GetDatum(0); new_record_login_ext[LOGIN_EXT_CREATE_DATE] = TimestampTzGetDatum(GetSQLCurrentTimestamp(-1)); new_record_login_ext[LOGIN_EXT_MODIFY_DATE] = TimestampTzGetDatum(GetSQLCurrentTimestamp(-1)); @@ -175,19 +175,19 @@ create_bbf_authid_login_ext(CreateRoleStmt *stmt) void alter_bbf_authid_login_ext(AlterRoleStmt *stmt) { - Relation bbf_authid_login_ext_rel; - TupleDesc bbf_authid_login_ext_dsc; - HeapTuple new_tuple; - HeapTuple tuple; - HeapTuple auth_tuple; - Datum new_record_login_ext[BBF_AUTHID_LOGIN_EXT_NUM_COLS]; - bool new_record_nulls_login_ext[BBF_AUTHID_LOGIN_EXT_NUM_COLS]; - bool new_record_repl_login_ext[BBF_AUTHID_LOGIN_EXT_NUM_COLS]; - ScanKeyData scanKey; - SysScanDesc scan; - Form_pg_authid authform; - ListCell *option; - char *default_database = NULL; + Relation bbf_authid_login_ext_rel; + TupleDesc bbf_authid_login_ext_dsc; + HeapTuple new_tuple; + HeapTuple tuple; + HeapTuple auth_tuple; + Datum new_record_login_ext[BBF_AUTHID_LOGIN_EXT_NUM_COLS]; + bool new_record_nulls_login_ext[BBF_AUTHID_LOGIN_EXT_NUM_COLS]; + bool new_record_repl_login_ext[BBF_AUTHID_LOGIN_EXT_NUM_COLS]; + ScanKeyData scanKey; + SysScanDesc scan; + Form_pg_authid authform; + ListCell *option; + char *default_database = NULL; if (sql_dialect != SQL_DIALECT_TSQL) return; @@ -221,7 +221,7 @@ alter_bbf_authid_login_ext(AlterRoleStmt *stmt) /* Advance the command counter to see the new record */ CommandCounterIncrement(); - /* Search and obtain the tuple on the role name*/ + /* Search and obtain the tuple on the role name */ ScanKeyInit(&scanKey, Anum_bbf_authid_login_ext_rolname, BTEqualStrategyNumber, F_NAMEEQ, @@ -276,10 +276,10 @@ alter_bbf_authid_login_ext(AlterRoleStmt *stmt) void drop_bbf_roles(ObjectAccessType access, - Oid classId, - Oid roleid, - int subId, - void *arg) + Oid classId, + Oid roleid, + int subId, + void *arg) { if (is_login(roleid)) drop_bbf_authid_login_ext(access, classId, roleid, subId, arg); @@ -289,10 +289,10 @@ drop_bbf_roles(ObjectAccessType access, static void drop_bbf_authid_login_ext(ObjectAccessType access, - Oid classId, - Oid roleid, - int subId, - void *arg) + Oid classId, + Oid roleid, + int subId, + void *arg) { Relation bbf_authid_login_ext_rel; Relation bbf_authid_user_ext_rel; @@ -304,9 +304,9 @@ drop_bbf_authid_login_ext(ObjectAccessType access, Datum new_record_user_ext[BBF_AUTHID_USER_EXT_NUM_COLS]; bool new_record_nulls_user_ext[BBF_AUTHID_USER_EXT_NUM_COLS]; bool new_record_repl_user_ext[BBF_AUTHID_USER_EXT_NUM_COLS]; - ScanKeyData scanKey; - SysScanDesc scan; - TableScanDesc tblscan; + ScanKeyData scanKey; + SysScanDesc scan; + TableScanDesc tblscan; NameData rolname; NameData *invalidated_login_name; @@ -316,7 +316,7 @@ drop_bbf_authid_login_ext(ObjectAccessType access, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("role with OID %u does not exist", roleid))); rolname = ((Form_pg_authid) GETSTRUCT(authtuple))->rolname; - + /* Fetch the relation */ bbf_authid_login_ext_rel = table_open(get_authid_login_ext_oid(), RowExclusiveLock); @@ -349,7 +349,7 @@ drop_bbf_authid_login_ext(ObjectAccessType access, RowExclusiveLock); bbf_authid_user_ext_dsc = RelationGetDescr(bbf_authid_user_ext_rel); - /* Search and obtain the tuple on the login name*/ + /* Search and obtain the tuple on the login name */ ScanKeyInit(&scanKey, Anum_bbf_authid_user_ext_login_name, BTEqualStrategyNumber, F_NAMEEQ, @@ -366,7 +366,8 @@ drop_bbf_authid_login_ext(ObjectAccessType access, while (HeapTupleIsValid(usertuple)) { /* - * Insert empty string as login_name as an invalidation mark for this login + * Insert empty string as login_name as an invalidation mark for this + * login */ invalidated_login_name = (NameData *) palloc0(NAMEDATALEN); snprintf(invalidated_login_name->data, NAMEDATALEN, "%s", ""); @@ -395,16 +396,16 @@ drop_bbf_authid_login_ext(ObjectAccessType access, static void drop_bbf_authid_user_ext(ObjectAccessType access, - Oid classId, - Oid roleid, - int subId, - void *arg) + Oid classId, + Oid roleid, + int subId, + void *arg) { Relation bbf_authid_user_ext_rel; HeapTuple tuple; HeapTuple authtuple; - ScanKeyData scanKey; - SysScanDesc scan; + ScanKeyData scanKey; + SysScanDesc scan; NameData rolname; authtuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid)); @@ -444,8 +445,8 @@ drop_bbf_authid_user_ext_by_rolname(const char *rolname) { Relation bbf_authid_user_ext_rel; HeapTuple tuple; - ScanKeyData scanKey; - SysScanDesc scan; + ScanKeyData scanKey; + SysScanDesc scan; /* Fetch the relation */ bbf_authid_user_ext_rel = table_open(get_authid_user_ext_oid(), @@ -474,11 +475,11 @@ drop_bbf_authid_user_ext_by_rolname(const char *rolname) void drop_related_bbf_users(List *db_users) { - ListCell *elem; + ListCell *elem; - foreach (elem, db_users) + foreach(elem, db_users) { - char *user_name = (char *) lfirst(elem); + char *user_name = (char *) lfirst(elem); drop_bbf_authid_user_ext_by_rolname(user_name); } @@ -487,16 +488,16 @@ drop_related_bbf_users(List *db_users) static void grant_guests_to_login(const char *login) { - Relation db_rel; - TableScanDesc scan; - HeapTuple tuple; - bool is_null; - StringInfoData query; - List *parsetree_list; - List *guests = NIL; - Node *stmt; - RoleSpec *tmp; - PlannedStmt *wrapper; + Relation db_rel; + TableScanDesc scan; + HeapTuple tuple; + bool is_null; + StringInfoData query; + List *parsetree_list; + List *guests = NIL; + Node *stmt; + RoleSpec *tmp; + PlannedStmt *wrapper; initStringInfo(&query); db_rel = table_open(sysdatabases_oid, AccessShareLock); @@ -505,15 +506,15 @@ grant_guests_to_login(const char *login) while (HeapTupleIsValid(tuple)) { - Datum db_name_datum = heap_getattr(tuple, - Anum_sysdatabaese_name, - db_rel->rd_att, - &is_null); + Datum db_name_datum = heap_getattr(tuple, + Anum_sysdatabaese_name, + db_rel->rd_att, + &is_null); const char *db_name = TextDatumGetCString(db_name_datum); const char *guest_name = NULL; AccessPriv *tmp = makeNode(AccessPriv); - + if (guest_role_exists_for_db(db_name)) guest_name = get_guest_role_name(db_name); @@ -538,8 +539,8 @@ grant_guests_to_login(const char *login) parsetree_list = raw_parser(query.data, RAW_PARSE_DEFAULT); if (list_length(parsetree_list) != 1) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), errmsg("Expected 1 statement but get %d statements after parsing", list_length(parsetree_list)))); @@ -581,8 +582,8 @@ static List * gen_droplogin_subcmds(const char *login) { StringInfoData query; - List *res; - Node *stmt; + List *res; + Node *stmt; initStringInfo(&query); @@ -608,7 +609,7 @@ gen_droplogin_subcmds(const char *login) bool role_is_sa(Oid role) { - HeapTuple tuple; + HeapTuple tuple; Oid dba; tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(MyDatabaseId)); @@ -638,8 +639,8 @@ PG_FUNCTION_INFO_V1(initialize_logins); Datum initialize_logins(PG_FUNCTION_ARGS) { - char *login = text_to_cstring(PG_GETARG_TEXT_PP(0)); - CreateRoleStmt *stmt = makeNode(CreateRoleStmt); + char *login = text_to_cstring(PG_GETARG_TEXT_PP(0)); + CreateRoleStmt *stmt = makeNode(CreateRoleStmt); stmt->stmt_type = ROLESTMT_USER; stmt->role = login; @@ -652,16 +653,16 @@ PG_FUNCTION_INFO_V1(user_name); Datum user_name(PG_FUNCTION_ARGS) { - Oid id; - Relation bbf_authid_user_ext_rel; - HeapTuple tuple; - ScanKeyData scanKey; - SysScanDesc scan; - char *physical_user; - NameData *physical_user_name; - char *user; - Datum datum; - bool is_null; + Oid id; + Relation bbf_authid_user_ext_rel; + HeapTuple tuple; + ScanKeyData scanKey; + SysScanDesc scan; + char *physical_user; + NameData *physical_user_name; + char *user; + Datum datum; + bool is_null; id = PG_ARGISNULL(0) ? InvalidOid : PG_GETARG_OID(0); @@ -675,7 +676,7 @@ user_name(PG_FUNCTION_ARGS) bbf_authid_user_ext_rel = table_open(get_authid_user_ext_oid(), RowExclusiveLock); - /* Search and obtain the tuple on the role name*/ + /* Search and obtain the tuple on the role name */ physical_user_name = (NameData *) palloc0(NAMEDATALEN); snprintf(physical_user_name->data, NAMEDATALEN, "%s", physical_user); ScanKeyInit(&scanKey, @@ -689,7 +690,7 @@ user_name(PG_FUNCTION_ARGS) tuple = systable_getnext(scan); if (!HeapTupleIsValid(tuple)) - { + { systable_endscan(scan); table_close(bbf_authid_user_ext_rel, RowExclusiveLock); PG_RETURN_NULL(); @@ -711,12 +712,12 @@ PG_FUNCTION_INFO_V1(user_id); Datum user_id(PG_FUNCTION_ARGS) { - char *user_input; - char *user_name; - char *db_name; - HeapTuple auth_tuple; - Form_pg_authid authform; - Oid ret; + char *user_input; + char *user_name; + char *db_name; + HeapTuple auth_tuple; + Form_pg_authid authform; + Oid ret; user_input = PG_ARGISNULL(0) ? NULL : text_to_cstring(PG_GETARG_TEXT_PP(0)); db_name = get_cur_db_name(); @@ -733,8 +734,9 @@ user_id(PG_FUNCTION_ARGS) PG_RETURN_NULL(); if (pltsql_case_insensitive_identifiers) - // Lowercase the entry, if needed - for (char *p = user_name ; *p; ++p) *p = tolower(*p); + /* Lowercase the entry, if needed */ + for (char *p = user_name; *p; ++p) + *p = tolower(*p); auth_tuple = SearchSysCache1(AUTHNAME, CStringGetDatum(user_name)); if (!HeapTupleIsValid(auth_tuple)) @@ -756,8 +758,8 @@ static char * get_original_login_name(char *login) { Relation relation; - ScanKeyData scanKey; - SysScanDesc scan; + ScanKeyData scanKey; + SysScanDesc scan; HeapTuple tuple; bool isnull; Datum datum; @@ -798,9 +800,9 @@ PG_FUNCTION_INFO_V1(suser_name); Datum suser_name(PG_FUNCTION_ARGS) { - Oid server_user_id; - char *ret; - char *orig_loginname; + Oid server_user_id; + char *ret; + char *orig_loginname; server_user_id = PG_ARGISNULL(0) ? InvalidOid : PG_GETARG_OID(0); @@ -831,10 +833,10 @@ PG_FUNCTION_INFO_V1(suser_id); Datum suser_id(PG_FUNCTION_ARGS) { - char *login; - HeapTuple auth_tuple; - Form_pg_authid authform; - Oid ret; + char *login; + HeapTuple auth_tuple; + Form_pg_authid authform; + Oid ret; login = PG_ARGISNULL(0) ? NULL : text_to_cstring(PG_GETARG_TEXT_PP(0)); @@ -843,17 +845,18 @@ suser_id(PG_FUNCTION_ARGS) else { /* Strip trailing whitespace to mimic SQL Server behaviour */ - int i; + int i; + i = strlen(login); while (i > 0 && isspace((unsigned char) login[i - 1])) login[--i] = '\0'; - + /* Convert login to lower-case */ for (i = 0; login[i]; i++) { login[i] = tolower(login[i]); } - + /* Check if it is a role and get the oid */ auth_tuple = SearchSysCache1(AUTHNAME, CStringGetDatum(login)); if (!HeapTupleIsValid(auth_tuple)) @@ -872,24 +875,25 @@ suser_id(PG_FUNCTION_ARGS) } PG_FUNCTION_INFO_V1(drop_all_logins); -Datum drop_all_logins(PG_FUNCTION_ARGS) +Datum +drop_all_logins(PG_FUNCTION_ARGS) { Relation bbf_authid_login_ext_rel; HeapTuple tuple; - SysScanDesc scan; - char* rolname; - List *rolname_list = NIL; - const char *prev_current_user; - List *parsetree_list; - ListCell *parsetree_item; - int saved_dialect = sql_dialect; - + SysScanDesc scan; + char *rolname; + List *rolname_list = NIL; + const char *prev_current_user; + List *parsetree_list; + ListCell *parsetree_item; + int saved_dialect = sql_dialect; + /* Only allow superuser or SA to drop all logins. */ if (!superuser() && !role_is_sa(GetUserId())) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("user %s not allowed to drop all logins in babelfish database %s", - GetUserNameFromId(GetUserId(), true), get_database_name(MyDatabaseId)))); + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("user %s not allowed to drop all logins in babelfish database %s", + GetUserNameFromId(GetUserId(), true), get_database_name(MyDatabaseId)))); /* Fetch the relation */ bbf_authid_login_ext_rel = table_open(get_authid_login_ext_oid(), @@ -897,10 +901,13 @@ Datum drop_all_logins(PG_FUNCTION_ARGS) scan = systable_beginscan(bbf_authid_login_ext_rel, 0, false, NULL, 0, NULL); /* Get all the login names beforehand. */ - while (HeapTupleIsValid(tuple = systable_getnext(scan))) { - Form_authid_login_ext loginform = (Form_authid_login_ext) GETSTRUCT(tuple); + while (HeapTupleIsValid(tuple = systable_getnext(scan))) + { + Form_authid_login_ext loginform = (Form_authid_login_ext) GETSTRUCT(tuple); + rolname = NameStr(loginform->rolname); - /* + + /* * Remove SA from authid_login_ext now but do not add it to the list * because we don't want to remove the corresponding PG role. */ @@ -919,8 +926,10 @@ Datum drop_all_logins(PG_FUNCTION_ARGS) sql_dialect = SQL_DIALECT_TSQL; - while (rolname_list != NIL) { - char *rolname = linitial(rolname_list); + while (rolname_list != NIL) + { + char *rolname = linitial(rolname_list); + rolname_list = list_delete_first(rolname_list); PG_TRY(); @@ -979,15 +988,15 @@ add_to_bbf_authid_user_ext(const char *user_name, const char *db_name, const char *schema_name, const char *login_name, - bool is_role, + bool is_role, bool has_dbaccess, bool from_windows) { - Relation bbf_authid_user_ext_rel; - TupleDesc bbf_authid_user_ext_dsc; - HeapTuple tuple_user_ext; - Datum new_record_user_ext[BBF_AUTHID_USER_EXT_NUM_COLS]; - bool new_record_nulls_user_ext[BBF_AUTHID_USER_EXT_NUM_COLS]; + Relation bbf_authid_user_ext_rel; + TupleDesc bbf_authid_user_ext_dsc; + HeapTuple tuple_user_ext; + Datum new_record_user_ext[BBF_AUTHID_USER_EXT_NUM_COLS]; + bool new_record_nulls_user_ext[BBF_AUTHID_USER_EXT_NUM_COLS]; if (!user_name || !orig_user_name) ereport(ERROR, @@ -1009,16 +1018,16 @@ add_to_bbf_authid_user_ext(const char *user_name, else new_record_user_ext[USER_EXT_LOGIN_NAME] = CStringGetDatum(""); if (is_role) - new_record_user_ext[USER_EXT_TYPE] = CStringGetTextDatum("R"); + new_record_user_ext[USER_EXT_TYPE] = CStringGetTextDatum("R"); else if (from_windows) new_record_user_ext[USER_EXT_TYPE] = CStringGetTextDatum("U"); else new_record_user_ext[USER_EXT_TYPE] = CStringGetTextDatum("S"); - new_record_user_ext[USER_EXT_OWNING_PRINCIPAL_ID] = Int32GetDatum(-1); /* placeholder */ - new_record_user_ext[USER_EXT_IS_FIXED_ROLE] = Int32GetDatum(-1); /* placeholder */ - new_record_user_ext[USER_EXT_AUTHENTICATION_TYPE] = Int32GetDatum(-1); /* placeholder */ - new_record_user_ext[USER_EXT_DEFAULT_LANGUAGE_LCID] = Int32GetDatum(-1); /* placeholder */ - new_record_user_ext[USER_EXT_ALLOW_ENCRYPTED_VALUE_MODIFICATIONS] = Int32GetDatum(-1); /* placeholder */ + new_record_user_ext[USER_EXT_OWNING_PRINCIPAL_ID] = Int32GetDatum(-1); /* placeholder */ + new_record_user_ext[USER_EXT_IS_FIXED_ROLE] = Int32GetDatum(-1); /* placeholder */ + new_record_user_ext[USER_EXT_AUTHENTICATION_TYPE] = Int32GetDatum(-1); /* placeholder */ + new_record_user_ext[USER_EXT_DEFAULT_LANGUAGE_LCID] = Int32GetDatum(-1); /* placeholder */ + new_record_user_ext[USER_EXT_ALLOW_ENCRYPTED_VALUE_MODIFICATIONS] = Int32GetDatum(-1); /* placeholder */ new_record_user_ext[USER_EXT_CREATE_DATE] = TimestampTzGetDatum(GetSQLCurrentTimestamp(-1)); new_record_user_ext[USER_EXT_MODIFY_DATE] = TimestampTzGetDatum(GetSQLCurrentTimestamp(-1)); new_record_user_ext[USER_EXT_ORIG_USERNAME] = CStringGetTextDatum(pstrdup(orig_user_name)); @@ -1031,7 +1040,7 @@ add_to_bbf_authid_user_ext(const char *user_name, else new_record_user_ext[USER_EXT_DEFAULT_SCHEMA_NAME] = CStringGetTextDatum(""); new_record_user_ext[USER_EXT_DEFAULT_LANGUAGE_NAME] = CStringGetTextDatum("English"); - new_record_user_ext[USER_EXT_AUTHENTICATION_TYPE_DESC] = CStringGetTextDatum(""); /* placeholder */ + new_record_user_ext[USER_EXT_AUTHENTICATION_TYPE_DESC] = CStringGetTextDatum(""); /* placeholder */ if (has_dbaccess) new_record_user_ext[USER_EXT_USER_CAN_CONNECT] = Int32GetDatum(1); else @@ -1054,12 +1063,12 @@ add_to_bbf_authid_user_ext(const char *user_name, void create_bbf_authid_user_ext(CreateRoleStmt *stmt, bool has_schema, bool has_login, bool from_windows) { - ListCell *option; - char *default_schema = NULL; - char *original_user_name = NULL; - RoleSpec *login = NULL; - NameData *login_name; - char *login_name_str = NULL; + ListCell *option; + char *default_schema = NULL; + char *original_user_name = NULL; + RoleSpec *login = NULL; + NameData *login_name; + char *login_name_str = NULL; /* Extract options from the statement node tree */ foreach(option, stmt->options) @@ -1079,7 +1088,7 @@ create_bbf_authid_user_ext(CreateRoleStmt *stmt, bool has_schema, bool has_login /* Extract login info if the stmt is CREATE USER */ else if (has_login && strcmp(defel->defname, "rolemembers") == 0) { - List *rolemembers = NIL; + List *rolemembers = NIL; rolemembers = (List *) defel->arg; login = (RoleSpec *) linitial(rolemembers); @@ -1091,11 +1100,11 @@ create_bbf_authid_user_ext(CreateRoleStmt *stmt, bool has_schema, bool has_login if (has_login) { - Relation bbf_authid_user_ext_rel; - HeapTuple tuple_user_ext; - ScanKeyData key[2]; - TableScanDesc scan; - const char *cur_db_owner; + Relation bbf_authid_user_ext_rel; + HeapTuple tuple_user_ext; + ScanKeyData key[2]; + TableScanDesc scan; + const char *cur_db_owner; if (login == NULL || !is_login_name(login->rolename)) ereport(ERROR, @@ -1130,7 +1139,7 @@ create_bbf_authid_user_ext(CreateRoleStmt *stmt, bool has_schema, bool has_login table_close(bbf_authid_user_ext_rel, RowExclusiveLock); login_name_str = login->rolename; - cur_db_owner = get_owner_of_db((const char *)get_cur_db_name()); + cur_db_owner = get_owner_of_db((const char *) get_cur_db_name()); if (strcmp(login_name_str, cur_db_owner) == 0) ereport(ERROR, @@ -1147,17 +1156,17 @@ PG_FUNCTION_INFO_V1(add_existing_users_to_catalog); Datum add_existing_users_to_catalog(PG_FUNCTION_ARGS) { - Relation db_rel; - TableScanDesc scan; - HeapTuple tuple; - bool is_null; - List *dbo_list = NIL; - StringInfoData query; - List *parsetree_list; - Node *stmt; - PlannedStmt *wrapper; - const char *prev_current_user; - int saved_dialect = sql_dialect; + Relation db_rel; + TableScanDesc scan; + HeapTuple tuple; + bool is_null; + List *dbo_list = NIL; + StringInfoData query; + List *parsetree_list; + Node *stmt; + PlannedStmt *wrapper; + const char *prev_current_user; + int saved_dialect = sql_dialect; db_rel = table_open(sysdatabases_oid, AccessShareLock); scan = table_beginscan_catalog(db_rel, 0, NULL); @@ -1165,17 +1174,17 @@ add_existing_users_to_catalog(PG_FUNCTION_ARGS) while (HeapTupleIsValid(tuple)) { - Datum db_name_datum; - const char *db_name; - const char *dbo_role; - const char *db_owner_role; - const char *guest; - RoleSpec *rolspec; + Datum db_name_datum; + const char *db_name; + const char *dbo_role; + const char *db_owner_role; + const char *guest; + RoleSpec *rolspec; db_name_datum = heap_getattr(tuple, - Anum_sysdatabaese_name, - db_rel->rd_att, - &is_null); + Anum_sysdatabaese_name, + db_rel->rd_att, + &is_null); db_name = TextDatumGetCString(db_name_datum); dbo_role = get_dbo_role_name(db_name); @@ -1196,7 +1205,10 @@ add_existing_users_to_catalog(PG_FUNCTION_ARGS) add_to_bbf_authid_user_ext(db_owner_role, "db_owner", db_name, NULL, NULL, true, true, false); if (guest) { - /* For master, tempdb and msdb databases, the guest user will be enabled by default */ + /* + * For master, tempdb and msdb databases, the guest user will be + * enabled by default + */ if (strcmp(db_name, "master") == 0 || strcmp(db_name, "tempdb") == 0 || strcmp(db_name, "msdb") == 0) add_to_bbf_authid_user_ext(guest, "guest", db_name, NULL, NULL, false, true, false); else @@ -1220,7 +1232,8 @@ add_existing_users_to_catalog(PG_FUNCTION_ARGS) while (dbo_list != NIL) { - RoleSpec *rolspec = (RoleSpec *) linitial(dbo_list); + RoleSpec *rolspec = (RoleSpec *) linitial(dbo_list); + dbo_list = list_delete_first(dbo_list); PG_TRY(); @@ -1234,7 +1247,7 @@ add_existing_users_to_catalog(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("Expected 1 statement after parsing, but got %d statements", - list_length(parsetree_list)))); + list_length(parsetree_list)))); stmt = parsetree_nth_stmt(parsetree_list, 0); @@ -1282,20 +1295,20 @@ add_existing_users_to_catalog(PG_FUNCTION_ARGS) void alter_bbf_authid_user_ext(AlterRoleStmt *stmt) { - Relation bbf_authid_user_ext_rel; - TupleDesc bbf_authid_user_ext_dsc; - HeapTuple new_tuple; - HeapTuple tuple; - Datum new_record_user_ext[BBF_AUTHID_USER_EXT_NUM_COLS]; - bool new_record_nulls_user_ext[BBF_AUTHID_USER_EXT_NUM_COLS]; - bool new_record_repl_user_ext[BBF_AUTHID_USER_EXT_NUM_COLS]; - ScanKeyData scanKey; - SysScanDesc scan; - ListCell *option; - NameData *user_name; - char *default_schema = NULL; - char *new_user_name = NULL; - char *physical_name = NULL; + Relation bbf_authid_user_ext_rel; + TupleDesc bbf_authid_user_ext_dsc; + HeapTuple new_tuple; + HeapTuple tuple; + Datum new_record_user_ext[BBF_AUTHID_USER_EXT_NUM_COLS]; + bool new_record_nulls_user_ext[BBF_AUTHID_USER_EXT_NUM_COLS]; + bool new_record_repl_user_ext[BBF_AUTHID_USER_EXT_NUM_COLS]; + ScanKeyData scanKey; + SysScanDesc scan; + ListCell *option; + NameData *user_name; + char *default_schema = NULL; + char *new_user_name = NULL; + char *physical_name = NULL; if (sql_dialect != SQL_DIALECT_TSQL) return; @@ -1322,7 +1335,7 @@ alter_bbf_authid_user_ext(AlterRoleStmt *stmt) RowExclusiveLock); bbf_authid_user_ext_dsc = RelationGetDescr(bbf_authid_user_ext_rel); - /* Search and obtain the tuple on the role name*/ + /* Search and obtain the tuple on the role name */ user_name = (NameData *) palloc0(NAMEDATALEN); snprintf(user_name->data, NAMEDATALEN, "%s", stmt->role->rolename); ScanKeyInit(&scanKey, @@ -1391,10 +1404,10 @@ alter_bbf_authid_user_ext(AlterRoleStmt *stmt) if (new_user_name) { - StringInfoData query; - List *parsetree_list; - Node *n; - PlannedStmt *wrapper; + StringInfoData query; + List *parsetree_list; + Node *n; + PlannedStmt *wrapper; initStringInfo(&query); appendStringInfo(&query, "ALTER ROLE dummy RENAME TO dummy; "); @@ -1436,17 +1449,18 @@ alter_bbf_authid_user_ext(AlterRoleStmt *stmt) } PG_FUNCTION_INFO_V1(drop_all_users); -Datum drop_all_users(PG_FUNCTION_ARGS) +Datum +drop_all_users(PG_FUNCTION_ARGS) { /* - * This function has been deprecated since v2.1. - * However, we cannot remove this function entirely because, - * in PG13, sys.babel_drop_all_users() procedure refers it. - * Without this function, MVU from PG13 to PG14 will fail. + * This function has been deprecated since v2.1. However, we cannot remove + * this function entirely because, in PG13, sys.babel_drop_all_users() + * procedure refers it. Without this function, MVU from PG13 to PG14 will + * fail. * - * Removing the procedure sys.babel_drop_all_users() during pg_dump - * cannot be an option because other user-defined procedures - * are able to refer this function as well. + * Removing the procedure sys.babel_drop_all_users() during pg_dump cannot + * be an option because other user-defined procedures are able to refer + * this function as well. */ ereport(WARNING, (errcode(ERRCODE_WARNING_DEPRECATED_FEATURE), @@ -1458,7 +1472,7 @@ PG_FUNCTION_INFO_V1(babelfish_set_role); Datum babelfish_set_role(PG_FUNCTION_ARGS) { - char *role = text_to_cstring(PG_GETARG_TEXT_PP(0)); + char *role = text_to_cstring(PG_GETARG_TEXT_PP(0)); bbf_set_current_user(role); @@ -1468,14 +1482,17 @@ babelfish_set_role(PG_FUNCTION_ARGS) bool is_alter_server_stmt(GrantRoleStmt *stmt) { - /* is alter server role statement, - * if one and the only one granted role is server role + /* + * is alter server role statement, if one and the only one granted role is + * server role */ if (list_length(stmt->granted_roles) == 1) { - RoleSpec *spec = (RoleSpec *) linitial(stmt->granted_roles); - if (strcmp(spec->rolename, "sysadmin") != 0) /* only supported server role */ + RoleSpec *spec = (RoleSpec *) linitial(stmt->granted_roles); + + if (strcmp(spec->rolename, "sysadmin") != 0) /* only supported server + * role */ return false; } /* has one and only one grantee */ @@ -1488,16 +1505,16 @@ is_alter_server_stmt(GrantRoleStmt *stmt) void check_alter_server_stmt(GrantRoleStmt *stmt) { - Oid grantee; - char *grantee_name; - const char *granted_name; - RoleSpec *spec; - AccessPriv *granted; - CatCList *memlist; - Oid sysadmin; - char *db_name; - - spec = (RoleSpec *) linitial(stmt->grantee_roles); + Oid grantee; + char *grantee_name; + const char *granted_name; + RoleSpec *spec; + AccessPriv *granted; + CatCList *memlist; + Oid sysadmin; + char *db_name; + + spec = (RoleSpec *) linitial(stmt->grantee_roles); sysadmin = get_role_oid("sysadmin", false); granted = (AccessPriv *) linitial(stmt->granted_roles); @@ -1513,9 +1530,9 @@ check_alter_server_stmt(GrantRoleStmt *stmt) spec->rolename = grantee_name; } - grantee = get_role_oid(grantee_name, false); /* missing not OK */ + grantee = get_role_oid(grantee_name, false); /* missing not OK */ - if(!is_login(grantee)) + if (!is_login(grantee)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("%s is not a login", grantee_name))); @@ -1525,22 +1542,25 @@ check_alter_server_stmt(GrantRoleStmt *stmt) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("Current login %s does not have permission to alter server role", - GetUserNameFromId(GetSessionUserId(), true)))); + GetUserNameFromId(GetSessionUserId(), true)))); - /* sysadmin role is not granted if grantee login has a user in one of the databases, as Babelfish only supports one dbo currently*/ + /* + * sysadmin role is not granted if grantee login has a user in one of the + * databases, as Babelfish only supports one dbo currently + */ if (stmt->is_grant && (strcmp(granted_name, "sysadmin") == 0) && has_user_in_db(grantee_name, &db_name)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("'sysadmin' role cannot be granted to login: a user is already created in database '%s'", db_name))); + errmsg("'sysadmin' role cannot be granted to login: a user is already created in database '%s'", db_name))); /* could not drop the last member of sysadmin */ memlist = SearchSysCacheList1(AUTHMEMROLEMEM, - ObjectIdGetDatum(sysadmin)); + ObjectIdGetDatum(sysadmin)); if (memlist->n_members == 1) { - HeapTuple tup = &memlist->members[0]->tuple; - Oid member = ((Form_pg_auth_members) GETSTRUCT(tup))->member; + HeapTuple tup = &memlist->members[0]->tuple; + Oid member = ((Form_pg_auth_members) GETSTRUCT(tup))->member; if (member == grantee) { @@ -1557,16 +1577,16 @@ bool is_alter_role_stmt(GrantRoleStmt *stmt) { /* - * The statement is ALTER ROLE if - * 1. There is only one grantee role - * 2. There is only one granted role and it's an existing babelfish db role + * The statement is ALTER ROLE if 1. There is only one grantee role 2. + * There is only one granted role and it's an existing babelfish db role */ if (list_length(stmt->granted_roles) != 1 || list_length(stmt->grantee_roles) != 1) return false; else { - RoleSpec *spec = (RoleSpec *) linitial(stmt->granted_roles); - Oid granted = get_role_oid(spec->rolename, true); + RoleSpec *spec = (RoleSpec *) linitial(stmt->granted_roles); + Oid granted = get_role_oid(spec->rolename, true); + /* Check if the granted role is an existing database role */ if (granted == InvalidOid || !is_role(granted)) return false; @@ -1578,15 +1598,15 @@ is_alter_role_stmt(GrantRoleStmt *stmt) void check_alter_role_stmt(GrantRoleStmt *stmt) { - Oid granted; - Oid grantee; - const char *granted_name; - const char *grantee_name; - RoleSpec *granted_spec; - RoleSpec *grantee_spec; + Oid granted; + Oid grantee; + const char *granted_name; + const char *grantee_name; + RoleSpec *granted_spec; + RoleSpec *grantee_spec; /* The grantee must be a db user or a user-defined db role */ - grantee_spec = (RoleSpec *) linitial(stmt->grantee_roles); + grantee_spec = (RoleSpec *) linitial(stmt->grantee_roles); grantee_name = grantee_spec->rolename; grantee = get_role_oid(grantee_name, false); @@ -1603,15 +1623,15 @@ check_alter_role_stmt(GrantRoleStmt *stmt) granted = get_role_oid(granted_name, false); /* - * Disallow ALTER ROLE if - * 1. Current login doesn't have permission on the granted role, or - * 2. The current user is trying to add/drop itself from the granted role + * Disallow ALTER ROLE if 1. Current login doesn't have permission on the + * granted role, or 2. The current user is trying to add/drop itself from + * the granted role */ if (!has_privs_of_role(GetSessionUserId(), granted) || grantee == GetUserId()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("Current login %s does not have permission to alter role %s", + errmsg("Current login %s does not have permission to alter role %s", GetUserNameFromId(GetSessionUserId(), true), granted_name))); } @@ -1622,7 +1642,7 @@ check_alter_role_stmt(GrantRoleStmt *stmt) bool is_empty_role(Oid roleid) { - CatCList *memlist; + CatCList *memlist; if (roleid == InvalidOid) return true; @@ -1634,7 +1654,7 @@ is_empty_role(Oid roleid) { HeapTuple tup = &memlist->members[0]->tuple; Oid member = ((Form_pg_auth_members) GETSTRUCT(tup))->member; - char *db_name = get_cur_db_name(); + char *db_name = get_cur_db_name(); if (db_name == NULL || strcmp(db_name, "") == 0) return true; @@ -1655,14 +1675,14 @@ PG_FUNCTION_INFO_V1(role_id); Datum role_id(PG_FUNCTION_ARGS) { - char *user_input; - char *role_name; - Oid result; + char *user_input; + char *role_name; + Oid result; user_input = text_to_cstring(PG_GETARG_TEXT_PP(0)); if (0 != strncmp(user_input, "db_owner", 8)) - PG_RETURN_NULL(); /* don't have other roles */ + PG_RETURN_NULL(); /* don't have other roles */ if (!get_cur_db_name()) PG_RETURN_NULL(); @@ -1684,20 +1704,20 @@ PG_FUNCTION_INFO_V1(is_rolemember); Datum is_rolemember(PG_FUNCTION_ARGS) { - Oid role_oid; - Oid principal_oid; - Oid cur_user_oid = GetUserId(); - Oid db_owner_oid; - Oid dbo_role_oid; - char *role; - char *dc_role; - char *dc_principal = NULL; - char *physical_role_name; - char *physical_principal_name; - char *cur_db_name; - const char *db_owner_name; - const char *dbo_role_name; - int idx; + Oid role_oid; + Oid principal_oid; + Oid cur_user_oid = GetUserId(); + Oid db_owner_oid; + Oid dbo_role_oid; + char *role; + char *dc_role; + char *dc_principal = NULL; + char *physical_role_name; + char *physical_principal_name; + char *cur_db_name; + const char *db_owner_name; + const char *dbo_role_name; + int idx; if (PG_ARGISNULL(0)) PG_RETURN_NULL(); @@ -1717,7 +1737,8 @@ is_rolemember(PG_FUNCTION_ARGS) else { /* Do principal name mapping */ - char *principal = text_to_cstring(PG_GETARG_TEXT_P(1)); + char *principal = text_to_cstring(PG_GETARG_TEXT_P(1)); + idx = strlen(principal); while (idx > 0 && isspace((unsigned char) principal[idx - 1])) principal[--idx] = '\0'; @@ -1727,7 +1748,7 @@ is_rolemember(PG_FUNCTION_ARGS) } /* Return 1 if given role is PUBLIC */ - if (strcmp(dc_role, "public") == 0 && + if (strcmp(dc_role, "public") == 0 && (principal_oid != InvalidOid || strcmp(dc_principal, "public") == 0)) PG_RETURN_INT32(1); @@ -1739,11 +1760,11 @@ is_rolemember(PG_FUNCTION_ARGS) if (role_oid == principal_oid) PG_RETURN_INT32(1); - /* - * Return NULL if given role is not a real role, or if current user doesn't - * directly/indirectly have privilges over the given role and principal. - * Note that if given principal is current user, we'll always have - * permissions. + /* + * Return NULL if given role is not a real role, or if current user + * doesn't directly/indirectly have privilges over the given role and + * principal. Note that if given principal is current user, we'll always + * have permissions. */ if (!is_role(role_oid) || (principal_oid != cur_user_oid && @@ -1751,7 +1772,7 @@ is_rolemember(PG_FUNCTION_ARGS) !has_privs_of_role(cur_user_oid, principal_oid)))) PG_RETURN_NULL(); - /* + /* * Recursively check if the given principal is a member of the role, not * considering superuserness */ @@ -1762,11 +1783,10 @@ is_rolemember(PG_FUNCTION_ARGS) dbo_role_oid = get_role_oid(dbo_role_name, false); if ((principal_oid == db_owner_oid) || (principal_oid == dbo_role_oid)) PG_RETURN_INT32(0); - else - if (is_member_of_role_nosuper(principal_oid, role_oid)) - PG_RETURN_INT32(1); - else - PG_RETURN_INT32(0); + else if (is_member_of_role_nosuper(principal_oid, role_oid)) + PG_RETURN_INT32(1); + else + PG_RETURN_INT32(0); } /* @@ -1776,7 +1796,7 @@ bool is_active_login(Oid role_oid) { if (CountUserBackends(role_oid) == 0) - return false; /* If there are no backends with given role */ + return false; /* If there are no backends with given role */ return true; } @@ -1787,38 +1807,38 @@ is_active_login(Oid role_oid) static bool has_user_in_db(const char *login, char **db_name) { - Relation bbf_authid_user_ext_rel; - HeapTuple tuple_user_ext; - ScanKeyData key[3]; - TableScanDesc scan; - NameData *login_name; - bool is_null; - - // open the table to scane + Relation bbf_authid_user_ext_rel; + HeapTuple tuple_user_ext; + ScanKeyData key[3]; + TableScanDesc scan; + NameData *login_name; + bool is_null; + + /* open the table to scane */ bbf_authid_user_ext_rel = table_open(get_authid_user_ext_oid(), RowExclusiveLock); - // change the target name to NameData for search + /* change the target name to NameData for search */ login_name = (NameData *) palloc0(NAMEDATALEN); snprintf(login_name->data, NAMEDATALEN, "%s", login); - // operate scanning + /* operate scanning */ ScanKeyInit(&key[0], Anum_bbf_authid_user_ext_login_name, BTEqualStrategyNumber, F_NAMEEQ, NameGetDatum(login_name)); scan = table_beginscan_catalog(bbf_authid_user_ext_rel, 1, key); - // match stored, if there is a match + /* match stored, if there is a match */ tuple_user_ext = heap_getnext(scan, ForwardScanDirection); if (HeapTupleIsValid(tuple_user_ext)) { - Datum name = heap_getattr(tuple_user_ext, Anum_bbf_authid_user_ext_database_name, - bbf_authid_user_ext_rel->rd_att, &is_null); + Datum name = heap_getattr(tuple_user_ext, Anum_bbf_authid_user_ext_database_name, + bbf_authid_user_ext_rel->rd_att, &is_null); *db_name = pstrdup(TextDatumGetCString(name)); - + table_endscan(scan); table_close(bbf_authid_user_ext_rel, RowExclusiveLock); return true; @@ -1828,6 +1848,7 @@ has_user_in_db(const char *login, char **db_name) return false; } + /* * get_fully_qualified_domain_name - Returns fully qualified domain name corresponding to * supplied netbios_domain by looking into sys.babelfish_domain_mapping catalog. @@ -1841,10 +1862,10 @@ get_fully_qualified_domain_name(char *netbios_domain) /* TODO: Add test cases for this mapping */ Relation bbf_domain_mapping_rel; TupleDesc dsc; - ScanKeyData scanKey; - SysScanDesc scan; + ScanKeyData scanKey; + SysScanDesc scan; HeapTuple tuple; - char *fq_domain_name; + char *fq_domain_name; bbf_domain_mapping_rel = table_open(get_bbf_domain_mapping_oid(), RowShareLock); @@ -1862,12 +1883,14 @@ get_fully_qualified_domain_name(char *netbios_domain) tuple = systable_getnext(scan); if (HeapTupleIsValid(tuple)) { - char *tmp; - bool isnull = true; - Datum datum = heap_getattr(tuple, Anum_bbf_domain_mapping_fq_domain_name, dsc, &isnull); - /* - * If tuple is found correpsonding to supplied netbios domain name then - * fully qualified domain should not be null. Throw an error if it is. + char *tmp; + bool isnull = true; + Datum datum = heap_getattr(tuple, Anum_bbf_domain_mapping_fq_domain_name, dsc, &isnull); + + /* + * If tuple is found correpsonding to supplied netbios domain name + * then fully qualified domain should not be null. Throw an error if + * it is. */ if (isnull) { @@ -1884,9 +1907,9 @@ get_fully_qualified_domain_name(char *netbios_domain) } else { - /* - * If we could not find fully qualified domain name then - * assume that user has supplied fully qualified domain name and use it. + /* + * If we could not find fully qualified domain name then assume that + * user has supplied fully qualified domain name and use it. */ fq_domain_name = str_toupper(netbios_domain, strlen(netbios_domain), C_COLLATION_OID); } @@ -1897,26 +1920,27 @@ get_fully_qualified_domain_name(char *netbios_domain) return fq_domain_name; } -/* - * convertToUPN - This function is called to convert +/* + * convertToUPN - This function is called to convert * domain\user to user@DOMAIN. */ char * -convertToUPN(char* input) +convertToUPN(char *input) { - char *pos_slash = NULL; + char *pos_slash = NULL; if ((pos_slash = strchr(input, '\\')) != NULL) { - char *output = NULL; - char *netbios_domain_name = pnstrdup(input, (pos_slash - input)); + char *output = NULL; + char *netbios_domain_name = pnstrdup(input, (pos_slash - input)); + /* - * This means that provided login name is in windows format - * so let's update role_name with UPN format. + * This means that provided login name is in windows format so let's + * update role_name with UPN format. */ - output = psprintf("%s@%s", - str_tolower(pos_slash + 1, strlen(pos_slash + 1), C_COLLATION_OID), - get_fully_qualified_domain_name(netbios_domain_name)); + output = psprintf("%s@%s", + str_tolower(pos_slash + 1, strlen(pos_slash + 1), C_COLLATION_OID), + get_fully_qualified_domain_name(netbios_domain_name)); pfree(netbios_domain_name); return output; } @@ -1929,31 +1953,31 @@ convertToUPN(char* input) */ static void -validateNetBIOS(char* netbios) +validateNetBIOS(char *netbios) { - int len = strlen(netbios); - int i = 0; + int len = strlen(netbios); + int i = 0; if (len > NETBIOS_NAME_MAX_LEN || len < NETBIOS_NAME_MIN_LEN) ereport(ERROR, - (errcode(ERRCODE_INVALID_NAME), - errmsg("The NetBIOS name '%s' has invalid length. NetBIOS name length should be between %d and %d.", - netbios, NETBIOS_NAME_MIN_LEN, NETBIOS_NAME_MAX_LEN))); + (errcode(ERRCODE_INVALID_NAME), + errmsg("The NetBIOS name '%s' has invalid length. NetBIOS name length should be between %d and %d.", + netbios, NETBIOS_NAME_MIN_LEN, NETBIOS_NAME_MAX_LEN))); if (netbios[0] == '.') ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("'%s' is not a valid NetBIOS name. It must not start with '.' .", netbios))); - + errmsg("'%s' is not a valid NetBIOS name. It must not start with '.' .", netbios))); + while (netbios[i] != '\0') { - if (netbios[i] == '\\' || netbios[i] == '/'|| - netbios[i] == ':' || netbios[i] == '|' || - netbios[i] == '*' || netbios[i] == '?' || - netbios[i] == '<' || netbios[i] == '>' || - netbios[i] == '"') + if (netbios[i] == '\\' || netbios[i] == '/' || + netbios[i] == ':' || netbios[i] == '|' || + netbios[i] == '*' || netbios[i] == '?' || + netbios[i] == '<' || netbios[i] == '>' || + netbios[i] == '"') ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("'%s' is not a valid NetBIOS name because it contains invalid characters.", netbios))); - + errmsg("'%s' is not a valid NetBIOS name because it contains invalid characters.", netbios))); + i++; } } @@ -1963,35 +1987,35 @@ validateNetBIOS(char* netbios) */ static void -validateFQDN(char* fqdn) +validateFQDN(char *fqdn) { - int len = strlen(fqdn); - int i = 1; + int len = strlen(fqdn); + int i = 1; if (len > FQDN_NAME_MAX_LEN || len < FQDN_NAME_MIN_LEN) ereport(ERROR, - (errcode(ERRCODE_INVALID_NAME), - errmsg("The FQDN '%s' has invalid length. FQDN length should be between %d and %d.", - fqdn, FQDN_NAME_MIN_LEN, FQDN_NAME_MAX_LEN))); + (errcode(ERRCODE_INVALID_NAME), + errmsg("The FQDN '%s' has invalid length. FQDN length should be between %d and %d.", + fqdn, FQDN_NAME_MIN_LEN, FQDN_NAME_MAX_LEN))); if (!((fqdn[0] >= 'a' && fqdn[0] <= 'z') || (fqdn[0] >= 'A' && fqdn[0] <= 'Z') || (fqdn[0] >= '0' && fqdn[0] <= '9'))) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("'%s' is not a valid FQDN. It must start with alphabetical or numeric character.", fqdn))); + errmsg("'%s' is not a valid FQDN. It must start with alphabetical or numeric character.", fqdn))); - if (fqdn[len-1] == '-' || fqdn[len-1] == '.') + if (fqdn[len - 1] == '-' || fqdn[len - 1] == '.') ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("'%s' is not a valid FQDN. The last character must not be a minus sign or a period .", fqdn))); - + errmsg("'%s' is not a valid FQDN. The last character must not be a minus sign or a period .", fqdn))); + while (fqdn[i] != '\0') { if (!((fqdn[i] >= 'a' && fqdn[i] <= 'z') || (fqdn[i] >= 'A' && fqdn[i] <= 'Z') || (fqdn[i] >= '0' && fqdn[i] <= '9') || - (fqdn[i] == '-' || fqdn[i] == '.'))) + (fqdn[i] == '-' || fqdn[i] == '.'))) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("'%s' is not a valid FQDN because it contains invalid characters.", fqdn))); - + errmsg("'%s' is not a valid FQDN because it contains invalid characters.", fqdn))); + i++; } - + } PG_FUNCTION_INFO_V1(babelfish_add_domain_mapping_entry_internal); @@ -2003,31 +2027,31 @@ PG_FUNCTION_INFO_V1(babelfish_add_domain_mapping_entry_internal); Datum babelfish_add_domain_mapping_entry_internal(PG_FUNCTION_ARGS) { - Relation bbf_domain_mapping_rel; - HeapTuple tuple; - Datum *new_record; - bool *new_record_nulls; - MemoryContext ccxt = CurrentMemoryContext; + Relation bbf_domain_mapping_rel; + HeapTuple tuple; + Datum *new_record; + bool *new_record_nulls; + MemoryContext ccxt = CurrentMemoryContext; if (!pltsql_allow_windows_login) ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Windows login is not supported in babelfish"))); - + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Windows login is not supported in babelfish"))); + if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Arguments to babelfish_add_domain_mapping_entry should not be NULL"))); - if (!has_privs_of_role(GetSessionUserId(), get_role_oid("sysadmin", false))) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("Current login %s does not have permission to add new domain mapping entry", - GetUserNameFromId(GetSessionUserId(), true)))); + if (!has_privs_of_role(GetSessionUserId(), get_role_oid("sysadmin", false))) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("Current login %s does not have permission to add new domain mapping entry", + GetUserNameFromId(GetSessionUserId(), true)))); /* - * Validate the netbios and fqdn - */ + * Validate the netbios and fqdn + */ validateNetBIOS(TextDatumGetCString(PG_GETARG_DATUM(0))); validateFQDN(TextDatumGetCString(PG_GETARG_DATUM(1))); @@ -2057,7 +2081,7 @@ babelfish_add_domain_mapping_entry_internal(PG_FUNCTION_ARGS) PG_CATCH(); { MemoryContext ectx; - ErrorData *edata; + ErrorData *edata; ectx = MemoryContextSwitchTo(ccxt); table_close(bbf_domain_mapping_rel, RowExclusiveLock); @@ -2074,7 +2098,7 @@ babelfish_add_domain_mapping_entry_internal(PG_FUNCTION_ARGS) edata->message))); } PG_END_TRY(); - + return (Datum) 0; } @@ -2088,25 +2112,25 @@ Datum babelfish_remove_domain_mapping_entry_internal(PG_FUNCTION_ARGS) { Relation bbf_domain_mapping_rel; - ScanKeyData scanKey; - SysScanDesc scan; + ScanKeyData scanKey; + SysScanDesc scan; HeapTuple tuple; if (!pltsql_allow_windows_login) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Windows login is not supported in babelfish"))); - + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Windows login is not supported in babelfish"))); + if (PG_ARGISNULL(0)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Argument to babelfish_remove_domain_mapping_entry should not be NULL"))); - if (!has_privs_of_role(GetSessionUserId(), get_role_oid("sysadmin", false))) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("Current login %s does not have permission to remove domain mapping entry", - GetUserNameFromId(GetSessionUserId(), true)))); + if (!has_privs_of_role(GetSessionUserId(), get_role_oid("sysadmin", false))) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("Current login %s does not have permission to remove domain mapping entry", + GetUserNameFromId(GetSessionUserId(), true)))); bbf_domain_mapping_rel = table_open(get_bbf_domain_mapping_oid(), RowExclusiveLock); @@ -2132,7 +2156,7 @@ babelfish_remove_domain_mapping_entry_internal(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Domain mapping entry corresponding to supplied argument: \"%s\" could not be found.", - TextDatumGetCString(PG_GETARG_DATUM(0))))); + TextDatumGetCString(PG_GETARG_DATUM(0))))); } systable_endscan(scan); @@ -2150,15 +2174,15 @@ babelfish_truncate_domain_mapping_table_internal(PG_FUNCTION_ARGS) Relation bbf_domain_mapping_rel; if (!pltsql_allow_windows_login) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Windows login is not supported in babelfish"))); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Windows login is not supported in babelfish"))); - if (!has_privs_of_role(GetSessionUserId(), get_role_oid("sysadmin", false))) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("Current login %s does not have permission to remove domain mapping entry", - GetUserNameFromId(GetSessionUserId(), true)))); + if (!has_privs_of_role(GetSessionUserId(), get_role_oid("sysadmin", false))) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("Current login %s does not have permission to remove domain mapping entry", + GetUserNameFromId(GetSessionUserId(), true)))); bbf_domain_mapping_rel = table_open(get_bbf_domain_mapping_oid(), RowExclusiveLock); @@ -2168,35 +2192,37 @@ babelfish_truncate_domain_mapping_table_internal(PG_FUNCTION_ARGS) table_close(bbf_domain_mapping_rel, RowExclusiveLock); return (Datum) 0; } + /* * AD does not allow user to have some special characters, -* from babelfish side, we can not connect to AD directly +* from babelfish side, we can not connect to AD directly * so we do not know whether the user exists in AD or not. * From TDS endpoint, if login is created with such special -* characters, then we will throw error or else the user will -* get confused because the login will get created but they +* characters, then we will throw error or else the user will +* get confused because the login will get created but they * won't be able to connect */ -bool -windows_login_contains_invalid_chars(char* input) +bool +windows_login_contains_invalid_chars(char *input) { - char* pos_slash = strchr(input, '\\'); - - char* logon_name = pos_slash + 1; + char *pos_slash = strchr(input, '\\'); + + char *logon_name = pos_slash + 1; + + int i = 0; - int i = 0; while (logon_name[i] != '\0') { - if (logon_name[i] == '\\' || logon_name[i] == '/'|| - logon_name[i] == '[' || logon_name[i] == ']' || - logon_name[i] == ';' || logon_name[i] == ':' || - logon_name[i] == '|' || logon_name[i] == '=' || - logon_name[i] == ',' || logon_name[i] == '+' || - logon_name[i] == '*' || logon_name[i] == '?' || - logon_name[i] == '<' || logon_name[i] == '>' || - logon_name[i] == '@') + if (logon_name[i] == '\\' || logon_name[i] == '/' || + logon_name[i] == '[' || logon_name[i] == ']' || + logon_name[i] == ';' || logon_name[i] == ':' || + logon_name[i] == '|' || logon_name[i] == '=' || + logon_name[i] == ',' || logon_name[i] == '+' || + logon_name[i] == '*' || logon_name[i] == '?' || + logon_name[i] == '<' || logon_name[i] == '>' || + logon_name[i] == '@') return true; - + i++; } @@ -2207,13 +2233,13 @@ windows_login_contains_invalid_chars(char* input) * Check whether the logon_name has a valid length or not. */ bool -check_windows_logon_length(char* input) +check_windows_logon_length(char *input) { - char *pos_slash = strchr(input, '\\'); - int logon_name_len = strlen(pos_slash + 1); + char *pos_slash = strchr(input, '\\'); + int logon_name_len = strlen(pos_slash + 1); if (logon_name_len > LOGON_NAME_MIN_LEN && logon_name_len < LOGON_NAME_MAX_LEN) return true; else return false; -} \ No newline at end of file +} diff --git a/contrib/babelfishpg_tsql/src/rolecmds.h b/contrib/babelfishpg_tsql/src/rolecmds.h index 4e012305f6..9407726afb 100644 --- a/contrib/babelfishpg_tsql/src/rolecmds.h +++ b/contrib/babelfishpg_tsql/src/rolecmds.h @@ -49,10 +49,10 @@ #define USER_EXT_USER_CAN_CONNECT 15 extern void drop_bbf_roles(ObjectAccessType access, - Oid classId, - Oid roleid, - int subId, - void *arg); + Oid classId, + Oid roleid, + int subId, + void *arg); extern bool role_is_sa(Oid roleid); extern bool tsql_has_pgstat_permissions(Oid roleid); extern bool tsql_has_linked_srv_permissions(Oid roleid); @@ -75,8 +75,8 @@ extern void add_to_bbf_authid_user_ext(const char *user_name, extern void drop_related_bbf_users(List *db_users); extern void alter_bbf_authid_user_ext(AlterRoleStmt *stmt); extern bool is_active_login(Oid role_oid); -extern char *convertToUPN(char* input); -extern bool windows_login_contains_invalid_chars(char* input); -extern bool check_windows_logon_length(char* input); +extern char *convertToUPN(char *input); +extern bool windows_login_contains_invalid_chars(char *input); +extern bool check_windows_logon_length(char *input); #endif diff --git a/contrib/babelfishpg_tsql/src/schemacmds.c b/contrib/babelfishpg_tsql/src/schemacmds.c index 650b0df1c6..acb4d02340 100644 --- a/contrib/babelfishpg_tsql/src/schemacmds.c +++ b/contrib/babelfishpg_tsql/src/schemacmds.c @@ -22,16 +22,19 @@ static bool has_ext_info(const char *schemaname); -void +void add_ns_ext_info(CreateSchemaStmt *stmt, const char *queryString, const char *orig_name) { - Relation rel; - Datum *new_record; - bool *new_record_nulls; + Relation rel; + Datum *new_record; + bool *new_record_nulls; HeapTuple tuple; - int16 db_id = get_cur_db_id(); + int16 db_id = get_cur_db_id(); - /* orig_name will be provided only when queryString is not valid. e.g CREATE LOGICLA DATABASE */ + /* + * orig_name will be provided only when queryString is not valid. e.g + * CREATE LOGICLA DATABASE + */ if (!orig_name) { if (stmt->location != -1 && queryString) @@ -51,7 +54,7 @@ add_ns_ext_info(CreateSchemaStmt *stmt, const char *queryString, const char *ori new_record[0] = CStringGetDatum(stmt->schemaname); new_record[1] = Int16GetDatum(db_id); new_record[2] = CStringGetTextDatum(orig_name); - new_record[3] = CStringGetTextDatum("{}"); /* place holder */ + new_record[3] = CStringGetTextDatum("{}"); /* place holder */ tuple = heap_form_tuple(RelationGetDescr(rel), new_record, new_record_nulls); @@ -62,10 +65,10 @@ add_ns_ext_info(CreateSchemaStmt *stmt, const char *queryString, const char *ori CommandCounterIncrement(); } -void +void del_ns_ext_info(const char *schemaname, bool missing_ok) { - Relation rel; + Relation rel; HeapTuple tuple; ScanKeyData scanKey; SysScanDesc scan; @@ -105,34 +108,38 @@ check_extra_schema_restrictions(Node *stmt) { if (sql_dialect == SQL_DIALECT_PG) { - switch(nodeTag(stmt)) + switch (nodeTag(stmt)) { case T_DropStmt: - { - DropStmt *drop_stmt = (DropStmt *) stmt; - if (drop_stmt->removeType == OBJECT_SCHEMA) { - const char *schemaname = strVal(lfirst(list_head(drop_stmt->objects))); - if (has_ext_info(schemaname)) - ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("Could not drop schema created under T-SQL dialect: \"%s\"", schemaname))); + DropStmt *drop_stmt = (DropStmt *) stmt; + + if (drop_stmt->removeType == OBJECT_SCHEMA) + { + const char *schemaname = strVal(lfirst(list_head(drop_stmt->objects))); + + if (has_ext_info(schemaname)) + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("Could not drop schema created under T-SQL dialect: \"%s\"", schemaname))); + } + break; } - break; - } case T_RenameStmt: - { - RenameStmt *rename_stmt = (RenameStmt *) stmt; - if (rename_stmt->renameType == OBJECT_SCHEMA) { - const char *schemaname = rename_stmt->subname; - if (has_ext_info(schemaname)) - ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("Could not rename schema created under T-SQL dialect: \"%s\"", schemaname))); + RenameStmt *rename_stmt = (RenameStmt *) stmt; + + if (rename_stmt->renameType == OBJECT_SCHEMA) + { + const char *schemaname = rename_stmt->subname; + + if (has_ext_info(schemaname)) + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("Could not rename schema created under T-SQL dialect: \"%s\"", schemaname))); + } + break; } - break; - } default: break; } @@ -142,11 +149,11 @@ check_extra_schema_restrictions(Node *stmt) static bool has_ext_info(const char *schemaname) { - Relation rel; + Relation rel; HeapTuple tuple; ScanKeyData scanKey; SysScanDesc scan; - bool found = true; + bool found = true; rel = table_open(namespace_ext_oid, AccessShareLock); ScanKeyInit(&scanKey, diff --git a/contrib/babelfishpg_tsql/src/session.c b/contrib/babelfishpg_tsql/src/session.c index 437d565e7b..5f6ea4001a 100644 --- a/contrib/babelfishpg_tsql/src/session.c +++ b/contrib/babelfishpg_tsql/src/session.c @@ -17,22 +17,24 @@ /* Core Session Properties */ -#define MAX_SYSNAME_LEN 512 /* Large enough to handle 128 character unicode strings */ +#define MAX_SYSNAME_LEN 512 /* Large enough to handle 128 character + * unicode strings */ static int16 current_db_id = 0; -static char current_db_name[MAX_BBF_NAMEDATALEND+1] = {'\0'}; -static Oid current_user_id = InvalidOid; -static void set_search_path_for_user_schema(const char* db_name, const char* user); -void reset_cached_batch(void); +static char current_db_name[MAX_BBF_NAMEDATALEND + 1] = {'\0'}; +static Oid current_user_id = InvalidOid; +static void set_search_path_for_user_schema(const char *db_name, const char *user); +void reset_cached_batch(void); /* Session Context */ static HTAB *session_context_table = NULL; static void initialize_context_table(void); typedef struct SessionCxtEntry { - char sessionKey[MAX_SYSNAME_LEN]; /* Hashtable Key, must be first */ - bool read_only; - bytea *value; + char sessionKey[MAX_SYSNAME_LEN]; /* Hashtable Key, must be + * first */ + bool read_only; + bytea *value; } SessionCxtEntry; int16 @@ -50,7 +52,7 @@ get_cur_db_name(void) void set_cur_db(int16 id, const char *name) { - int len = strlen(name); + int len = strlen(name); Assert(len <= MAX_BBF_NAMEDATALEND); @@ -59,13 +61,13 @@ set_cur_db(int16 id, const char *name) current_db_name[len] = '\0'; if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->set_db_stat_var) - (*pltsql_protocol_plugin_ptr)->set_db_stat_var(id); + (*pltsql_protocol_plugin_ptr)->set_db_stat_var(id); } void bbf_set_current_user(const char *user_name) { - Oid userid; + Oid userid; userid = get_role_oid(user_name, false); SetConfigOption("role", user_name, PGC_SUSET, PGC_S_DATABASE_USER); @@ -75,27 +77,27 @@ bbf_set_current_user(const char *user_name) void set_session_properties(const char *db_name) { - int16 db_id = get_db_id(db_name); + int16 db_id = get_db_id(db_name); if (!DbidIsValid(db_id)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_DATABASE), - errmsg("database \"%s\" does not exist", db_name))); + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_DATABASE), + errmsg("database \"%s\" does not exist", db_name))); check_session_db_access(db_name); set_cur_user_db_and_path(db_name); } -/* +/* * Raises an error if the current session does not have access to the given database - * Caller responsible for checking db_name is valid + * Caller responsible for checking db_name is valid */ void -check_session_db_access(const char* db_name) +check_session_db_access(const char *db_name) { - const char *user = NULL; - const char *login; + const char *user = NULL; + const char *login; user = get_user_for_database(db_name); @@ -112,10 +114,10 @@ check_session_db_access(const char* db_name) /* Caller responsible for checking db_name is valid */ void -set_cur_user_db_and_path(const char* db_name) +set_cur_user_db_and_path(const char *db_name) { - const char *user = get_user_for_database(db_name); - int16 db_id = get_db_id(db_name); + const char *user = get_user_for_database(db_name); + int16 db_id = get_db_id(db_name); /* set current DB */ set_cur_db(db_id, db_name); @@ -129,13 +131,13 @@ set_cur_user_db_and_path(const char* db_name) } static void -set_search_path_for_user_schema(const char* db_name, const char* user) +set_search_path_for_user_schema(const char *db_name, const char *user) { - const char *path; - const char *buffer = "%s, \"$user\", sys, pg_catalog"; - const char *physical_schema; - const char *dbo_role_name = get_dbo_role_name(db_name); - const char *guest_role_name = get_guest_role_name(db_name); + const char *path; + const char *buffer = "%s, \"$user\", sys, pg_catalog"; + const char *physical_schema; + const char *dbo_role_name = get_dbo_role_name(db_name); + const char *guest_role_name = get_guest_role_name(db_name); if ((dbo_role_name && strcmp(user, dbo_role_name) == 0)) { @@ -144,13 +146,15 @@ set_search_path_for_user_schema(const char* db_name, const char* user) else if (guest_role_name && strcmp(user, guest_role_name) == 0) { const char *guest_schema = get_authid_user_ext_schema_name(db_name, "guest"); + if (!guest_schema) guest_schema = "guest"; physical_schema = get_physical_schema_name(pstrdup(db_name), guest_schema); } else { - const char *schema; + const char *schema; + schema = get_authid_user_ext_schema_name(db_name, user); physical_schema = get_physical_schema_name(pstrdup(db_name), schema); } @@ -178,7 +182,7 @@ restore_session_properties() { if (DbidIsValid(get_cur_db_id()) && OidIsValid(current_user_id)) { - char *cur_user; + char *cur_user; cur_user = GetUserNameFromId(current_user_id, true); @@ -192,18 +196,20 @@ restore_session_properties() } PG_FUNCTION_INFO_V1(babelfish_db_id); -Datum babelfish_db_id(PG_FUNCTION_ARGS) +Datum +babelfish_db_id(PG_FUNCTION_ARGS) { - char *str; - int16 dbid; + char *str; + int16 dbid; if (PG_NARGS() > 0) { str = TextDatumGetCString(PG_GETARG_DATUM(0)); if (pltsql_case_insensitive_identifiers) - // Lowercase the entry, if needed - for (char *p = str ; *p; ++p) *p = tolower(*p); - + /* Lowercase the entry, if needed */ + for (char *p = str; *p; ++p) + *p = tolower(*p); + dbid = get_db_id(str); } else @@ -218,10 +224,11 @@ Datum babelfish_db_id(PG_FUNCTION_ARGS) } PG_FUNCTION_INFO_V1(babelfish_db_name); -Datum babelfish_db_name(PG_FUNCTION_ARGS) +Datum +babelfish_db_name(PG_FUNCTION_ARGS) { - int16 dbid; - char * dbname; + int16 dbid; + char *dbname; if (PG_NARGS() > 0) dbid = PG_GETARG_INT32(0); @@ -252,28 +259,29 @@ Datum babelfish_db_name(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(CStringGetTextDatum(dbname)); } -/* +/* * Stores key-value pairs in a hashtable * Table takes a string as a key, and saves a pointer to the sql_variant-typed value */ PG_FUNCTION_INFO_V1(sp_set_session_context); -Datum sp_set_session_context(PG_FUNCTION_ARGS) +Datum +sp_set_session_context(PG_FUNCTION_ARGS) { - VarChar *key_arg; + VarChar *key_arg; SessionCxtEntry *result_entry; - char *key; - bool found; + char *key; + bool found; MemoryContext oldContext; - int i; + int i; if (PG_ARGISNULL(0)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("The parameters supplied for the procedure \"sp_set_session_context\" are not valid."))); + errmsg("The parameters supplied for the procedure \"sp_set_session_context\" are not valid."))); key_arg = PG_GETARG_VARCHAR_PP(0); key = str_tolower(VARDATA_ANY(key_arg), VARSIZE_ANY_EXHDR(key_arg), DEFAULT_COLLATION_OID); if (strlen(key) == 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("The parameters supplied for the procedure \"sp_set_session_context\" are not valid."))); + errmsg("The parameters supplied for the procedure \"sp_set_session_context\" are not valid."))); /* Strip Whitespace */ i = strlen(key); @@ -283,11 +291,11 @@ Datum sp_set_session_context(PG_FUNCTION_ARGS) if (!session_context_table) initialize_context_table(); - result_entry = (SessionCxtEntry*) hash_search(session_context_table, key, HASH_ENTER, &found); + result_entry = (SessionCxtEntry *) hash_search(session_context_table, key, HASH_ENTER, &found); if (found && result_entry->read_only == true) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("Cannot set key '%s' in the session context. The key has been set as read_only for this session.", key))); + errmsg("Cannot set key '%s' in the session context. The key has been set as read_only for this session.", key))); /* Free old entry if val argument is null */ if (PG_ARGISNULL(1)) @@ -295,7 +303,7 @@ Datum sp_set_session_context(PG_FUNCTION_ARGS) if (found) pfree(result_entry->value); hash_search(session_context_table, key, HASH_REMOVE, NULL); - PG_RETURN_NULL(); + PG_RETURN_NULL(); } pfree(key); @@ -308,29 +316,30 @@ Datum sp_set_session_context(PG_FUNCTION_ARGS) } PG_FUNCTION_INFO_V1(session_context); -Datum session_context(PG_FUNCTION_ARGS) +Datum +session_context(PG_FUNCTION_ARGS) { - char *key; + char *key; SessionCxtEntry *result_entry; - VarChar *key_arg; - int i; + VarChar *key_arg; + int i; if (!session_context_table) PG_RETURN_NULL(); if (PG_ARGISNULL(0)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("The parameters supplied for the function \"session_context\" are not valid."))); + errmsg("The parameters supplied for the function \"session_context\" are not valid."))); key_arg = PG_GETARG_VARCHAR_PP(0); key = str_tolower(VARDATA_ANY(key_arg), VARSIZE_ANY_EXHDR(key_arg), DEFAULT_COLLATION_OID); - + /* Strip Whitespace */ i = strlen(key); while (i > 0 && isspace((unsigned char) key[i - 1])) key[--i] = '\0'; - result_entry = (SessionCxtEntry*) hash_search(session_context_table, key, HASH_FIND, NULL); + result_entry = (SessionCxtEntry *) hash_search(session_context_table, key, HASH_FIND, NULL); pfree(key); if (!result_entry) @@ -339,9 +348,10 @@ Datum session_context(PG_FUNCTION_ARGS) } static void -initialize_context_table() +initialize_context_table() { - HASHCTL hash_options; + HASHCTL hash_options; + memset(&hash_options, 0, sizeof(hash_options)); hash_options.keysize = MAX_SYSNAME_LEN; hash_options.entrysize = sizeof(SessionCxtEntry); diff --git a/contrib/babelfishpg_tsql/src/session.h b/contrib/babelfishpg_tsql/src/session.h index d425099435..32de3f8427 100644 --- a/contrib/babelfishpg_tsql/src/session.h +++ b/contrib/babelfishpg_tsql/src/session.h @@ -7,8 +7,8 @@ extern void set_cur_db(int16 id, const char *name); extern char *get_cur_db_name(void); extern void bbf_set_current_user(const char *user_name); extern void set_session_properties(const char *db_name); -extern void check_session_db_access(const char* dn_name); -extern void set_cur_user_db_and_path(const char* db_name); +extern void check_session_db_access(const char *dn_name); +extern void set_cur_user_db_and_path(const char *db_name); extern void restore_session_properties(void); extern void reset_session_properties(void); diff --git a/contrib/babelfishpg_tsql/src/special_keywords.c b/contrib/babelfishpg_tsql/src/special_keywords.c index 9c73e96f21..3c7214687a 100644 --- a/contrib/babelfishpg_tsql/src/special_keywords.c +++ b/contrib/babelfishpg_tsql/src/special_keywords.c @@ -7,38 +7,39 @@ #include "c.h" -size_t get_num_column_names_to_be_delimited(void); -size_t get_num_pg_reserved_keywords_to_be_delimited(void); +size_t get_num_column_names_to_be_delimited(void); +size_t get_num_pg_reserved_keywords_to_be_delimited(void); const char *column_names_to_be_delimited[] = { - /* - * PG keywords defined as TYPE_FUNC_NAME_KEYWORD - * but treated as a normal unreserved keyword (or not a keyword) in T-SQL. - */ - "binary", - "collation", - "concurrently", - "current_schema", - "freeze", - "ilike", - "isnull", - "natural", - "notnull", - "overlaps", - "similar", + /* + * PG keywords defined as TYPE_FUNC_NAME_KEYWORD but treated as a normal + * unreserved keyword (or not a keyword) in T-SQL. + */ + "binary", + "collation", + "concurrently", + "current_schema", + "freeze", + "ilike", + "isnull", + "natural", + "notnull", + "overlaps", + "similar", - /* - * PG unreserved keyword which can be used in table hint. - * this cause an issue in a query such as "create table t(nowait int)" - */ - "noexpand", - "nowait", - "snapshot" + /* + * PG unreserved keyword which can be used in table hint. this cause an + * issue in a query such as "create table t(nowait int)" + */ + "noexpand", + "nowait", + "snapshot" }; -size_t get_num_column_names_to_be_delimited() +size_t +get_num_column_names_to_be_delimited() { - return lengthof(column_names_to_be_delimited); + return lengthof(column_names_to_be_delimited); } /* @@ -51,53 +52,53 @@ size_t get_num_column_names_to_be_delimited() * which can be located in any column reference. */ const char *pg_reserved_keywords_to_be_delimited[] = { - "analyse", - "analyze", - "array", - "asymmetric", - "both", - "cast", - "current_catalog", - "current_role", - "deferrable", - "do", - //"false", - "initially", - "lateral", - "leading", - "limit", - "localtime", - "localtimestamp", - "offset", - "only", - "placing", - "returning", - "symmetric", - "trailing", - //"true", - "using", - "variadic", - "window", + "analyse", + "analyze", + "array", + "asymmetric", + "both", + "cast", + "current_catalog", + "current_role", + "deferrable", + "do", + /* "false", */ + "initially", + "lateral", + "leading", + "limit", + "localtime", + "localtimestamp", + "offset", + "only", + "placing", + "returning", + "symmetric", + "trailing", + /* "true", */ + "using", + "variadic", + "window", - /* reserved keywords listed in Babelfish backend parser extension */ - "apply", - "choose", - "dateadd", - "datediff", - "datediff_big", - "datename", - "datepart", - "iif", - "out", - "output", - "parse", - "readonly", - "try_cast", - "try_parse" + /* reserved keywords listed in Babelfish backend parser extension */ + "apply", + "choose", + "dateadd", + "datediff", + "datediff_big", + "datename", + "datepart", + "iif", + "out", + "output", + "parse", + "readonly", + "try_cast", + "try_parse" }; -size_t get_num_pg_reserved_keywords_to_be_delimited() +size_t +get_num_pg_reserved_keywords_to_be_delimited() { - return lengthof(pg_reserved_keywords_to_be_delimited); + return lengthof(pg_reserved_keywords_to_be_delimited); } - diff --git a/contrib/babelfishpg_tsql/src/stmt_walker.c b/contrib/babelfishpg_tsql/src/stmt_walker.c index eb64987f23..7fa14f5263 100644 --- a/contrib/babelfishpg_tsql/src/stmt_walker.c +++ b/contrib/babelfishpg_tsql/src/stmt_walker.c @@ -5,133 +5,140 @@ * BASIC APIS **********************************************************************************/ -bool stmt_walker(PLtsql_stmt *stmt, WalkerFunc walker, void *context) +bool +stmt_walker(PLtsql_stmt *stmt, WalkerFunc walker, void *context) { - ListCell *s; - if (!stmt) - return false; - - check_stack_depth(); - - switch (stmt->cmd_type) - { - case PLTSQL_STMT_BLOCK: - { - PLtsql_stmt_block *stmt_block = (PLtsql_stmt_block *) stmt; - foreach(s, stmt_block->body) - if (walker((PLtsql_stmt *) lfirst(s), context)) - return true; - break; - } - case PLTSQL_STMT_ASSIGN: - break; - case PLTSQL_STMT_IF: - { - PLtsql_stmt_if *stmt_if = (PLtsql_stmt_if *) stmt; - - if (walker(stmt_if->then_body, context)) - return true; - - if (stmt_if->else_body && - walker(stmt_if->else_body, context)) - return true; - - break; - } - case PLTSQL_STMT_WHILE: - { - PLtsql_stmt_while *stmt_while = (PLtsql_stmt_while *) stmt; - foreach(s, stmt_while->body) - if (walker((PLtsql_stmt *) lfirst(s), context)) - return true; - - break; - } - case PLTSQL_STMT_EXIT: - case PLTSQL_STMT_RETURN: - case PLTSQL_STMT_RETURN_QUERY: - case PLTSQL_STMT_EXECSQL: - case PLTSQL_STMT_OPEN: - case PLTSQL_STMT_FETCH: - case PLTSQL_STMT_CLOSE: - case PLTSQL_STMT_COMMIT: - case PLTSQL_STMT_ROLLBACK: - break; - - /* TSQL-only statement types follow */ - case PLTSQL_STMT_GOTO: - case PLTSQL_STMT_PRINT: - break; - case PLTSQL_STMT_INIT: - { - PLtsql_stmt_init *stmt_init = (PLtsql_stmt_init *) stmt; - foreach(s, stmt_init->inits) - if (walker((PLtsql_stmt *) lfirst(s), context)) - return true; - - break; - } - case PLTSQL_STMT_QUERY_SET: + ListCell *s; + + if (!stmt) + return false; + + check_stack_depth(); + + switch (stmt->cmd_type) + { + case PLTSQL_STMT_BLOCK: + { + PLtsql_stmt_block *stmt_block = (PLtsql_stmt_block *) stmt; + + foreach(s, stmt_block->body) + if (walker((PLtsql_stmt *) lfirst(s), context)) + return true; + break; + } + case PLTSQL_STMT_ASSIGN: break; - case PLTSQL_STMT_TRY_CATCH: - { - PLtsql_stmt_try_catch *stmt_try_catch = (PLtsql_stmt_try_catch *) stmt; - - if (walker(stmt_try_catch->body, context)) - return true; - - if (walker(stmt_try_catch->handler, context)) - return true; - - break; - } - case PLTSQL_STMT_PUSH_RESULT: - case PLTSQL_STMT_EXEC: - case PLTSQL_STMT_EXEC_BATCH: - case PLTSQL_STMT_EXEC_SP: - case PLTSQL_STMT_DECL_TABLE: - case PLTSQL_STMT_RETURN_TABLE: - case PLTSQL_STMT_DEALLOCATE: - case PLTSQL_STMT_DECL_CURSOR: - case PLTSQL_STMT_LABEL: + case PLTSQL_STMT_IF: + { + PLtsql_stmt_if *stmt_if = (PLtsql_stmt_if *) stmt; + + if (walker(stmt_if->then_body, context)) + return true; + + if (stmt_if->else_body && + walker(stmt_if->else_body, context)) + return true; + + break; + } + case PLTSQL_STMT_WHILE: + { + PLtsql_stmt_while *stmt_while = (PLtsql_stmt_while *) stmt; + + foreach(s, stmt_while->body) + if (walker((PLtsql_stmt *) lfirst(s), context)) + return true; + + break; + } + case PLTSQL_STMT_EXIT: + case PLTSQL_STMT_RETURN: + case PLTSQL_STMT_RETURN_QUERY: + case PLTSQL_STMT_EXECSQL: + case PLTSQL_STMT_OPEN: + case PLTSQL_STMT_FETCH: + case PLTSQL_STMT_CLOSE: + case PLTSQL_STMT_COMMIT: + case PLTSQL_STMT_ROLLBACK: + break; + + /* TSQL-only statement types follow */ + case PLTSQL_STMT_GOTO: + case PLTSQL_STMT_PRINT: + break; + case PLTSQL_STMT_INIT: + { + PLtsql_stmt_init *stmt_init = (PLtsql_stmt_init *) stmt; + + foreach(s, stmt_init->inits) + if (walker((PLtsql_stmt *) lfirst(s), context)) + return true; + + break; + } + case PLTSQL_STMT_QUERY_SET: + break; + case PLTSQL_STMT_TRY_CATCH: + { + PLtsql_stmt_try_catch *stmt_try_catch = (PLtsql_stmt_try_catch *) stmt; + + if (walker(stmt_try_catch->body, context)) + return true; + + if (walker(stmt_try_catch->handler, context)) + return true; + + break; + } + case PLTSQL_STMT_PUSH_RESULT: + case PLTSQL_STMT_EXEC: + case PLTSQL_STMT_EXEC_BATCH: + case PLTSQL_STMT_EXEC_SP: + case PLTSQL_STMT_DECL_TABLE: + case PLTSQL_STMT_RETURN_TABLE: + case PLTSQL_STMT_DEALLOCATE: + case PLTSQL_STMT_DECL_CURSOR: + case PLTSQL_STMT_LABEL: case PLTSQL_STMT_RAISERROR: case PLTSQL_STMT_THROW: - case PLTSQL_STMT_USEDB: - case PLTSQL_STMT_INSERT_BULK: - case PLTSQL_STMT_SET_EXPLAIN_MODE: - case PLTSQL_STMT_GRANTDB: - break; - /* TSQL-only executable node */ - case PLTSQL_STMT_SAVE_CTX: - case PLTSQL_STMT_RESTORE_CTX_FULL: - case PLTSQL_STMT_RESTORE_CTX_PARTIAL: - /* no child child statement */ - break; - default: - ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Unsupported statment type %s when adding child node", - pltsql_stmt_typename(stmt)))); - } - return false; + case PLTSQL_STMT_USEDB: + case PLTSQL_STMT_INSERT_BULK: + case PLTSQL_STMT_SET_EXPLAIN_MODE: + case PLTSQL_STMT_GRANTDB: + break; + /* TSQL-only executable node */ + case PLTSQL_STMT_SAVE_CTX: + case PLTSQL_STMT_RESTORE_CTX_FULL: + case PLTSQL_STMT_RESTORE_CTX_PARTIAL: + /* no child child statement */ + break; + default: + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Unsupported statment type %s when adding child node", + pltsql_stmt_typename(stmt)))); + } + return false; } /*********************************************************************************** - * General Walker Function and Template Context + * General Walker Function and Template Context **********************************************************************************/ /* get template context */ -Walker_context *make_template_context(void) +Walker_context * +make_template_context(void) { - return palloc0(sizeof(Walker_context)); + return palloc0(sizeof(Walker_context)); } -void destroy_template_context(Walker_context *ctx) +void +destroy_template_context(Walker_context *ctx) { - /* destroy extra context first */ - if (ctx->destroy_extra_ctx) - ctx->destroy_extra_ctx(ctx->extra_ctx); + /* destroy extra context first */ + if (ctx->destroy_extra_ctx) + ctx->destroy_extra_ctx(ctx->extra_ctx); - pfree(ctx); + pfree(ctx); } #define DISPATCH(T, f) \ @@ -143,69 +150,70 @@ void destroy_template_context(Walker_context *ctx) } /* dispatch each statement to its action defined in context */ -bool general_walker_func(PLtsql_stmt *stmt, void *context) +bool +general_walker_func(PLtsql_stmt *stmt, void *context) { - Walker_context *ctx = (Walker_context *) context; + Walker_context *ctx = (Walker_context *) context; #if 1 if (stmt == NULL) return false; #endif - - switch(stmt->cmd_type) - { - DISPATCH(BLOCK, block) - DISPATCH(ASSIGN, assign) - DISPATCH(IF, if) - DISPATCH(WHILE, while) - DISPATCH(EXIT, exit) - DISPATCH(RETURN, return) - DISPATCH(RETURN_QUERY, return_query) - DISPATCH(EXECSQL, execsql) - DISPATCH(OPEN, open) - DISPATCH(FETCH, fetch) - DISPATCH(CLOSE, close) - DISPATCH(COMMIT, commit) - DISPATCH(ROLLBACK, rollback) - - /* TSQL-only statement types follow */ - DISPATCH(GOTO, goto) - DISPATCH(PRINT, print) - DISPATCH(INIT, init) - DISPATCH(QUERY_SET, query_set) - DISPATCH(TRY_CATCH, try_catch) - DISPATCH(PUSH_RESULT, push_result) - DISPATCH(EXEC, exec) - DISPATCH(EXEC_BATCH, exec_batch) - DISPATCH(EXEC_SP, exec_sp) - DISPATCH(DECL_TABLE, decl_table) - case PLTSQL_STMT_RETURN_TABLE: - { - if (ctx->return_table_act) - return ctx->return_table_act(ctx, (PLtsql_stmt_return_query *) stmt); - break; - } - DISPATCH(DEALLOCATE, deallocate) - DISPATCH(DECL_CURSOR, decl_cursor) - DISPATCH(LABEL, label) - DISPATCH(RAISERROR, raiserror) - DISPATCH(THROW, throw) - DISPATCH(USEDB, usedb) - DISPATCH(INSERT_BULK, insert_bulk) - DISPATCH(SET_EXPLAIN_MODE, set_explain_mode) - DISPATCH(GRANTDB, grantdb) - - /* TSQL-only executable node */ - DISPATCH(SAVE_CTX, save_ctx) - DISPATCH(RESTORE_CTX_FULL, restore_ctx_full) - DISPATCH(RESTORE_CTX_PARTIAL, restore_ctx_partial) - default: - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Unsupported statment type %d", stmt->cmd_type))); - } - if (ctx->default_act) - return ctx->default_act(ctx, stmt); - return stmt_walker(stmt, general_walker_func, context); + switch (stmt->cmd_type) + { + DISPATCH(BLOCK, block) + DISPATCH(ASSIGN, assign) + DISPATCH(IF, if) + DISPATCH(WHILE, while) + DISPATCH(EXIT, exit) + DISPATCH(RETURN, return) + DISPATCH(RETURN_QUERY, return_query) + DISPATCH(EXECSQL, execsql) + DISPATCH(OPEN, open) + DISPATCH(FETCH, fetch) + DISPATCH(CLOSE, close) + DISPATCH(COMMIT, commit) + DISPATCH(ROLLBACK, rollback) + + /* TSQL-only statement types follow */ + DISPATCH(GOTO, goto) + DISPATCH(PRINT, print) + DISPATCH(INIT, init) + DISPATCH(QUERY_SET, query_set) + DISPATCH(TRY_CATCH, try_catch) + DISPATCH(PUSH_RESULT, push_result) + DISPATCH(EXEC, exec) + DISPATCH(EXEC_BATCH, exec_batch) + DISPATCH(EXEC_SP, exec_sp) + DISPATCH(DECL_TABLE, decl_table) + case PLTSQL_STMT_RETURN_TABLE: + { + if (ctx->return_table_act) + return ctx->return_table_act(ctx, (PLtsql_stmt_return_query *) stmt); + break; + } + DISPATCH(DEALLOCATE, deallocate) + DISPATCH(DECL_CURSOR, decl_cursor) + DISPATCH(LABEL, label) + DISPATCH(RAISERROR, raiserror) + DISPATCH(THROW, throw) + DISPATCH(USEDB, usedb) + DISPATCH(INSERT_BULK, insert_bulk) + DISPATCH(SET_EXPLAIN_MODE, set_explain_mode) + DISPATCH(GRANTDB, grantdb) + + /* TSQL-only executable node */ + DISPATCH(SAVE_CTX, save_ctx) + DISPATCH(RESTORE_CTX_FULL, restore_ctx_full) + DISPATCH(RESTORE_CTX_PARTIAL, restore_ctx_partial) + default: + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Unsupported statment type %d", stmt->cmd_type))); + } + if (ctx->default_act) + return ctx->default_act(ctx, stmt); + + return stmt_walker(stmt, general_walker_func, context); } diff --git a/contrib/babelfishpg_tsql/src/stmt_walker.h b/contrib/babelfishpg_tsql/src/stmt_walker.h index e026596190..8dc7db0983 100644 --- a/contrib/babelfishpg_tsql/src/stmt_walker.h +++ b/contrib/babelfishpg_tsql/src/stmt_walker.h @@ -13,21 +13,21 @@ typedef bool (*WalkerFunc) (PLtsql_stmt *stmt, void *context); /* Walker */ -bool stmt_walker(PLtsql_stmt *stmt, WalkerFunc walker, void *context); +bool stmt_walker(PLtsql_stmt *stmt, WalkerFunc walker, void *context); /*********************************************************************************** - * General Walker Function and Template Context + * General Walker Function and Template Context **********************************************************************************/ /* * Simple algorithms handling only a few types of nodes could rely on above APIs. * Algorithms handling more types could consider using following general walker function * and template context to further simplify the implementation - * + * * Walker_context *mycontext = make_context_template(); * - * // 1. define actions + * // 1. define actions * mycontext->if_act = &my_if_action; * ..... * mycontext->label_act = &mylabel_action; @@ -45,8 +45,8 @@ bool stmt_walker(PLtsql_stmt *stmt, WalkerFunc walker, void *context); /* actions associated with each stmt */ typedef struct Walker_context Walker_context; -typedef bool (*Stmt_default_act) - (Walker_context *ctx, PLtsql_stmt *stmt); +typedef bool (*Stmt_default_act) + (Walker_context *ctx, PLtsql_stmt *stmt); #define ACTION_SIGNITURE(type) \ (Walker_context *ctx, PLtsql_stmt_##type *stmt) @@ -65,7 +65,7 @@ typedef bool (*Stmt_close_act) ACTION_SIGNITURE(close); typedef bool (*Stmt_commit_act) ACTION_SIGNITURE(commit); typedef bool (*Stmt_rollback_act) ACTION_SIGNITURE(rollback); - /* TSQL-only statement types follow */ + /* TSQL-only statement types follow */ typedef bool (*Stmt_goto_act) ACTION_SIGNITURE(goto); typedef bool (*Stmt_print_act) ACTION_SIGNITURE(print); typedef bool (*Stmt_init_act) ACTION_SIGNITURE(init); @@ -87,7 +87,7 @@ typedef bool (*Stmt_insert_bulk_act) ACTION_SIGNITURE(insert_bulk); typedef bool (*Stmt_set_explain_mode) ACTION_SIGNITURE(set_explain_mode); typedef bool (*Stmt_grantdb_act) ACTION_SIGNITURE(grantdb); - /* TSQL-only executable node */ + /* TSQL-only executable node */ typedef bool (*Stmt_save_ctx) ACTION_SIGNITURE(save_ctx); typedef bool (*Stmt_restore_ctx_full) ACTION_SIGNITURE(restore_ctx_full); typedef bool (*Stmt_restore_ctx_partial) ACTION_SIGNITURE(restore_ctx_partial); @@ -97,60 +97,60 @@ typedef void (*Context_destroyer) (void *extra_ctx); typedef struct Walker_context { - /* Action associated to each stmt */ - Stmt_default_act default_act; - - Stmt_block_act block_act; - Stmt_assign_act assign_act; - Stmt_if_act if_act; - Stmt_while_act while_act; - Stmt_exit_act exit_act; - Stmt_return_act return_act; - Stmt_return_query_act return_query_act; - Stmt_execsql_act execsql_act; - Stmt_open_act open_act; - Stmt_fetch_act fetch_act; - Stmt_close_act close_act; - Stmt_commit_act commit_act; - Stmt_rollback_act rollback_act; + /* Action associated to each stmt */ + Stmt_default_act default_act; + + Stmt_block_act block_act; + Stmt_assign_act assign_act; + Stmt_if_act if_act; + Stmt_while_act while_act; + Stmt_exit_act exit_act; + Stmt_return_act return_act; + Stmt_return_query_act return_query_act; + Stmt_execsql_act execsql_act; + Stmt_open_act open_act; + Stmt_fetch_act fetch_act; + Stmt_close_act close_act; + Stmt_commit_act commit_act; + Stmt_rollback_act rollback_act; /* TSQL-only statement types follow */ - Stmt_goto_act goto_act; - Stmt_print_act print_act; - Stmt_init_act init_act; - Stmt_query_set_act query_set_act; - Stmt_try_catch_act try_catch_act; - Stmt_push_result_act push_result_act; - Stmt_exec_act exec_act; - Stmt_exec_batch_act exec_batch_act; - Stmt_exec_sp_act exec_sp_act; - Stmt_decl_table_act decl_table_act; - Stmt_return_table_act return_table_act; - Stmt_deallocate_act deallocate_act; - Stmt_decl_cursor_act decl_cursor_act; - Stmt_label_act label_act; - Stmt_raiserror_act raiserror_act; - Stmt_throw_act throw_act; - Stmt_usedb_act usedb_act; - Stmt_insert_bulk_act insert_bulk_act; - Stmt_set_explain_mode set_explain_mode_act; - Stmt_grantdb_act grantdb_act; - - /* TSQL-only executable node */ - Stmt_save_ctx save_ctx_act; - Stmt_restore_ctx_full restore_ctx_full_act; - Stmt_restore_ctx_partial restore_ctx_partial_act; - - /* external pointer for extensions */ - void *extra_ctx; - Context_destroyer destroy_extra_ctx; + Stmt_goto_act goto_act; + Stmt_print_act print_act; + Stmt_init_act init_act; + Stmt_query_set_act query_set_act; + Stmt_try_catch_act try_catch_act; + Stmt_push_result_act push_result_act; + Stmt_exec_act exec_act; + Stmt_exec_batch_act exec_batch_act; + Stmt_exec_sp_act exec_sp_act; + Stmt_decl_table_act decl_table_act; + Stmt_return_table_act return_table_act; + Stmt_deallocate_act deallocate_act; + Stmt_decl_cursor_act decl_cursor_act; + Stmt_label_act label_act; + Stmt_raiserror_act raiserror_act; + Stmt_throw_act throw_act; + Stmt_usedb_act usedb_act; + Stmt_insert_bulk_act insert_bulk_act; + Stmt_set_explain_mode set_explain_mode_act; + Stmt_grantdb_act grantdb_act; + + /* TSQL-only executable node */ + Stmt_save_ctx save_ctx_act; + Stmt_restore_ctx_full restore_ctx_full_act; + Stmt_restore_ctx_partial restore_ctx_partial_act; + + /* external pointer for extensions */ + void *extra_ctx; + Context_destroyer destroy_extra_ctx; } Walker_context; /* * General walker function */ -bool general_walker_func(PLtsql_stmt *stmt, void *context); +bool general_walker_func(PLtsql_stmt *stmt, void *context); /* * Get a template context @@ -161,6 +161,6 @@ Walker_context *make_template_context(void); /* * Destory template context and extra context if any */ -void destroy_template_context(Walker_context *ctx); +void destroy_template_context(Walker_context *ctx); -#endif /* STMT_WALKER_H */ +#endif /* STMT_WALKER_H */ diff --git a/contrib/babelfishpg_tsql/src/string.c b/contrib/babelfishpg_tsql/src/string.c index 4372e51544..40681a5df3 100644 --- a/contrib/babelfishpg_tsql/src/string.c +++ b/contrib/babelfishpg_tsql/src/string.c @@ -34,8 +34,8 @@ PG_FUNCTION_INFO_V1(float_str); /* * Helper functions for float_str() */ -static int round_float_char(char *float_char, int round_pos, int has_neg_sign); -static int find_round_pos(char *float_char, int has_neg_sign, int int_digits, int deci_digits, int input_deci_digits, int input_deci_point, int deci_sig); +static int round_float_char(char *float_char, int round_pos, int has_neg_sign); +static int find_round_pos(char *float_char, int has_neg_sign, int int_digits, int deci_digits, int input_deci_digits, int input_deci_point, int deci_sig); static Datum return_varchar_pointer(char *buf, int size); /* @@ -54,11 +54,11 @@ static Datum return_varchar_pointer(char *buf, int size); Datum hashbytes(PG_FUNCTION_ARGS) { - const char *algorithm = text_to_cstring(PG_GETARG_TEXT_P(0)); - bytea *in = PG_GETARG_BYTEA_PP(1); - size_t len = VARSIZE_ANY_EXHDR(in); - const uint8 *data = (unsigned char*) VARDATA_ANY(in); - bytea *result; + const char *algorithm = text_to_cstring(PG_GETARG_TEXT_P(0)); + bytea *in = PG_GETARG_BYTEA_PP(1); + size_t len = VARSIZE_ANY_EXHDR(in); + const uint8 *data = (unsigned char *) VARDATA_ANY(in); + bytea *result; if (strcasecmp(algorithm, "MD2") == 0) { @@ -70,9 +70,9 @@ hashbytes(PG_FUNCTION_ARGS) } else if (strcasecmp(algorithm, "MD5") == 0) { - unsigned char buf[MD5_RESULTLEN]; - const char *errstr = NULL; - bool success; + unsigned char buf[MD5_RESULTLEN]; + const char *errstr = NULL; + bool success; success = pg_md5_binary(data, len, buf, &errstr); @@ -82,19 +82,21 @@ hashbytes(PG_FUNCTION_ARGS) errmsg("could not compute MD5 encryption: %s", errstr))); result = palloc(sizeof(buf) + VARHDRSZ); + SET_VARSIZE(result, sizeof(buf) + VARHDRSZ); memcpy(VARDATA(result), buf, sizeof(buf)); PG_RETURN_BYTEA_P(result); } else if (strcasecmp(algorithm, "SHA") == 0 || - strcasecmp(algorithm, "SHA1") == 0) + strcasecmp(algorithm, "SHA1") == 0) { unsigned char buf[SHA1_RESULTLEN]; SHA1(data, len, buf); result = palloc(sizeof(buf) + VARHDRSZ); + SET_VARSIZE(result, sizeof(buf) + VARHDRSZ); memcpy(VARDATA(result), buf, sizeof(buf)); @@ -114,6 +116,7 @@ hashbytes(PG_FUNCTION_ARGS) pg_cryptohash_free(ctx); result = palloc(sizeof(buf) + VARHDRSZ); + SET_VARSIZE(result, sizeof(buf) + VARHDRSZ); memcpy(VARDATA(result), buf, sizeof(buf)); @@ -126,6 +129,7 @@ hashbytes(PG_FUNCTION_ARGS) SHA512(data, len, buf); result = palloc(sizeof(buf) + VARHDRSZ); + SET_VARSIZE(result, sizeof(buf) + VARHDRSZ); memcpy(VARDATA(result), buf, sizeof(buf)); @@ -138,7 +142,7 @@ hashbytes(PG_FUNCTION_ARGS) } /* - * Takes in a sysname (nvarchar(128) NOT NULL) + * Takes in a sysname (nvarchar(128) NOT NULL) * * Returns nvarchar * @@ -150,20 +154,23 @@ quotename(PG_FUNCTION_ARGS) const char *input_string = text_to_cstring(PG_GETARG_TEXT_P(0)); const char *delimiter = text_to_cstring(PG_GETARG_TEXT_P(1)); - char left_delim; - char right_delim; - char *buf; - int buf_i = 0; + char left_delim; + char right_delim; + char *buf; + int buf_i = 0; /* Validate input len */ - if (strlen(input_string) > 128) { + if (strlen(input_string) > 128) + { PG_RETURN_NULL(); } - if (strlen(delimiter) != 1) { + if (strlen(delimiter) != 1) + { PG_RETURN_NULL(); } - switch (*delimiter) { + switch (*delimiter) + { case ']': case '[': left_delim = '['; @@ -196,14 +203,16 @@ quotename(PG_FUNCTION_ARGS) /* Input size is max 128, so output max is 128 * 2 + 2 (for delimiters) */ buf = palloc(258 * sizeof(char)); - memset(buf, 0, 258 * sizeof (char)); + memset(buf, 0, 258 * sizeof(char)); + - /* Process input string to include escape characters */ buf[buf_i++] = left_delim; - for (int i = 0; i < strlen(input_string); i++) { - switch (input_string[i]) { - /* Escape chars */ + for (int i = 0; i < strlen(input_string); i++) + { + switch (input_string[i]) + { + /* Escape chars */ case '\'': case ']': case '"': @@ -216,7 +225,7 @@ quotename(PG_FUNCTION_ARGS) } buf[buf_i++] = right_delim; - return return_varchar_pointer(buf, buf_i); + return return_varchar_pointer(buf, buf_i); } Datum @@ -224,11 +233,11 @@ string_escape(PG_FUNCTION_ARGS) { const char *str = text_to_cstring(PG_GETARG_TEXT_P(0)); const char *type = text_to_cstring(PG_GETARG_TEXT_P(1)); - + StringInfoData buf; - int text_len = strlen(str); + int text_len = strlen(str); - if (strcmp(type, "json")) + if (strcmp(type, "json")) { PG_RETURN_NULL(); } @@ -242,36 +251,36 @@ string_escape(PG_FUNCTION_ARGS) for (int i = 0; i < text_len; i++) { - switch(str[i]) + switch (str[i]) { - case 8: /* Backspace */ + case 8: /* Backspace */ appendStringInfoString(&buf, "\\b"); break; - case 9: /* Horizontal tab */ + case 9: /* Horizontal tab */ appendStringInfoString(&buf, "\\t"); break; - case 10: /* New line */ + case 10: /* New line */ appendStringInfoString(&buf, "\\n"); break; - case 12: /* Form feed */ + case 12: /* Form feed */ appendStringInfoString(&buf, "\\f"); break; - case 13: /* Carriage return */ + case 13: /* Carriage return */ appendStringInfoString(&buf, "\\r"); break; case '\"': appendStringInfoString(&buf, "\\\""); break; - case '/': + case '/': appendStringInfoString(&buf, "\\/"); break; - case '\\': + case '\\': appendStringInfoString(&buf, "\\\\"); break; default: if (str[i] < 32) { - appendStringInfo(&buf, "\\u00%02x", (unsigned char)(str[i])); + appendStringInfo(&buf, "\\u00%02x", (unsigned char) (str[i])); } else { @@ -279,26 +288,26 @@ string_escape(PG_FUNCTION_ARGS) } } } - - return return_varchar_pointer(buf.data, buf.len); + + return return_varchar_pointer(buf.data, buf.len); } /* * The default format() function implemented in Postgres doesn't cover some - * of the more exotic number formats, such as %i, %o, %u, and %x. There are + * of the more exotic number formats, such as %i, %o, %u, and %x. There are * also TSQL specific implementation details for FORMATMESSAGE, such as NULL * handling and escape sequences that differ from the default as well.. - * + * */ Datum formatmessage(PG_FUNCTION_ARGS) { - char *msg_string; - int nargs = PG_NARGS() - 1; - Datum *args; - Oid *argtypes; - bool *argisnull; - StringInfoData buf; + char *msg_string; + int nargs = PG_NARGS() - 1; + Datum *args; + Oid *argtypes; + bool *argisnull; + StringInfoData buf; if (nargs > 20) { @@ -324,30 +333,33 @@ formatmessage(PG_FUNCTION_ARGS) initStringInfo(&buf); prepare_format_string(&buf, msg_string, nargs, args, argtypes, argisnull); - return return_varchar_pointer(buf.data, buf.len); + return return_varchar_pointer(buf.data, buf.len); } /* * Constructs a formatted string with provided format and arguments. */ void -prepare_format_string(StringInfo buf, char *msg_string, int nargs, +prepare_format_string(StringInfo buf, char *msg_string, int nargs, Datum *args, Oid *argtypes, bool *argisnull) { - int i = 0; + int i = 0; - size_t prev_fmt_seg_sz = TSQL_MAX_MESSAGE_LEN + 1; - size_t seg_len = 0; + size_t prev_fmt_seg_sz = TSQL_MAX_MESSAGE_LEN + 1; + size_t seg_len = 0; - char *seg_start, *seg_end, *arg_str, *fmt_seg; - char placeholder; + char *seg_start, + *seg_end, + *arg_str, + *fmt_seg; + char placeholder; - Oid prev_type = 0; - Oid typid; - TYPCATEGORY type; - Datum arg; + Oid prev_type = 0; + Oid typid; + TYPCATEGORY type; + Datum arg; - FmgrInfo typoutputfinfo; + FmgrInfo typoutputfinfo; fmt_seg = palloc((TSQL_MAX_MESSAGE_LEN + 1) * sizeof(char)); memset(fmt_seg, 0, (TSQL_MAX_MESSAGE_LEN + 1) * sizeof(char)); @@ -369,7 +381,7 @@ prepare_format_string(StringInfo buf, char *msg_string, int nargs, appendBinaryStringInfoNT(buf, seg_start, seg_len); while (seg_end != NULL && buf->len <= TSQL_MAX_MESSAGE_LEN) - { + { seg_start = seg_end; seg_end = strchr(seg_start + 1, '%'); @@ -386,15 +398,15 @@ prepare_format_string(StringInfo buf, char *msg_string, int nargs, seg_len = TSQL_MAX_MESSAGE_LEN + 1; } placeholder = seg_start[1]; - + if (strchr("diouxXs", placeholder) != NULL) { /* Valid placeholder */ - + memset(fmt_seg, 0, prev_fmt_seg_sz); strncpy(fmt_seg, seg_start, seg_len); prev_fmt_seg_sz = seg_len; - + arg = args[i]; if (i >= nargs || argisnull[i]) @@ -411,17 +423,18 @@ prepare_format_string(StringInfo buf, char *msg_string, int nargs, { Oid typoutputfunc; bool typIsVarlena; + getTypeOutputInfo(typid, &typoutputfunc, &typIsVarlena); fmgr_info(typoutputfunc, &typoutputfinfo); prev_type = typid; } - switch(type) + switch (type) { case TYPCATEGORY_STRING: case TYPCATEGORY_UNKNOWN: if (placeholder != 's') - ereport(ERROR, + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Param %d expected format type %s but received type %s", i + 1, fmt_seg, format_type_be(typid)))); @@ -434,7 +447,7 @@ prepare_format_string(StringInfo buf, char *msg_string, int nargs, break; case TYPCATEGORY_NUMERIC: if (placeholder == 's') - ereport(ERROR, + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Param %d expected format type %s but received type %s", i + 1, fmt_seg, format_type_be(typid)))); @@ -442,8 +455,8 @@ prepare_format_string(StringInfo buf, char *msg_string, int nargs, break; default: ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("Unsupported type with type %s", format_type_be(typid)))); + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Unsupported type with type %s", format_type_be(typid)))); } i++; @@ -452,8 +465,8 @@ prepare_format_string(StringInfo buf, char *msg_string, int nargs, { /* Invalid placeholder, throw an error */ ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("Invalid format specification: %s", seg_start))); + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Invalid format specification: %s", seg_start))); } } if (seg_end != NULL) @@ -464,14 +477,14 @@ prepare_format_string(StringInfo buf, char *msg_string, int nargs, if (buf->len > TSQL_MAX_MESSAGE_LEN) { - // Trim buf to be 2044, truncate with ... + /* Trim buf to be 2044, truncate with ... */ for (int i = TSQL_MAX_MESSAGE_LEN - 3; i < TSQL_MAX_MESSAGE_LEN; i++) { buf->data[i] = '.'; } buf->len = TSQL_MAX_MESSAGE_LEN; } - + buf->data[buf->len] = '\0'; pfree(fmt_seg); @@ -486,303 +499,359 @@ tsql_varchar_substr(PG_FUNCTION_ARGS) { if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2)) PG_RETURN_NULL(); - - PG_RETURN_VARCHAR_P(DirectFunctionCall3(text_substr,PG_GETARG_DATUM(0), - PG_GETARG_INT32(1), - PG_GETARG_INT32(2))); + + PG_RETURN_VARCHAR_P(DirectFunctionCall3(text_substr, PG_GETARG_DATUM(0), + PG_GETARG_INT32(1), + PG_GETARG_INT32(2))); } /* - * Returns character data converted from numeric data. The character data + * Returns character data converted from numeric data. The character data * is right-justified, with a specified length and decimal precision. */ Datum float_str(PG_FUNCTION_ARGS) { - Numeric float_numeric; - int precision; - char *float_char; - int32 length; - int32 decimal; - char *buf; - int size; - char *ptr; - int input_deci_digits; - int has_neg_sign = 0; - int input_deci_point = 0; - int has_deci_point = 0; - int num_spaces = 0; - int int_digits = 0; - int deci_digits = 0; - int int_part_zeros = 0; - int deci_part_zeros = 0; - int deci_sig; - int round_pos = -1; - - if (PG_ARGISNULL(0)) - PG_RETURN_NULL(); - - float_numeric = PG_GETARG_NUMERIC(0); - - if (numeric_is_nan(float_numeric) || numeric_is_inf(float_numeric)) - PG_RETURN_NULL(); - - float_char = DatumGetCString(DirectFunctionCall1(numeric_out, - NumericGetDatum(float_numeric))); - - // precision = num of digits - negative sign - decimal point - precision = strlen(float_char); - - // count number of numeric digits in the numeric input - // find - and . in input - if (strchr(float_char, '-') != NULL) - { - precision--; - has_neg_sign = 1; - } - - if (strchr(float_char, '.') != NULL) - { - precision--; - input_deci_point = 1; - // int_digits is num digits before decimal point (excluding -) - // STR(-1234.56), int_digits = 4 - int_digits = strchr(float_char, '.') - float_char - has_neg_sign; - } - else - { - // no decimal point, all digits are int digits - // STR(123400), int_digits = precision = 6 - int_digits = precision; - } - input_deci_digits = precision - int_digits; - - // max allowed input precision is 38 - if (precision > 38) - ereport(ERROR, - (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("The number '%s' is out of the range for numeric representation (maximum precision 38).", float_char))); - - length = PG_GETARG_INT32(1); - decimal = PG_GETARG_INT32(2); - - if (length <=0 || length > 8000 || decimal < 0) - PG_RETURN_NULL(); - - if (int_digits + has_neg_sign > length) - { - // return string of length filled with * - // STR(-1234, 4), return "****" - buf = palloc(length); - memset(buf, '*', length); - return return_varchar_pointer(buf, length); - } - else if (int_digits > 17) - { - // max precision is 17 so remaining int digits will be padded with zeros - // STR(12345678901234567890, 20), int_part_zeros = 3, will return "12345678901234568000" - int_part_zeros = int_digits - 17; - } - - // calculate num_spaces and deci_part_zeros - size = length + 1; - // allocate buffer for putting result together - buf = palloc(size); - memset(buf, 0, size); - if (has_neg_sign) - length--; - if (decimal > 0 && length > int_digits) - { // result will have decimal part and it will take up 1 space - has_deci_point = 1; - length--; - } - - // update atual max decimal digits in result - // STR(1234.5678, 8, 4), int_digits=4, length=8-1=7, decimal=7-4=3, will return "1234.567" - if (length < (decimal + int_digits)) - decimal = length - int_digits; - - if (decimal > 0) - { // max scale is 16, so actual deci_digits is min(decimal, 16), - // rest of the decimal digits will be disgarded - // STR(0.123456789012345678, 20, 18), decimal=18, deci_digits=16. will return " 0.1234567890123457" - deci_digits = Min(decimal, 16); - } - else - { // no decimal digits - deci_digits = 0; - } - - num_spaces = length - int_digits - deci_digits; - - // comp space for the decimal point - if (has_deci_point && !deci_digits) - { // no enough space for decimal part, remove the decimal point and add one space - // STR(1.234, 2, 1) returns " 1" - num_spaces++; - has_deci_point--; - } - - // max precision is 17, max significant digits in decimal part = min(remaining significant digits, input decimal digits) - deci_sig = Min(Max(17 - int_digits, 0), input_deci_digits); - - // compute deci_part_zeros and update actual deci_sig - if (deci_digits > 0 && length > 17 && deci_digits > deci_sig) - { // total significant digits > 17 and last sig digit in decimal part - // STR(1234567890.1234567890, 22, 20) returns "1234567890.12345670000" - deci_part_zeros = deci_digits - deci_sig; - } - else if (deci_digits > input_deci_digits) - { // decimal digits needed more than input - // STR(1.1234, 8, 6) returns "1.123400", deci_sig = 4, deci_part_zeros = 2 - deci_part_zeros = deci_digits - input_deci_digits; - deci_sig = input_deci_digits; - } - else - { // no zeros in the decimal part - // STR(1.1234, 5, 3) returns "1.123" - deci_sig = deci_digits; - } - - - // set the spaces at the start of the string - if (num_spaces > 0) - memset(buf, ' ', num_spaces); - - - // find if need to round, if round_pos = 0, do not need rounding - round_pos = find_round_pos(float_char, has_neg_sign, int_digits, deci_digits, input_deci_digits, input_deci_point, deci_sig); - - if (round_pos > 0) { - // do rounding - if (round_float_char(float_char, round_pos, has_neg_sign)) - { - if (num_spaces > 0) - { - // one more digits in front of the number, - // set the 1 in buffer and set first digit in float_char to 0 - // STR(-999.9, 6, 0) returns " -1000" - if (has_neg_sign) - { // set '-' after the spaces and increment num_spaces to skip '-' when copying number - memset(buf+num_spaces - 1, '-', 1); - num_spaces++; - } - memset(buf+num_spaces - 1, '1', 1); - memset(float_char, '0', 1); - } - else - { - // not enough space for the carried_over digit, return *** - // the space limitation goes by the one set before the rounding & carried over - // STR(9999.998, 7, 2) returns "*******" but STR(10000.000, 7, 2) returns "10000.0" - // which means the max length constraint of integer part is still 4 after rounding - memset(buf, '*', size - 1); - return return_varchar_pointer(buf, size - 1); - } - } - } - - - // copy the actual number to the buffer after preceding spaces - strncpy(buf+num_spaces, float_char, size - 1 - num_spaces); - - // add decimal point if needed - // STR(4, 3, 1) returns "4.0" - if (has_deci_point && !input_deci_digits) - memset(buf+num_spaces+has_neg_sign+int_digits, '.', 1); - - - // set the zeros - if (deci_part_zeros > 0) - memset(buf + size - deci_part_zeros - 1, '0', deci_part_zeros); - - if (int_part_zeros > 0) - { - if (deci_digits > 0) - { - ptr = strchr(buf, '.'); - memset(ptr - int_part_zeros, '0', int_part_zeros); - } - else - { - memset(buf+ size - int_part_zeros - 1, '0', int_part_zeros); - } - } - - return return_varchar_pointer(buf, size); + Numeric float_numeric; + int precision; + char *float_char; + int32 length; + int32 decimal; + char *buf; + int size; + char *ptr; + int input_deci_digits; + int has_neg_sign = 0; + int input_deci_point = 0; + int has_deci_point = 0; + int num_spaces = 0; + int int_digits = 0; + int deci_digits = 0; + int int_part_zeros = 0; + int deci_part_zeros = 0; + int deci_sig; + int round_pos = -1; + + if (PG_ARGISNULL(0)) + PG_RETURN_NULL(); + + float_numeric = PG_GETARG_NUMERIC(0); + + if (numeric_is_nan(float_numeric) || numeric_is_inf(float_numeric)) + PG_RETURN_NULL(); + + float_char = DatumGetCString(DirectFunctionCall1(numeric_out, + NumericGetDatum(float_numeric))); + + /* precision = num of digits - negative sign - decimal point */ + precision = strlen(float_char); + + /* count number of numeric digits in the numeric input */ + /* find - and . in input */ + if (strchr(float_char, '-') != NULL) + { + precision--; + has_neg_sign = 1; + } + + if (strchr(float_char, '.') != NULL) + { + precision--; + input_deci_point = 1; + /* int_digits is num digits before decimal point (excluding -) */ + /* STR(-1234.56), int_digits = 4 */ + int_digits = strchr(float_char, '.') - float_char - has_neg_sign; + } + else + { + /* no decimal point, all digits are int digits */ + /* STR(123400), int_digits = precision = 6 */ + int_digits = precision; + } + input_deci_digits = precision - int_digits; + + /* max allowed input precision is 38 */ + if (precision > 38) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("The number '%s' is out of the range for numeric representation (maximum precision 38).", float_char))); + + length = PG_GETARG_INT32(1); + decimal = PG_GETARG_INT32(2); + + if (length <= 0 || length > 8000 || decimal < 0) + PG_RETURN_NULL(); + + if (int_digits + has_neg_sign > length) + { + /* return string of length filled with * */ + /* STR(-1234, 4), return "****" */ + buf = palloc(length); + memset(buf, '*', length); + return return_varchar_pointer(buf, length); + } + else if (int_digits > 17) + { + /* + * max precision is 17 so remaining int digits will be padded with + * zeros + */ + /* + * STR(12345678901234567890, 20), int_part_zeros = 3, will return + * "12345678901234568000" + */ + int_part_zeros = int_digits - 17; + } + + /* calculate num_spaces and deci_part_zeros */ + size = length + 1; + /* allocate buffer for putting result together */ + buf = palloc(size); + memset(buf, 0, size); + if (has_neg_sign) + length--; + if (decimal > 0 && length > int_digits) + { + /* result will have decimal part and it will take up 1 space */ + has_deci_point = 1; + length--; + } + + /* update atual max decimal digits in result */ + + /* + * STR(1234.5678, 8, 4), int_digits=4, length=8-1=7, decimal=7-4=3, will + * return "1234.567" + */ + if (length < (decimal + int_digits)) + decimal = length - int_digits; + + if (decimal > 0) + { + /* max scale is 16, so actual deci_digits is min(decimal, 16), */ + /* rest of the decimal digits will be disgarded */ + + /* + * STR(0.123456789012345678, 20, 18), decimal=18, deci_digits=16. will + * return " 0.1234567890123457" + */ + deci_digits = Min(decimal, 16); + } + else + { + /* no decimal digits */ + deci_digits = 0; + } + + num_spaces = length - int_digits - deci_digits; + + /* comp space for the decimal point */ + if (has_deci_point && !deci_digits) + { + /* + * no enough space for decimal part, remove the decimal point and add + * one space. STR(1.234, 2, 1) returns " 1" + */ + num_spaces++; + has_deci_point--; + } + + /* + * max precision is 17, max significant digits in decimal part = + * min(remaining significant digits, input decimal digits) + */ + deci_sig = Min(Max(17 - int_digits, 0), input_deci_digits); + + /* compute deci_part_zeros and update actual deci_sig */ + if (deci_digits > 0 && length > 17 && deci_digits > deci_sig) + { + /* total significant digits > 17 and last sig digit in decimal part */ + /* STR(1234567890.1234567890, 22, 20) returns "1234567890.12345670000" */ + deci_part_zeros = deci_digits - deci_sig; + } + else if (deci_digits > input_deci_digits) + { + /* decimal digits needed more than input */ + + /* + * STR(1.1234, 8, 6) returns "1.123400", deci_sig = 4, deci_part_zeros + * = 2 + */ + deci_part_zeros = deci_digits - input_deci_digits; + deci_sig = input_deci_digits; + } + else + { + /* no zeros in the decimal part */ + /* STR(1.1234, 5, 3) returns "1.123" */ + deci_sig = deci_digits; + } + + + /* set the spaces at the start of the string */ + if (num_spaces > 0) + memset(buf, ' ', num_spaces); + + + /* find if need to round, if round_pos = 0, do not need rounding */ + round_pos = find_round_pos(float_char, has_neg_sign, int_digits, deci_digits, input_deci_digits, input_deci_point, deci_sig); + + if (round_pos > 0) + { + /* do rounding */ + if (round_float_char(float_char, round_pos, has_neg_sign)) + { + if (num_spaces > 0) + { + /* one more digits in front of the number, */ + /* set the 1 in buffer and set first digit in float_char to 0 */ + /* STR(-999.9, 6, 0) returns " -1000" */ + if (has_neg_sign) + { + /* + * set '-' after the spaces and increment num_spaces to + * skip '-' when copying number + */ + memset(buf + num_spaces - 1, '-', 1); + num_spaces++; + } + memset(buf + num_spaces - 1, '1', 1); + memset(float_char, '0', 1); + } + else + { + /* not enough space for the carried_over digit, return *** */ + /* + * the space limitation goes by the one set before the + * rounding & carried over + */ + /* + * STR(9999.998, 7, 2) returns "*******" but STR(10000.000, 7, + * 2) returns "10000.0" + */ + /* + * which means the max length constraint of integer part is + * still 4 after rounding + */ + memset(buf, '*', size - 1); + return return_varchar_pointer(buf, size - 1); + } + } + } + + + /* copy the actual number to the buffer after preceding spaces */ + strncpy(buf + num_spaces, float_char, size - 1 - num_spaces); + + /* add decimal point if needed */ + /* STR(4, 3, 1) returns "4.0" */ + if (has_deci_point && !input_deci_digits) + memset(buf + num_spaces + has_neg_sign + int_digits, '.', 1); + + + /* set the zeros */ + if (deci_part_zeros > 0) + memset(buf + size - deci_part_zeros - 1, '0', deci_part_zeros); + + if (int_part_zeros > 0) + { + if (deci_digits > 0) + { + ptr = strchr(buf, '.'); + memset(ptr - int_part_zeros, '0', int_part_zeros); + } + else + { + memset(buf + size - int_part_zeros - 1, '0', int_part_zeros); + } + } + + return return_varchar_pointer(buf, size); } /* * Find the rounding position of the float_char input using the constraints - * returns the rounding position + * returns the rounding position */ static int find_round_pos(char *float_char, int has_neg_sign, int int_digits, int deci_digits, int input_deci_digits, int input_deci_point, int deci_sig) { - int round_pos = 0; - int curr_digit; - - if (int_digits + input_deci_digits > 17) - { - // exceeds the max precision, need to round to 17th digit(excluding - and .) - if (int_digits > 17) - { // round in int part - // STR(12345678901234567890, 20) returns "1234567890123456800" - curr_digit = float_char[17 + has_neg_sign] - '0'; - if (curr_digit >= 5) - round_pos = 16 + has_neg_sign; - } - else - { // round in decimal part - // STR(1234567890.1234567890, 22, 20) returns "1234567890.12345670000" - curr_digit = float_char[17 + has_neg_sign + input_deci_point] - '0'; - if (curr_digit >= 5) - round_pos = 16 + has_neg_sign + input_deci_point; - } - } - else if (deci_digits && input_deci_digits > deci_sig) - { - // input decimal digits > needed, round to last output decimal digit - // STR(-1.123456, 8, 5) retuns "-1.12346" - curr_digit = float_char[has_neg_sign + int_digits + input_deci_point + deci_sig] - '0'; - if (curr_digit >= 5) - round_pos = has_neg_sign + int_digits + input_deci_point + deci_sig - 1; - } - else if (!deci_sig && input_deci_digits) - { - // int part == length and has deci digit input, round to integer - // STR(-1234.9, 5, 1) returns "-1235" - curr_digit = float_char[has_neg_sign + int_digits + 1] - '0'; - if (curr_digit >= 5) - round_pos = has_neg_sign + int_digits - 1; // last digit of integer - } - - return round_pos; + int round_pos = 0; + int curr_digit; + + if (int_digits + input_deci_digits > 17) + { + /* + * exceeds the max precision, need to round to 17th digit(excluding - + * and .) + */ + if (int_digits > 17) + { + /* round in int part */ + /* STR(12345678901234567890, 20) returns "1234567890123456800" */ + curr_digit = float_char[17 + has_neg_sign] - '0'; + + if (curr_digit >= 5) + round_pos = 16 + has_neg_sign; + } + else + { + /* round in decimal part */ + + /* + * STR(1234567890.1234567890, 22, 20) returns + * "1234567890.12345670000" + */ + curr_digit = float_char[17 + has_neg_sign + input_deci_point] - '0'; + if (curr_digit >= 5) + round_pos = 16 + has_neg_sign + input_deci_point; + } + } + else if (deci_digits && input_deci_digits > deci_sig) + { + /* input decimal digits > needed, round to last output decimal digit */ + /* STR(-1.123456, 8, 5) retuns "-1.12346" */ + curr_digit = float_char[has_neg_sign + int_digits + input_deci_point + deci_sig] - '0'; + if (curr_digit >= 5) + round_pos = has_neg_sign + int_digits + input_deci_point + deci_sig - 1; + } + else if (!deci_sig && input_deci_digits) + { + /* int part == length and has deci digit input, round to integer */ + /* STR(-1234.9, 5, 1) returns "-1235" */ + curr_digit = float_char[has_neg_sign + int_digits + 1] - '0'; + if (curr_digit >= 5) + round_pos = has_neg_sign + int_digits - 1; + /* last digit of integer */ + } + + return round_pos; } /* * Inplace round the float_char to the digit at round_pos, returns the final carried over digit */ -static int +static int round_float_char(char *float_char, int round_pos, int has_neg_sign) { - int curr_digit; - int carry = 1; - - while (round_pos > (0 + has_neg_sign) && carry) - { - if (float_char[round_pos] == '.') - { - round_pos--; - continue; - } - curr_digit = float_char[round_pos] - '0' + carry; - carry = curr_digit / 10; - memset(float_char+round_pos, '0' + curr_digit % 10, 1); // update the curr digit - round_pos--; - } - - return carry; + int curr_digit; + int carry = 1; + + while (round_pos > (0 + has_neg_sign) && carry) + { + if (float_char[round_pos] == '.') + { + round_pos--; + continue; + } + curr_digit = float_char[round_pos] - '0' + carry; + carry = curr_digit / 10; + memset(float_char + round_pos, '0' + curr_digit % 10, 1); + /* update the curr digit */ + round_pos--; + } + + return carry; } /* @@ -790,11 +859,12 @@ round_float_char(char *float_char, int round_pos, int has_neg_sign) * returns the Varchar * */ static Datum -return_varchar_pointer(char *buf, int size) -{ - VarChar *result; - - result = (*common_utility_plugin_ptr->tsql_varchar_input)(buf, size, -1); - pfree(buf); - PG_RETURN_VARCHAR_P(result); -} \ No newline at end of file +return_varchar_pointer(char *buf, int size) +{ + VarChar *result; + + result = (*common_utility_plugin_ptr->tsql_varchar_input) (buf, size, -1); + + pfree(buf); + PG_RETURN_VARCHAR_P(result); +} diff --git a/contrib/babelfishpg_tsql/src/tablecmds.c b/contrib/babelfishpg_tsql/src/tablecmds.c index b131cc3639..ef640ca358 100644 --- a/contrib/babelfishpg_tsql/src/tablecmds.c +++ b/contrib/babelfishpg_tsql/src/tablecmds.c @@ -40,136 +40,150 @@ #include "catalog.h" #include "hooks.h" -const char* ATTOPTION_BBF_ORIGINAL_NAME = "bbf_original_name"; -const char* ATTOPTION_BBF_ORIGINAL_TABLE_NAME = "bbf_original_rel_name"; -const char* ATTOPTION_BBF_TABLE_CREATE_DATE = "bbf_rel_create_date"; +const char *ATTOPTION_BBF_ORIGINAL_NAME = "bbf_original_name"; +const char *ATTOPTION_BBF_ORIGINAL_TABLE_NAME = "bbf_original_rel_name"; +const char *ATTOPTION_BBF_TABLE_CREATE_DATE = "bbf_rel_create_date"; typedef struct ComputedColumnContextData { Relation rel; - ParseState *pstate; - List *gen_column_list; + ParseState *pstate; + List *gen_column_list; } ComputedColumnContextData; typedef ComputedColumnContextData *ComputedColumnContext; -void assign_object_access_hook_drop_relation(void); -void uninstall_object_access_hook_drop_relation(void); -static void lookup_and_drop_triggers(ObjectAccessType access, Oid classId, - Oid relOid, int subId, void *arg); -void assign_tablecmds_hook(void); +void assign_object_access_hook_drop_relation(void); +void uninstall_object_access_hook_drop_relation(void); +static void lookup_and_drop_triggers(ObjectAccessType access, Oid classId, + Oid relOid, int subId, void *arg); +void assign_tablecmds_hook(void); static void pltsql_PreDropColumnHook(Relation rel, AttrNumber attnum); static void pltsql_PreAddConstraintsHook(Relation rel, ParseState *pstate, List *newColDefaults); static bool checkAllowedTsqlAttoptions(Node *options); + /* Hook to tablecmds.c in the engine */ static object_access_hook_type prev_object_access_hook = NULL; static InvokePreDropColumnHook_type prev_InvokePreDropColumnHook = NULL; static InvokePreAddConstraintsHook_type prev_InvokePreAddConstraintsHook = NULL; -void pre_check_trigger_schema(List *object, bool missing_ok); +void pre_check_trigger_schema(List *object, bool missing_ok); -void pre_check_trigger_schema(List *object, bool missing_ok){ - const char *depname; - Oid trigger_rel_oid = InvalidOid; - const char *tsql_trigger_logical_schema = NULL; +void +pre_check_trigger_schema(List *object, bool missing_ok) +{ + const char *depname; + Oid trigger_rel_oid = InvalidOid; + const char *tsql_trigger_logical_schema = NULL; /* Extract name of dependent object. */ depname = strVal(llast(object)); - if (list_length(object) > 1){ - tsql_trigger_logical_schema = ((String *)linitial(object))->sval; + if (list_length(object) > 1) + { + tsql_trigger_logical_schema = ((String *) linitial(object))->sval; } - trigger_rel_oid = get_tsql_trigger_oid(object,depname,true); - + trigger_rel_oid = get_tsql_trigger_oid(object, depname, true); + if (!missing_ok && !OidIsValid(trigger_rel_oid)) { - if(list_length(object) == 1){ + if (list_length(object) == 1) + { ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("trigger \"%s\" does not exist", - depname))); - }else{ + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("trigger \"%s\" does not exist", + depname))); + } + else + { ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("trigger \"%s.%s\" does not exist", - tsql_trigger_logical_schema ,depname))); - } + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("trigger \"%s.%s\" does not exist", + tsql_trigger_logical_schema, depname))); + } } } -static void lookup_and_drop_triggers(ObjectAccessType access, Oid classId, - Oid relOid, int subId, void *arg) +static void +lookup_and_drop_triggers(ObjectAccessType access, Oid classId, + Oid relOid, int subId, void *arg) { - Relation tgrel; - ScanKeyData key; + Relation tgrel; + ScanKeyData key; SysScanDesc tgscan; HeapTuple tuple; - DropBehavior behavior = DROP_CASCADE; - ObjectAddress trigAddress; - Relation trigRelation; - List *trigobjlist; - char * trig_physical_schema; - - /* Call previous hook if exists */ - if (prev_object_access_hook) - (*prev_object_access_hook) (access, classId, relOid, subId, arg); - - /* babelfishpg_tsql extension is loaded does not mean dialect is necessarily tsql */ - if (sql_dialect != SQL_DIALECT_TSQL) - return; - - /* We only want to execute this function for the DROP TABLE case */ - if (classId != RelationRelationId || access != OAT_DROP) - return; - - /* - * If the relation is a table, we must look for triggers and drop them - * when in the tsql dialect because the user does not create a function for - * the trigger - we create it internally, and so the table cannot be dropped - * if there is a tsql trigger on it because of the dependency of the function. - */ - tgrel = table_open(TriggerRelationId, AccessShareLock); - - ScanKeyInit(&key, - Anum_pg_trigger_tgrelid, - BTEqualStrategyNumber, F_OIDEQ, - relOid); - - tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, false, - NULL, 1, &key); - - while (HeapTupleIsValid(tuple = systable_getnext(tgscan))) - { - Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple); - - if (pg_trigger->tgrelid == relOid && !pg_trigger->tgisinternal) - { - trigRelation = RelationIdGetRelation(relOid); + DropBehavior behavior = DROP_CASCADE; + ObjectAddress trigAddress; + Relation trigRelation; + List *trigobjlist; + char *trig_physical_schema; + + /* Call previous hook if exists */ + if (prev_object_access_hook) + (*prev_object_access_hook) (access, classId, relOid, subId, arg); + + /* + * babelfishpg_tsql extension is loaded does not mean dialect is + * necessarily tsql + */ + if (sql_dialect != SQL_DIALECT_TSQL) + return; + + /* We only want to execute this function for the DROP TABLE case */ + if (classId != RelationRelationId || access != OAT_DROP) + return; + + /* + * If the relation is a table, we must look for triggers and drop them + * when in the tsql dialect because the user does not create a function + * for the trigger - we create it internally, and so the table cannot be + * dropped if there is a tsql trigger on it because of the dependency of + * the function. + */ + tgrel = table_open(TriggerRelationId, AccessShareLock); + + ScanKeyInit(&key, + Anum_pg_trigger_tgrelid, + BTEqualStrategyNumber, F_OIDEQ, + relOid); + + tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, false, + NULL, 1, &key); + + while (HeapTupleIsValid(tuple = systable_getnext(tgscan))) + { + Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple); + + if (pg_trigger->tgrelid == relOid && !pg_trigger->tgisinternal) + { + trigRelation = RelationIdGetRelation(relOid); trig_physical_schema = get_namespace_name(get_rel_namespace(pg_trigger->tgrelid)); - trigobjlist = list_make2(makeString(trig_physical_schema),makeString(NameStr(pg_trigger->tgname))); - trigAddress = (*get_trigger_object_address_hook)(trigobjlist, &trigRelation, true, false); - performDeletion(&trigAddress, behavior, PERFORM_DELETION_INTERNAL); - RelationClose(trigRelation); - } - } - - systable_endscan(tgscan); - table_close(tgrel, AccessShareLock); + trigobjlist = list_make2(makeString(trig_physical_schema), makeString(NameStr(pg_trigger->tgname))); + trigAddress = (*get_trigger_object_address_hook) (trigobjlist, &trigRelation, true, false); + performDeletion(&trigAddress, behavior, PERFORM_DELETION_INTERNAL); + RelationClose(trigRelation); + } + } + + systable_endscan(tgscan); + table_close(tgrel, AccessShareLock); } -void assign_object_access_hook_drop_relation() +void +assign_object_access_hook_drop_relation() { - if (object_access_hook) - { - prev_object_access_hook = object_access_hook; - } + if (object_access_hook) + { + prev_object_access_hook = object_access_hook; + } object_access_hook = lookup_and_drop_triggers; } -void uninstall_object_access_hook_drop_relation() +void +uninstall_object_access_hook_drop_relation() { - if (prev_object_access_hook) - object_access_hook = prev_object_access_hook; + if (prev_object_access_hook) + object_access_hook = prev_object_access_hook; } void @@ -232,7 +246,10 @@ pltsql_PreDropColumnHook(Relation rel, AttrNumber attnum) foundObject.objectId = foundDep->objid; foundObject.objectSubId = foundDep->objsubid; - /* Below logic has been taken from backend's ATExecAlterColumnType function */ + /* + * Below logic has been taken from backend's ATExecAlterColumnType + * function + */ if (getObjectClass(&foundObject) == OCLASS_DEFAULT) { ObjectAddress col = GetAttrDefaultColumnAddress(foundObject.objectId); @@ -242,10 +259,10 @@ pltsql_PreDropColumnHook(Relation rel, AttrNumber attnum) Form_pg_attribute att = TupleDescAttr(rel->rd_att, attnum - 1); /* - * This must be a reference from the expression of a - * generated column elsewhere in the same table. - * Dropping the type of a column that is used by a - * generated column is not allowed by SQL standard. + * This must be a reference from the expression of a generated + * column elsewhere in the same table. Dropping the type of a + * column that is used by a generated column is not allowed by + * SQL standard. */ ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), @@ -269,20 +286,20 @@ check_nested_computed_column(Node *node, void *context) return false; else if (IsA(node, ColumnRef)) { - ColumnRef *cref = (ColumnRef *) node; - ParseState *pstate = ((ComputedColumnContext) context)->pstate; + ColumnRef *cref = (ColumnRef *) node; + ParseState *pstate = ((ComputedColumnContext) context)->pstate; switch (list_length(cref->fields)) { case 1: { - Node *field1 = (Node *) linitial(cref->fields); - List *colList; - char *col1name; + Node *field1 = (Node *) linitial(cref->fields); + List *colList; + char *col1name; ListCell *lc; Relation rel; - colList = ((ComputedColumnContext) context)->gen_column_list; + colList = ((ComputedColumnContext) context)->gen_column_list; rel = ((ComputedColumnContext) context)->rel; Assert(IsA(field1, String)); @@ -290,7 +307,7 @@ check_nested_computed_column(Node *node, void *context) foreach(lc, colList) { - char *col2name = (char *) lfirst(lc); + char *col2name = (char *) lfirst(lc); if (strcmp(col1name, col2name) == 0) ereport(ERROR, @@ -307,8 +324,8 @@ check_nested_computed_column(Node *node, void *context) default: /* - * In CREATE/ALTER TABLE command, the name of the column should have - * only one field. + * In CREATE/ALTER TABLE command, the name of the column + * should have only one field. */ ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), @@ -342,10 +359,9 @@ pltsql_PreAddConstraintsHook(Relation rel, ParseState *pstate, List *newColDefau * For a computed column, datatype is not provided by the user. Hence, * we've to evaluate the computed column expression in order to determine * the datatype. By now, we should've already made an entry for the - * relatio in the catalog, which means we can execute transformExpr on - * the computed column expression. - * Once we determine the datatype of the column, we'll update the - * corresponding entry in the catalog. + * relatio in the catalog, which means we can execute transformExpr on the + * computed column expression. Once we determine the datatype of the + * column, we'll update the corresponding entry in the catalog. */ context = palloc0(sizeof(ComputedColumnContextData)); context->pstate = pstate; @@ -353,13 +369,13 @@ pltsql_PreAddConstraintsHook(Relation rel, ParseState *pstate, List *newColDefau context->gen_column_list = NIL; /* - * Collect the names of all computed columns first. We need this in - * order to detect nested computed columns later. + * Collect the names of all computed columns first. We need this in order + * to detect nested computed columns later. */ foreach(cell, newColDefaults) { - RawColumnDefault *colDef = (RawColumnDefault *) lfirst(cell); - Form_pg_attribute atp = TupleDescAttr(rel->rd_att, colDef->attnum - 1); + RawColumnDefault *colDef = (RawColumnDefault *) lfirst(cell); + Form_pg_attribute atp = TupleDescAttr(rel->rd_att, colDef->attnum - 1); if (!atp->attgenerated) continue; @@ -371,30 +387,28 @@ pltsql_PreAddConstraintsHook(Relation rel, ParseState *pstate, List *newColDefau foreach(cell, newColDefaults) { - RawColumnDefault *colDef = (RawColumnDefault *) lfirst(cell); - Form_pg_attribute atp = TupleDescAttr(rel->rd_att, colDef->attnum - 1); - Node *expr; - Oid targettype; - int32 targettypmod; - HeapTuple heapTup; - Type targetType; - Form_pg_attribute attTup; - Form_pg_type tform; + RawColumnDefault *colDef = (RawColumnDefault *) lfirst(cell); + Form_pg_attribute atp = TupleDescAttr(rel->rd_att, colDef->attnum - 1); + Node *expr; + Oid targettype; + int32 targettypmod; + HeapTuple heapTup; + Type targetType; + Form_pg_attribute attTup; + Form_pg_type tform; /* skip if not a computed column */ if (!atp->attgenerated) continue; /* - * Since we're using a dummy datatype for a computed column, we - * need to check for a nested computed column usage in the - * expression before evaluating the expression through - * transformExpr. - * N.B. When we add a new column through ALTER command, it's - * possible that the expression includes another computed - * column in the table. We'll not be able to detetct that case - * here. That'll be handled later in check_nested_generated - * that works on the executable expression. + * Since we're using a dummy datatype for a computed column, we need + * to check for a nested computed column usage in the expression + * before evaluating the expression through transformExpr. N.B. When + * we add a new column through ALTER command, it's possible that the + * expression includes another computed column in the table. We'll + * not be able to detetct that case here. That'll be handled later in + * check_nested_generated that works on the executable expression. */ Assert(context->gen_column_list != NULL); check_nested_computed_column(colDef->raw_default, context); @@ -429,15 +443,14 @@ pltsql_PreAddConstraintsHook(Relation rel, ParseState *pstate, List *newColDefau attTup->atttypmod = targettypmod; /* - * The target column should already be having a collation - * associated with it due to explicit COLLATE clause - * If suppose collation is not valid or there is no explicit - * COLLATE clause, we try to find column collation from - * finished expession. + * The target column should already be having a collation associated + * with it due to explicit COLLATE clause If suppose collation is not + * valid or there is no explicit COLLATE clause, we try to find column + * collation from finished expession. */ if (!OidIsValid(attTup->attcollation) || !colDef->hasCollClause) { - Oid targetcollid; + Oid targetcollid; /* take care of collations in the finished expression */ assign_expr_collations(pstate, expr); @@ -457,9 +470,9 @@ pltsql_PreAddConstraintsHook(Relation rel, ParseState *pstate, List *newColDefau /* * Instead of invalidating and refetching the relcache entry, just - * update the entry that we've fetched previously. This works - * because no one else can see our in-progress changes. Also note - * that we only updated the fixed part of Form_pg_attribute. + * update the entry that we've fetched previously. This works because + * no one else can see our in-progress changes. Also note that we + * only updated the fixed part of Form_pg_attribute. */ memcpy(atp, attTup, ATTRIBUTE_FIXED_PART_SIZE); @@ -482,23 +495,23 @@ pltsql_PreAddConstraintsHook(Relation rel, ParseState *pstate, List *newColDefau pfree(context); } -static bool checkAllowedTsqlAttoptions(Node *options) +static bool +checkAllowedTsqlAttoptions(Node *options) { if (castNode(List, options) == NIL) return true; - if (strcmp(((DefElem *) linitial(castNode(List, options)))->defname, - ATTOPTION_BBF_ORIGINAL_NAME) == 0) + if (strcmp(((DefElem *) linitial(castNode(List, options)))->defname, + ATTOPTION_BBF_ORIGINAL_NAME) == 0) return true; if (strcmp(((DefElem *) linitial(castNode(List, options)))->defname, - ATTOPTION_BBF_ORIGINAL_TABLE_NAME) == 0) + ATTOPTION_BBF_ORIGINAL_TABLE_NAME) == 0) return true; if (strcmp(((DefElem *) linitial(castNode(List, options)))->defname, - ATTOPTION_BBF_TABLE_CREATE_DATE) == 0) + ATTOPTION_BBF_TABLE_CREATE_DATE) == 0) return true; return false; } - diff --git a/contrib/babelfishpg_tsql/src/tsqlHandler.c b/contrib/babelfishpg_tsql/src/tsqlHandler.c index 41bd513428..64a4aa904f 100644 --- a/contrib/babelfishpg_tsql/src/tsqlHandler.c +++ b/contrib/babelfishpg_tsql/src/tsqlHandler.c @@ -5,14 +5,14 @@ #if 0 PG_MODULE_MAGIC; -void _PG_init(void); +void _PG_init(void); void _PG_init(void) { - /* - * Do initialization here - */ + /* + * Do initialization here + */ } #endif @@ -21,10 +21,10 @@ PG_FUNCTION_INFO_V1(antlr_parser); Datum antlr_parser(PG_FUNCTION_ARGS) { - extern ANTLR_result antlr_parser_cpp(const char *sourceText); - char *sourceText = text_to_cstring(PG_GETARG_TEXT_PP(0)); - - ANTLR_result result = antlr_parser_cpp(sourceText); + extern ANTLR_result antlr_parser_cpp(const char *sourceText); + char *sourceText = text_to_cstring(PG_GETARG_TEXT_PP(0)); - PG_RETURN_TEXT_P(cstring_to_text((result.success ? "success" : result.errfmt))); + ANTLR_result result = antlr_parser_cpp(sourceText); + + PG_RETURN_TEXT_P(cstring_to_text((result.success ? "success" : result.errfmt))); } diff --git a/contrib/babelfishpg_tsql/src/tsqlNodes.c b/contrib/babelfishpg_tsql/src/tsqlNodes.c index 25a19b482e..385a20d725 100644 --- a/contrib/babelfishpg_tsql/src/tsqlNodes.c +++ b/contrib/babelfishpg_tsql/src/tsqlNodes.c @@ -5,37 +5,37 @@ PLtsql_expr * makeTsqlExpr(const char *fragment) { - PLtsql_expr *result = (PLtsql_expr *) palloc0(sizeof(*result)); + PLtsql_expr *result = (PLtsql_expr *) palloc0(sizeof(*result)); - result->query = pstrdup(fragment); - result->plan = NULL; - result->paramnos = NULL; - result->rwparam = -1; - result->ns = pltsql_ns_top(); + result ->query = pstrdup(fragment); + result ->plan = NULL; + result ->paramnos = NULL; + result ->rwparam = -1; + result ->ns = pltsql_ns_top(); - return result; + return result; } PLtsql_stmt_while * makeWhileStmt(PLtsql_expr *cond) { - PLtsql_stmt_while *result = (PLtsql_stmt_while *) palloc0(sizeof(*result)); + PLtsql_stmt_while *result = (PLtsql_stmt_while *) palloc0(sizeof(*result)); - result->cmd_type = PLTSQL_STMT_WHILE; - result->cond = cond; + result ->cmd_type = PLTSQL_STMT_WHILE; + result ->cond = cond; - return result; + return result; } - + PLtsql_stmt_print * makePrintStmt(PLtsql_expr *expr) { - PLtsql_stmt_print *result = (PLtsql_stmt_print *) palloc0(sizeof(*result)); + PLtsql_stmt_print *result = (PLtsql_stmt_print *) palloc0(sizeof(*result)); - result->cmd_type = PLTSQL_STMT_PRINT; - result->exprs = list_make1(expr); + result ->cmd_type = PLTSQL_STMT_PRINT; + result ->exprs = list_make1(expr); - return result; + return result; } diff --git a/contrib/babelfishpg_tsql/src/tsqlNodes.h b/contrib/babelfishpg_tsql/src/tsqlNodes.h index 60bad5a565..2bdc6b4fda 100644 --- a/contrib/babelfishpg_tsql/src/tsqlNodes.h +++ b/contrib/babelfishpg_tsql/src/tsqlNodes.h @@ -5,100 +5,101 @@ #if 0 typedef enum pltsql_stmt_type { - PLTSQL_STMT_BLOCK, - PLTSQL_STMT_ASSIGN, - PLTSQL_STMT_IF, - PLTSQL_STMT_CASE, - PLTSQL_STMT_LOOP, - PLTSQL_STMT_WHILE, - PLTSQL_STMT_FORI, - PLTSQL_STMT_FORS, - PLTSQL_STMT_FORC, - PLTSQL_STMT_FOREACH_A, - PLTSQL_STMT_EXIT, - PLTSQL_STMT_RETURN, - PLTSQL_STMT_RETURN_NEXT, - PLTSQL_STMT_RETURN_QUERY, - PLTSQL_STMT_RAISE, - PLTSQL_STMT_ASSERT, - PLTSQL_STMT_EXECSQL, - PLTSQL_STMT_DYNEXECUTE, - PLTSQL_STMT_DYNFORS, - PLTSQL_STMT_GETDIAG, - PLTSQL_STMT_OPEN, - PLTSQL_STMT_FETCH, - PLTSQL_STMT_CLOSE, - PLTSQL_STMT_PERFORM, - PLTSQL_STMT_CALL, - PLTSQL_STMT_COMMIT, - PLTSQL_STMT_ROLLBACK, - PLTSQL_STMT_SET, - /* TSQL-only statement types follow */ - PLTSQL_STMT_GOTO, - PLTSQL_STMT_PRINT, - PLTSQL_STMT_INIT, - PLTSQL_STMT_SELECT_SET, - PLTSQL_STMT_TRY_CATCH, - PLTSQL_STMT_PUSH_RESULT, - PLTSQL_STMT_EXEC, - PLTSQL_STMT_DECL_TABLE, - PLTSQL_STMT_RETURN_TABLE, - PLTSQL_STMT_EXEC_BATCH, - PLTSQL_STMT_EXEC_SPEXECUTESQL, - PLTSQL_STMT_ASSIGN_CURVAR, - PLTSQL_STMT_DEALLOCATE, - PLTSQL_STMT_INSERT_BULK, - PLTSQL_STMT_GRANTDB + PLTSQL_STMT_BLOCK, + PLTSQL_STMT_ASSIGN, + PLTSQL_STMT_IF, + PLTSQL_STMT_CASE, + PLTSQL_STMT_LOOP, + PLTSQL_STMT_WHILE, + PLTSQL_STMT_FORI, + PLTSQL_STMT_FORS, + PLTSQL_STMT_FORC, + PLTSQL_STMT_FOREACH_A, + PLTSQL_STMT_EXIT, + PLTSQL_STMT_RETURN, + PLTSQL_STMT_RETURN_NEXT, + PLTSQL_STMT_RETURN_QUERY, + PLTSQL_STMT_RAISE, + PLTSQL_STMT_ASSERT, + PLTSQL_STMT_EXECSQL, + PLTSQL_STMT_DYNEXECUTE, + PLTSQL_STMT_DYNFORS, + PLTSQL_STMT_GETDIAG, + PLTSQL_STMT_OPEN, + PLTSQL_STMT_FETCH, + PLTSQL_STMT_CLOSE, + PLTSQL_STMT_PERFORM, + PLTSQL_STMT_CALL, + PLTSQL_STMT_COMMIT, + PLTSQL_STMT_ROLLBACK, + PLTSQL_STMT_SET, + /* TSQL-only statement types follow */ + PLTSQL_STMT_GOTO, + PLTSQL_STMT_PRINT, + PLTSQL_STMT_INIT, + PLTSQL_STMT_SELECT_SET, + PLTSQL_STMT_TRY_CATCH, + PLTSQL_STMT_PUSH_RESULT, + PLTSQL_STMT_EXEC, + PLTSQL_STMT_DECL_TABLE, + PLTSQL_STMT_RETURN_TABLE, + PLTSQL_STMT_EXEC_BATCH, + PLTSQL_STMT_EXEC_SPEXECUTESQL, + PLTSQL_STMT_ASSIGN_CURVAR, + PLTSQL_STMT_DEALLOCATE, + PLTSQL_STMT_INSERT_BULK, + PLTSQL_STMT_GRANTDB } PLtsql_stmt_type; typedef struct PLtsql_expr { - char *query; - SPIPlanPtr plan; - Bitmapset *paramnos; /* all dnos referenced by this query */ - int rwparam; /* dno of read/write param, or -1 if none */ + char *query; + SPIPlanPtr plan; + Bitmapset *paramnos; /* all dnos referenced by this query */ + int rwparam; /* dno of read/write param, or -1 if none */ - /* function containing this expr (not set until we first parse query) */ - struct PLpgSQL_function *func; + /* function containing this expr (not set until we first parse query) */ + struct PLpgSQL_function *func; - /* namespace chain visible to this expr */ - struct PLpgSQL_nsitem *ns; + /* namespace chain visible to this expr */ + struct PLpgSQL_nsitem *ns; - /* fields for "simple expression" fast-path execution: */ - Expr *expr_simple_expr; /* NULL means not a simple expr */ - int expr_simple_generation; /* plancache generation we checked */ - Oid expr_simple_type; /* result type Oid, if simple */ - int32 expr_simple_typmod; /* result typmod, if simple */ + /* fields for "simple expression" fast-path execution: */ + Expr *expr_simple_expr; /* NULL means not a simple expr */ + int expr_simple_generation; /* plancache generation we checked */ + Oid expr_simple_type; /* result type Oid, if simple */ + int32 expr_simple_typmod; /* result typmod, if simple */ - /* - * if expr is simple AND prepared in current transaction, - * expr_simple_state and expr_simple_in_use are valid. Test validity by - * seeing if expr_simple_lxid matches current LXID. (If not, - * expr_simple_state probably points at garbage!) - */ - ExprState *expr_simple_state; /* eval tree for expr_simple_expr */ - bool expr_simple_in_use; /* true if eval tree is active */ - LocalTransactionId expr_simple_lxid; - - /* tsql table variables */ - List *tsql_tablevars; - /* here for itvf? queries with all idents replaced with NULLs */ - char *itvf_query; // make sure always set to NULL + /* + * if expr is simple AND prepared in current transaction, + * expr_simple_state and expr_simple_in_use are valid. Test validity by + * seeing if expr_simple_lxid matches current LXID. (If not, + * expr_simple_state probably points at garbage!) + */ + ExprState *expr_simple_state; /* eval tree for expr_simple_expr */ + bool expr_simple_in_use; /* true if eval tree is active */ + LocalTransactionId expr_simple_lxid; + + /* tsql table variables */ + List *tsql_tablevars; + /* here for itvf? queries with all idents replaced with NULLs */ + char *itvf_query; + /* make sure always set to NULL */ } PLtsql_expr; typedef struct { - PLtsql_stmt_type cmd_type; - int lineno; - PLtsql_expr *cond; - List *then_body; - List *elsif_list; - List *else_body; + PLtsql_stmt_type cmd_type; + int lineno; + PLtsql_expr *cond; + List *then_body; + List *elsif_list; + List *else_body; } PLtsql_stmt_if; -//////////////////////////////////////////////////////////////////////////////// +/* ////////////////////////////////////////////////////////////////////////////// */ #endif -PLtsql_stmt_print * makePrintStmt(PLtsql_expr *expr); +PLtsql_stmt_print *makePrintStmt(PLtsql_expr *expr); PLtsql_expr *makeTsqlExpr(const char *src); PLtsql_stmt_while *makeWhileStmt(PLtsql_expr *expr); diff --git a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.h b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.h deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/contrib/babelfishpg_tsql/src/tsql_analyze.c b/contrib/babelfishpg_tsql/src/tsql_analyze.c index 79ef852dc9..16a431dce9 100644 --- a/contrib/babelfishpg_tsql/src/tsql_analyze.c +++ b/contrib/babelfishpg_tsql/src/tsql_analyze.c @@ -36,39 +36,39 @@ static RangeVar *find_matching_table(RangeVar *target, Node *tblref); RangeVar * pltsql_get_target_table(RangeVar *orig_target, List *fromClause) { - ListCell *lc; + ListCell *lc; if (!orig_target || !fromClause || !IsA(orig_target, RangeVar) || orig_target->alias) return NULL; - + /* - * For each table reference in fromClause, check if the table name or table alias - * name matches the target table. - * If yes, we'll return the table reference. + * For each table reference in fromClause, check if the table name or + * table alias name matches the target table. If yes, we'll return the + * table reference. */ foreach(lc, fromClause) { - Node *n = lfirst(lc); - RangeVar *rv = find_matching_table(orig_target, n); + Node *n = lfirst(lc); + RangeVar *rv = find_matching_table(orig_target, n); if (rv) return rv; } - + return NULL; } static RangeVar * find_matching_table(RangeVar *target, Node *tblref) { - /* - * If the table refenrence is a JoinExpr, recursively check the - * join tree's left child and right child. - */ + /* + * If the table refenrence is a JoinExpr, recursively check the join + * tree's left child and right child. + */ if (IsA(tblref, JoinExpr)) { - JoinExpr *je = (JoinExpr *) tblref; - RangeVar *rv = NULL; + JoinExpr *je = (JoinExpr *) tblref; + RangeVar *rv = NULL; rv = find_matching_table(target, (Node *) je->larg); @@ -77,23 +77,25 @@ find_matching_table(RangeVar *target, Node *tblref) return rv; } + /* - * If the table reference is an actual table (RangeVar), check if - * the table name or table alias is the same as the target table name. - * Return the matching table if exists. + * If the table reference is an actual table (RangeVar), check if the + * table name or table alias is the same as the target table name. Return + * the matching table if exists. */ else if (IsA(tblref, RangeVar)) { - RangeVar *rv = (RangeVar *) tblref; + RangeVar *rv = (RangeVar *) tblref; + if (pg_strcasecmp(target->relname, rv->relname) == 0) { - if (target->schemaname && + if (target->schemaname && (!rv->schemaname || pg_strcasecmp(target->schemaname, rv->schemaname) != 0)) { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("The objects \"%s.%s\" and \"%s\" in the FROM clause have the same exposed names. " \ - "Use correlation names to distinguish them.", + "Use correlation names to distinguish them.", target->schemaname, target->relname, rv->relname))); } return rv; @@ -103,27 +105,29 @@ find_matching_table(RangeVar *target, Node *tblref) if (target->schemaname) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("The correlation name \'%s\' has the same exposed name as table \'%s.%s\'.", + errmsg("The correlation name \'%s\' has the same exposed name as table \'%s.%s\'.", rv->alias->aliasname, target->schemaname, target->relname))); return rv; } } - /* - * Currently we only consider RangeVar and JoinExpr cases. In the - * future, if there are concrete use cases, we'll add support for - * more table reference types - */ + + /* + * Currently we only consider RangeVar and JoinExpr cases. In the future, + * if there are concrete use cases, we'll add support for more table + * reference types + */ return NULL; } void pltsql_update_query_result_relation(Query *qry, Relation target_rel, List *rtable) { - Oid target_relid = RelationGetRelid(target_rel); + Oid target_relid = RelationGetRelid(target_rel); for (int i = 0; i < list_length(rtable); i++) { RangeTblEntry *rte = (RangeTblEntry *) list_nth(rtable, i); + if (rte->relid == target_relid) { qry->resultRelation = i + 1; @@ -135,21 +139,21 @@ pltsql_update_query_result_relation(Query *qry, Relation target_rel, List *rtabl void handle_rowversion_target_in_update_stmt(RangeVar *target_table, UpdateStmt *stmt) { - Oid relid; - Relation rel; - TupleDesc tupdesc; - AttrNumber attr_num; + Oid relid; + Relation rel; + TupleDesc tupdesc; + AttrNumber attr_num; relid = RangeVarGetRelid(target_table, NoLock, false); rel = RelationIdGetRelation(relid); tupdesc = RelationGetDescr(rel); /* - * If target table contains a rowversion column, add a new ResTarget node - * with a SetToDefault expression into statement's targetList. This will - * ensure that the rows which are going to be updated will have new rowversion - * value. - */ + * If target table contains a rowversion column, add a new ResTarget node + * with a SetToDefault expression into statement's targetList. This will + * ensure that the rows which are going to be updated will have new + * rowversion value. + */ for (attr_num = 0; attr_num < tupdesc->natts; attr_num++) { Form_pg_attribute attr; @@ -159,10 +163,10 @@ handle_rowversion_target_in_update_stmt(RangeVar *target_table, UpdateStmt *stmt if (attr->attisdropped) continue; - if ((*common_utility_plugin_ptr->is_tsql_rowversion_or_timestamp_datatype)(attr->atttypid)) + if ((*common_utility_plugin_ptr->is_tsql_rowversion_or_timestamp_datatype) (attr->atttypid)) { SetToDefault *def = makeNode(SetToDefault); - ResTarget *res; + ResTarget *res; def->typeId = attr->atttypid; def->typeMod = attr->atttypmod; @@ -171,7 +175,7 @@ handle_rowversion_target_in_update_stmt(RangeVar *target_table, UpdateStmt *stmt res->name = pstrdup(NameStr(attr->attname)); res->name_location = -1; res->indirection = NIL; - res->val = (Node *)def; + res->val = (Node *) def; res->location = -1; stmt->targetList = lappend(stmt->targetList, res); break; @@ -184,22 +188,26 @@ handle_rowversion_target_in_update_stmt(RangeVar *target_table, UpdateStmt *stmt static bool search_join_recursive(Node *expr, RangeVar *target, bool outside_outer) { - JoinExpr *join_expr; - RangeVar *arg; + JoinExpr *join_expr; + RangeVar *arg; if (!expr) return false; - else if (IsA(expr, RangeVar)) // Base condition + else if (IsA(expr, RangeVar)) + /* Base condition */ { - arg = (RangeVar *)expr; + arg = (RangeVar *) expr; return outside_outer && strcmp(arg->relname, target->relname) == 0; } - else if(!IsA(expr, JoinExpr)) + else if (!IsA(expr, JoinExpr)) return false; join_expr = (JoinExpr *) expr; - // Check if 'target' is on the 'outside' of a join, i.e. right on a left join or left on a right join - switch(join_expr->jointype) + /* + * Check if 'target' is on the 'outside' of a join, i.e. right on a left + * join or left on a right join + */ + switch (join_expr->jointype) { case JOIN_INNER: return search_join_recursive(join_expr->larg, target, outside_outer) @@ -222,23 +230,23 @@ static bool target_in_outer_join(List *fromClause, RangeVar *target) { bool result = false; - ListCell *lc; + ListCell *lc; - foreach (lc, fromClause) + foreach(lc, fromClause) { - Node *node = lfirst(lc); - result |= search_join_recursive(node, target, false); + Node *node = lfirst(lc); + result |=search_join_recursive(node, target, false); } - + return result; } static void add_target_ctid_not_null_clause(Node **where_clause, RangeVar *target) { - NullTest *new_clause; - ColumnRef *col_ref; - char *rel_name = target->relname; + NullTest *new_clause; + ColumnRef *col_ref; + char *rel_name = target->relname; new_clause = makeNode(NullTest); new_clause->nulltesttype = IS_NOT_NULL; @@ -250,19 +258,19 @@ add_target_ctid_not_null_clause(Node **where_clause, RangeVar *target) col_ref = makeNode(ColumnRef); col_ref->location = -1; col_ref->fields = list_make2(makeString(rel_name), makeString("ctid")); - new_clause->arg = (Expr*) col_ref; + new_clause->arg = (Expr *) col_ref; if (!*where_clause) - *where_clause = (Node *)new_clause; + *where_clause = (Node *) new_clause; else { - BoolExpr *bool_expr = makeNode(BoolExpr);; + BoolExpr *bool_expr = makeNode(BoolExpr);; bool_expr->boolop = AND_EXPR; bool_expr->location = -1; bool_expr->args = list_make2(*where_clause, new_clause); - *where_clause = (Node*) bool_expr; + *where_clause = (Node *) bool_expr; } - + } void @@ -271,22 +279,24 @@ rewrite_update_outer_join(Node *stmt, CmdType command, RangeVar *target) switch (command) { case CMD_UPDATE: - { - UpdateStmt *update_stmt = (UpdateStmt *) stmt; - List *fromClause = update_stmt->fromClause; - if (fromClause && target_in_outer_join(fromClause, target)) - add_target_ctid_not_null_clause(&update_stmt->whereClause, target); - break; - } + { + UpdateStmt *update_stmt = (UpdateStmt *) stmt; + List *fromClause = update_stmt->fromClause; + + if (fromClause && target_in_outer_join(fromClause, target)) + add_target_ctid_not_null_clause(&update_stmt->whereClause, target); + break; + } case CMD_DELETE: - { - DeleteStmt *delete_stmt = (DeleteStmt *) stmt; - List *fromClause = delete_stmt->usingClause; - if (fromClause && target_in_outer_join(fromClause, target)) - add_target_ctid_not_null_clause(&delete_stmt->whereClause, target); - break; - } + { + DeleteStmt *delete_stmt = (DeleteStmt *) stmt; + List *fromClause = delete_stmt->usingClause; + + if (fromClause && target_in_outer_join(fromClause, target)) + add_target_ctid_not_null_clause(&delete_stmt->whereClause, target); + break; + } default: return; } -} \ No newline at end of file +} diff --git a/contrib/babelfishpg_tsql/src/tsql_analyze.h b/contrib/babelfishpg_tsql/src/tsql_analyze.h index fd916844b5..dc8819d37d 100644 --- a/contrib/babelfishpg_tsql/src/tsql_analyze.h +++ b/contrib/babelfishpg_tsql/src/tsql_analyze.h @@ -14,4 +14,4 @@ extern void pltsql_update_query_result_relation(Query *qry, Relation target_rel, extern void handle_rowversion_target_in_update_stmt(RangeVar *target_table, UpdateStmt *stmt); extern void rewrite_update_outer_join(Node *stmt, CmdType command, RangeVar *target); -#endif /* TSQL_ANALYZE_H */ +#endif /* TSQL_ANALYZE_H */ diff --git a/contrib/babelfishpg_tsql/src/tsql_for/forjson.c b/contrib/babelfishpg_tsql/src/tsql_for/forjson.c index 6bf719228a..b825037e06 100644 --- a/contrib/babelfishpg_tsql/src/tsql_for/forjson.c +++ b/contrib/babelfishpg_tsql/src/tsql_for/forjson.c @@ -34,19 +34,24 @@ tsql_query_to_json_sfunc(PG_FUNCTION_ARGS) int mode; bool include_null_values; bool without_array_wrapper; - char *root_name; - + char *root_name; + MemoryContext agg_context; MemoryContext old_context; + if (!AggCheckCallContext(fcinfo, &agg_context)) elog(ERROR, "aggregate function called in non-aggregate context"); old_context = MemoryContextSwitchTo(agg_context); - for (int i=1; i < PG_NARGS()-1; i++) + for (int i = 1; i < PG_NARGS() - 1; i++) { - /* only state and root_name can be null, so check the other params for safety */ - if PG_ARGISNULL(i) - PG_RETURN_NULL(); + /* + * only state and root_name can be null, so check the other params for + * safety + */ + if PG_ARGISNULL + (i) + PG_RETURN_NULL(); } record = PG_GETARG_DATUM(1); mode = PG_GETARG_INT32(2); @@ -58,11 +63,15 @@ tsql_query_to_json_sfunc(PG_FUNCTION_ARGS) without_array_wrapper = PG_GETARG_BOOL(4); root_name = PG_ARGISNULL(5) ? NULL : text_to_cstring(PG_GETARG_TEXT_PP(5)); /* If root_name is present then WITHOUT_ARRAY_WRAPPER will be FALSE */ - if(root_name) - /* we need to add an extra token to the beginning so that the finalfunc knows to append "]}" to the end */ + if (root_name) + + /* + * we need to add an extra token to the beginning so that the + * finalfunc knows to append "]}" to the end + */ appendStringInfo(state, "<{\"%s\":[", root_name); else if (!without_array_wrapper) - appendStringInfoChar(state,'['); + appendStringInfoChar(state, '['); } else { @@ -72,14 +81,15 @@ tsql_query_to_json_sfunc(PG_FUNCTION_ARGS) switch (mode) { case TSQL_FORJSON_AUTO: + /* * TODO FOR JSON AUTO: if there are joined tables, we need to know - * which table a particular column came from, but that is currently - * not accessible within the aggregate function. + * which table a particular column came from, but that is + * currently not accessible within the aggregate function. */ ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("AUTO mode is not supported"))); + errmsg("AUTO mode is not supported"))); break; case TSQL_FORJSON_PATH: /* FOR JSON PATH */ /* add the current row to the state */ @@ -89,7 +99,7 @@ tsql_query_to_json_sfunc(PG_FUNCTION_ARGS) /* Invalid mode, should not happen, report internal error */ ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("invalid FOR JSON mode"))); + errmsg("invalid FOR JSON mode"))); } MemoryContextSwitchTo(old_context); @@ -103,15 +113,16 @@ Datum tsql_query_to_json_ffunc(PG_FUNCTION_ARGS) { StringInfo res = makeStringInfo(); - char *state = ((StringInfo) PG_GETARG_POINTER(0))->data; - if (state[0] == '[') /* check for array wrapper */ + char *state = ((StringInfo) PG_GETARG_POINTER(0))->data; + + if (state[0] == '[') /* check for array wrapper */ { appendStringInfoString(res, state); appendStringInfoChar(res, ']'); } - else if (state[0] == '<') /* '<' indicates that root was specified */ + else if (state[0] == '<') /* '<' indicates that root was specified */ { - appendStringInfoString(res, state+1); + appendStringInfoString(res, state + 1); appendStringInfoString(res, "]}"); } else @@ -121,16 +132,16 @@ tsql_query_to_json_ffunc(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(cstring_to_text_with_len(res->data, res->len)); } -static void +static void tsql_row_to_json(StringInfo state, Datum record, bool include_null_values) { HeapTupleHeader td; - Oid tupType; - int32 tupTypmod; - TupleDesc tupdesc; - HeapTupleData tmptup; - HeapTuple tuple; - char *sep=""; + Oid tupType; + int32 tupTypmod; + TupleDesc tupdesc; + HeapTupleData tmptup; + HeapTuple tuple; + char *sep = ""; td = DatumGetHeapTupleHeader(record); @@ -143,54 +154,57 @@ tsql_row_to_json(StringInfo state, Datum record, bool include_null_values) tmptup.t_len = HeapTupleHeaderGetDatumLength(td); tmptup.t_data = td; tuple = &tmptup; - + /* each tuple is its own object */ - appendStringInfoChar(state,'{'); + appendStringInfoChar(state, '{'); /* process the tuple into key/value pairs */ for (int i = 0; i < tupdesc->natts; i++) { - char *colname; - Datum colval; - bool isnull; - Oid datatype_oid; - Oid nspoid; - Oid tsql_datatype_oid; - char *typename; + char *colname; + Datum colval; + bool isnull; + Oid datatype_oid; + Oid nspoid; + Oid tsql_datatype_oid; + char *typename; Form_pg_attribute att = TupleDescAttr(tupdesc, i); if (att->attisdropped) continue; - + colname = NameStr(att->attname); - - if (!strcmp(colname,"\?column\?")) /* When column name or alias is not provided */ + + if (!strcmp(colname, "\?column\?")) /* When column name or alias is + * not provided */ { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("column expressions and data sources without names or aliases cannot be formatted as JSON text using FOR JSON clause. Add alias to the unnamed column or table"))); + errmsg("column expressions and data sources without names or aliases cannot be formatted as JSON text using FOR JSON clause. Add alias to the unnamed column or table"))); } - + colval = heap_getattr(tuple, i + 1, tupdesc, &isnull); if (isnull && !include_null_values) continue; - /* - * Below is a workaround for is_tsql_x_datatype() which does not work as expected. - * We compare the datatype oid of the columns with the tsql_datatype_oid and - * then specially handle some TSQL-specific datatypes. + /* + * Below is a workaround for is_tsql_x_datatype() which does not work + * as expected. We compare the datatype oid of the columns with the + * tsql_datatype_oid and then specially handle some TSQL-specific + * datatypes. */ datatype_oid = att->atttypid; - typename = SPI_gettype(tupdesc, i+1); + typename = SPI_gettype(tupdesc, i + 1); nspoid = get_namespace_oid("sys", true); Assert(nspoid != InvalidOid); tsql_datatype_oid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, CStringGetDatum(typename), ObjectIdGetDatum(nspoid)); - + /* - * tsql_datatype_oid can be different from datatype_oid when there are datatypes in different namespaces - * but with the same name. Examples: bigint, int, etc. + * tsql_datatype_oid can be different from datatype_oid when there are + * datatypes in different namespaces but with the same name. Examples: + * bigint, int, etc. */ if (tsql_datatype_oid == datatype_oid) { @@ -200,38 +214,42 @@ tsql_row_to_json(StringInfo state, Datum record, bool include_null_values) strcmp(typename, "image") == 0 || strcmp(typename, "timestamp") == 0 || strcmp(typename, "rowversion") == 0) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("binary types are not supported with FOR JSON"))); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("binary types are not supported with FOR JSON"))); /* check for bit datatype, and if so, change type to BOOL */ - if (strcmp(typename, "bit") == 0) + if (strcmp(typename, "bit") == 0) { datatype_oid = BOOLOID; } + /* - * convert datetime, smalldatetime, and datetime2 to appropriate text values, - * as T-SQL has a different text conversion than postgres. + * convert datetime, smalldatetime, and datetime2 to appropriate + * text values, as T-SQL has a different text conversion than + * postgres. */ - else if (strcmp(typename, "datetime") == 0 || - strcmp(typename, "smalldatetime") == 0 || - strcmp(typename, "datetime2") == 0) + else if (strcmp(typename, "datetime") == 0 || + strcmp(typename, "smalldatetime") == 0 || + strcmp(typename, "datetime2") == 0) { - char *val = SPI_getvalue(tuple, tupdesc, i+1); - StringInfo format_output = makeStringInfo(); + char *val = SPI_getvalue(tuple, tupdesc, i + 1); + StringInfo format_output = makeStringInfo(); + tsql_for_datetime_format(format_output, val); colval = CStringGetDatum(format_output->data); datatype_oid = CSTRINGOID; } + /* - * datetimeoffset has two behaviors: - * if offset is 0, just return the datetime with 'Z' at the end - * otherwise, append the offset + * datetimeoffset has two behaviors: if offset is 0, just return + * the datetime with 'Z' at the end otherwise, append the offset */ else if (strcmp(typename, "datetimeoffset") == 0) { - char *val = SPI_getvalue(tuple, tupdesc, i+1); - StringInfo format_output = makeStringInfo(); + char *val = SPI_getvalue(tuple, tupdesc, i + 1); + StringInfo format_output = makeStringInfo(); + tsql_for_datetimeoffset_format(format_output, val); colval = CStringGetDatum(format_output->data); @@ -239,19 +257,20 @@ tsql_row_to_json(StringInfo state, Datum record, bool include_null_values) } /* convert money and smallmoney to numeric */ else if (strcmp(typename, "money") == 0 || - strcmp(typename, "smallmoney") == 0) + strcmp(typename, "smallmoney") == 0) { - char *val = SPI_getvalue(tuple, tupdesc, i+1); + char *val = SPI_getvalue(tuple, tupdesc, i + 1); + colval = DirectFunctionCall3(numeric_in, CStringGetDatum(val), ObjectIdGetDatum(InvalidOid), Int32GetDatum(-1)); datatype_oid = NUMERICOID; } } - appendStringInfoString(state,sep); + appendStringInfoString(state, sep); sep = ","; tsql_json_build_object(state, CStringGetDatum(colname), colval, datatype_oid, isnull); } - appendStringInfoChar(state,'}'); + appendStringInfoChar(state, '}'); ReleaseTupleDesc(tupdesc); } diff --git a/contrib/babelfishpg_tsql/src/tsql_for/forjson_old.c b/contrib/babelfishpg_tsql/src/tsql_for/forjson_old.c index b29033b84d..fbdc04a6e0 100644 --- a/contrib/babelfishpg_tsql/src/tsql_for/forjson_old.c +++ b/contrib/babelfishpg_tsql/src/tsql_for/forjson_old.c @@ -2,7 +2,7 @@ * * forjson.c * For JSON clause support for Babel - * + * * This implementation of FOR JSON has been deprecated as of v2.4.0. However, * we cannot remove this implementation, as there may be older views that reference * these functions from prior versions, and we do not want to prevent those @@ -27,7 +27,7 @@ #include "tsql_for.h" static StringInfo tsql_query_to_json_internal(const char *query, int mode, bool include_null_value, - bool without_array_wrapper, const char *root_name); + bool without_array_wrapper, const char *root_name); static void SPI_sql_row_to_json_path(uint64 rownum, StringInfo result, bool include_null_value); static void tsql_unsupported_datatype_check(void); static void for_json_datetime_format(StringInfo format_output, char *outputstr); @@ -36,33 +36,35 @@ static void for_json_datetimeoffset_format(StringInfo format_output, char *outpu PG_FUNCTION_INFO_V1(tsql_query_to_json_text); -Datum +Datum tsql_query_to_json_text(PG_FUNCTION_ARGS) { - char *query; - int mode; - bool include_null_value ; + char *query; + int mode; + bool include_null_value; bool without_array_wrapper; - char *root_name; - StringInfo result; + char *root_name; + StringInfo result; ereport(WARNING, (errcode(ERRCODE_WARNING_DEPRECATED_FEATURE), errmsg("This version of FOR JSON has been deprecated. We recommend recreating the view for this query."))); - for (int i=0; i< PG_NARGS()-1; i++) + for (int i = 0; i < PG_NARGS() - 1; i++) { - if PG_ARGISNULL(i) - PG_RETURN_NULL(); + if PG_ARGISNULL + (i) + PG_RETURN_NULL(); } query = text_to_cstring(PG_GETARG_TEXT_PP(0)); mode = PG_GETARG_INT32(1); include_null_value = PG_GETARG_BOOL(2); without_array_wrapper = PG_GETARG_BOOL(3); - root_name = PG_ARGISNULL(4) ? NULL : text_to_cstring(PG_GETARG_TEXT_PP(4)); + root_name = PG_ARGISNULL(4) ? NULL : text_to_cstring(PG_GETARG_TEXT_PP(4)); result = tsql_query_to_json_internal(query, mode, include_null_value, - without_array_wrapper, root_name); + without_array_wrapper, root_name); + if (result) PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len)); else @@ -78,32 +80,33 @@ static void SPI_sql_row_to_json_path(uint64 rownum, StringInfo result, bool include_null_value) { int i; - const char *sep=""; - bool isnull; + const char *sep = ""; + bool isnull; - appendStringInfoChar(result,'{'); + appendStringInfoChar(result, '{'); for (i = 1; i <= SPI_tuptable->tupdesc->natts; i++) { - char *colname; - Datum colval; - Oid nspoid; - Oid tsql_datatype_oid; - Oid datatype_oid; - char *typename; + char *colname; + Datum colval; + Oid nspoid; + Oid tsql_datatype_oid; + Oid datatype_oid; + char *typename; colname = SPI_fname(SPI_tuptable->tupdesc, i); - if (!strcmp(colname,"\?column\?")) /* When column name or alias is not provided */ + if (!strcmp(colname, "\?column\?")) /* When column name or alias is + * not provided */ { ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("column expressions and data sources without names or aliases cannot be formatted as JSON text using FOR JSON clause. Add alias to the unnamed column or table"))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("column expressions and data sources without names or aliases cannot be formatted as JSON text using FOR JSON clause. Add alias to the unnamed column or table"))); } colval = SPI_getbinval(SPI_tuptable->vals[rownum], SPI_tuptable->tupdesc, i, - &isnull); + &isnull); if (isnull && !include_null_value) continue; @@ -118,32 +121,38 @@ SPI_sql_row_to_json_path(uint64 rownum, StringInfo result, bool include_null_val if (tsql_datatype_oid == datatype_oid) { /* check for bit datatype, and if so, change type to BOOL */ - if (strcmp(typename, "bit") == 0) + if (strcmp(typename, "bit") == 0) { datatype_oid = BOOLOID; } - /* convert datetime, smalldatetime, and datetime2 to appropriate text values, - * as T-SQL has a different text conversion than postgres. + + /* + * convert datetime, smalldatetime, and datetime2 to appropriate + * text values, as T-SQL has a different text conversion than + * postgres. */ - else if (strcmp(typename, "datetime") == 0 || - strcmp(typename, "smalldatetime") == 0 || - strcmp(typename, "datetime2") == 0) + else if (strcmp(typename, "datetime") == 0 || + strcmp(typename, "smalldatetime") == 0 || + strcmp(typename, "datetime2") == 0) { - char *val = SPI_getvalue(SPI_tuptable->vals[rownum], SPI_tuptable->tupdesc, i); - StringInfo format_output = makeStringInfo(); + char *val = SPI_getvalue(SPI_tuptable->vals[rownum], SPI_tuptable->tupdesc, i); + StringInfo format_output = makeStringInfo(); + for_json_datetime_format(format_output, val); colval = CStringGetDatum(format_output->data); datatype_oid = CSTRINGOID; } - /* datetimeoffset has two behaviors: - * if offset is 0, just return the datetime with 'Z' at the end - * otherwise, append the offset + + /* + * datetimeoffset has two behaviors: if offset is 0, just return + * the datetime with 'Z' at the end otherwise, append the offset */ else if (strcmp(typename, "datetimeoffset") == 0) { - char *val = SPI_getvalue(SPI_tuptable->vals[rownum], SPI_tuptable->tupdesc, i); - StringInfo format_output = makeStringInfo(); + char *val = SPI_getvalue(SPI_tuptable->vals[rownum], SPI_tuptable->tupdesc, i); + StringInfo format_output = makeStringInfo(); + for_json_datetimeoffset_format(format_output, val); colval = CStringGetDatum(format_output->data); @@ -151,9 +160,10 @@ SPI_sql_row_to_json_path(uint64 rownum, StringInfo result, bool include_null_val } /* convert money and smallmoney to numeric */ else if (strcmp(typename, "money") == 0 || - strcmp(typename, "smallmoney") == 0) + strcmp(typename, "smallmoney") == 0) { - char *val = SPI_getvalue(SPI_tuptable->vals[rownum], SPI_tuptable->tupdesc, i); + char *val = SPI_getvalue(SPI_tuptable->vals[rownum], SPI_tuptable->tupdesc, i); + colval = DirectFunctionCall3(numeric_in, CStringGetDatum(val), ObjectIdGetDatum(InvalidOid), Int32GetDatum(-1)); datatype_oid = NUMERICOID; } @@ -165,10 +175,10 @@ SPI_sql_row_to_json_path(uint64 rownum, StringInfo result, bool include_null_val tsql_json_build_object(result, CStringGetDatum(colname), colval, datatype_oid, isnull); } - appendStringInfoChar(result,'}'); - if (rownum != SPI_processed-1) + appendStringInfoChar(result, '}'); + if (rownum != SPI_processed - 1) { - appendStringInfoString(result,","); + appendStringInfoString(result, ","); } } @@ -177,10 +187,11 @@ SPI_sql_row_to_json_path(uint64 rownum, StringInfo result, bool include_null_val */ static StringInfo tsql_query_to_json_internal(const char *query, int mode, bool include_null_value, - bool without_array_wrapper, const char *root_name) + bool without_array_wrapper, const char *root_name) { - StringInfo result; + StringInfo result; uint64 i; + set_config_option("babelfishpg_tsql.sql_dialect", "tsql", (superuser() ? PGC_SUSET : PGC_USERSET), PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); @@ -192,28 +203,31 @@ tsql_query_to_json_internal(const char *query, int mode, bool include_null_value (errcode(ERRCODE_DATA_EXCEPTION), errmsg("invalid query"))); - if (SPI_processed==0) + if (SPI_processed == 0) { SPI_finish(); return NULL; } - // To check if query output table has columns with datatypes that are currently not supported in FOR JSON + /* + * To check if query output table has columns with datatypes that are + * currently not supported in FOR JSON + */ tsql_unsupported_datatype_check(); /* If root_name is present then WITHOUT_ARRAY_WRAPPER will be FALSE */ - if(root_name) - appendStringInfo(result, "{\"%s\":[",root_name); + if (root_name) + appendStringInfo(result, "{\"%s\":[", root_name); else if (!without_array_wrapper) - appendStringInfoChar(result,'['); + appendStringInfoChar(result, '['); /* Format the query result according to the mode specified by the query */ switch (mode) { case TSQL_FORJSON_AUTO: /* FOR JSON AUTO */ ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("AUTO mode is not supported"))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("AUTO mode is not supported"))); break; case TSQL_FORJSON_PATH: /* FOR JSON PATH */ for (i = 0; i < SPI_processed; i++) @@ -222,17 +236,17 @@ tsql_query_to_json_internal(const char *query, int mode, bool include_null_value default: /* Invalid mode, should not happen, report internal error */ ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("invalid FOR JSON mode"))); + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("invalid FOR JSON mode"))); } SPI_finish(); - if(root_name) + if (root_name) appendStringInfoString(result, "]}"); else if (!without_array_wrapper) - appendStringInfoChar(result,']'); + appendStringInfoChar(result, ']'); return result; } @@ -244,22 +258,25 @@ tsql_unsupported_datatype_check(void) { for (int i = 1; i <= SPI_tuptable->tupdesc->natts; i++) { - /* - * This part of code is a workaround for is_tsql_x_datatype() which does not work as expected. - * It compares the datatype oid of the columns with the tsql_datatype_oid and - * then throw feature not supported error based on the typename. + /* + * This part of code is a workaround for is_tsql_x_datatype() which + * does not work as expected. It compares the datatype oid of the + * columns with the tsql_datatype_oid and then throw feature not + * supported error based on the typename. */ - Oid tsql_datatype_oid; - Oid datatype_oid = SPI_gettypeid(SPI_tuptable->tupdesc, i); - char* typename = SPI_gettype(SPI_tuptable->tupdesc, i); - Oid nspoid = get_namespace_oid("sys", true); + Oid tsql_datatype_oid; + Oid datatype_oid = SPI_gettypeid(SPI_tuptable->tupdesc, i); + char *typename = SPI_gettype(SPI_tuptable->tupdesc, i); + Oid nspoid = get_namespace_oid("sys", true); + Assert(nspoid != InvalidOid); tsql_datatype_oid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, CStringGetDatum(typename), ObjectIdGetDatum(nspoid)); /* - * tsql_datatype_oid can be different from datatype_oid when there are datatypes in different namespaces - * but with the same name. Examples: bigint, int, etc. + * tsql_datatype_oid can be different from datatype_oid when there are + * datatypes in different namespaces but with the same name. Examples: + * bigint, int, etc. */ if (tsql_datatype_oid == datatype_oid) { @@ -270,7 +287,7 @@ tsql_unsupported_datatype_check(void) strcmp(typename, "rowversion") == 0) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("binary types are not supported with FOR JSON"))); + errmsg("binary types are not supported with FOR JSON"))); } } } @@ -283,9 +300,9 @@ tsql_unsupported_datatype_check(void) static void for_json_datetime_format(StringInfo format_output, char *outputstr) { - char *date; - char *spaceptr = strstr(outputstr, " "); - int len; + char *date; + char *spaceptr = strstr(outputstr, " "); + int len; len = spaceptr - outputstr; date = palloc(len + 1); @@ -305,9 +322,12 @@ for_json_datetime_format(StringInfo format_output, char *outputstr) static void for_json_datetimeoffset_format(StringInfo format_output, char *str) { - char *date, *endptr, *time, *offset; - char *spaceptr = strstr(str, " "); - int len; + char *date, + *endptr, + *time, + *offset; + char *spaceptr = strstr(str, " "); + int len; /* append date part of string */ len = spaceptr - str; diff --git a/contrib/babelfishpg_tsql/src/tsql_for/forxml.c b/contrib/babelfishpg_tsql/src/tsql_for/forxml.c index 8174e23a96..7632679228 100644 --- a/contrib/babelfishpg_tsql/src/tsql_for/forxml.c +++ b/contrib/babelfishpg_tsql/src/tsql_for/forxml.c @@ -25,8 +25,8 @@ #include "tsql_for.h" static StringInfo for_xml_ffunc(PG_FUNCTION_ARGS); -static void tsql_row_to_xml_raw(StringInfo state, Datum record, const char* element_name, bool binary_base64); -static void tsql_row_to_xml_path(StringInfo state, Datum record, const char* element_name, bool binary_base64); +static void tsql_row_to_xml_raw(StringInfo state, Datum record, const char *element_name, bool binary_base64); +static void tsql_row_to_xml_path(StringInfo state, Datum record, const char *element_name, bool binary_base64); static void update_tsql_datatype_and_val(HeapTuple tuple, TupleDesc tupdesc, Oid *datatype_oid, Datum *colval, bool binary_base64, int i); PG_FUNCTION_INFO_V1(tsql_query_to_xml_sfunc); @@ -37,12 +37,13 @@ tsql_query_to_xml_sfunc(PG_FUNCTION_ARGS) StringInfo state; Datum record = PG_GETARG_DATUM(1); int mode = PG_GETARG_INT32(2); - char *element_name = PG_ARGISNULL(3) ? "row" : text_to_cstring(PG_GETARG_TEXT_PP(3)); + char *element_name = PG_ARGISNULL(3) ? "row" : text_to_cstring(PG_GETARG_TEXT_PP(3)); bool binary_base64 = PG_GETARG_BOOL(4); - char *root_name; - + char *root_name; + MemoryContext agg_context; MemoryContext old_context; + if (!AggCheckCallContext(fcinfo, &agg_context)) elog(ERROR, "aggregate function called in non-aggregate context"); old_context = MemoryContextSwitchTo(agg_context); @@ -51,9 +52,13 @@ tsql_query_to_xml_sfunc(PG_FUNCTION_ARGS) { /* first time setup */ state = makeStringInfo(); - root_name = PG_ARGISNULL(5) ? NULL : text_to_cstring(PG_GETARG_TEXT_PP(5)); + root_name = PG_ARGISNULL(5) ? NULL : text_to_cstring(PG_GETARG_TEXT_PP(5)); if (root_name != NULL && strlen(root_name) > 0) - /* we need to add an extra token to the beginning so that the finalfunc knows there is a root element */ + + /* + * we need to add an extra token to the beginning so that the + * finalfunc knows there is a root element + */ appendStringInfo(state, "{<%s>", root_name); } else @@ -62,36 +67,40 @@ tsql_query_to_xml_sfunc(PG_FUNCTION_ARGS) } switch (mode) { - case TSQL_FORXML_RAW: /* FOR XML RAW */ + case TSQL_FORXML_RAW: /* FOR XML RAW */ tsql_row_to_xml_raw(state, record, element_name, binary_base64); break; case TSQL_FORXML_AUTO: + /* - * TODO FOR XML AUTO: element_name should be set to relation name of the attribute - * value being processed, but relation id/name is not provided by aggregate functions. We need to make - * relation id available in aggregate functions in order to support AUTO mode. + * TODO FOR XML AUTO: element_name should be set to relation name + * of the attribute value being processed, but relation id/name is + * not provided by aggregate functions. We need to make relation + * id available in aggregate functions in order to support AUTO + * mode. */ ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("AUTO mode is not supported"))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("AUTO mode is not supported"))); break; - case TSQL_FORXML_PATH: /* FOR XML PATH */ + case TSQL_FORXML_PATH: /* FOR XML PATH */ tsql_row_to_xml_path(state, record, element_name, binary_base64); break; case TSQL_FORXML_EXPLICIT: + /* - * TODO: EXPLICIT mode is quite different from the other mode and is - * not supported yet. + * TODO: EXPLICIT mode is quite different from the other mode and + * is not supported yet. */ ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("EXPLICIT mode is not supported"))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("EXPLICIT mode is not supported"))); break; default: /* Invalid mode, should not happen, report internal error */ ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("invalid FOR XML mode"))); + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("invalid FOR XML mode"))); } MemoryContextSwitchTo(old_context); @@ -104,7 +113,8 @@ PG_FUNCTION_INFO_V1(tsql_query_to_xml_ffunc); Datum tsql_query_to_xml_ffunc(PG_FUNCTION_ARGS) { - StringInfo res = for_xml_ffunc(fcinfo); + StringInfo res = for_xml_ffunc(fcinfo); + PG_RETURN_XML_P((xmltype *) cstring_to_text_with_len(res->data, res->len)); } @@ -113,7 +123,8 @@ PG_FUNCTION_INFO_V1(tsql_query_to_xml_text_ffunc); Datum tsql_query_to_xml_text_ffunc(PG_FUNCTION_ARGS) { - StringInfo res = for_xml_ffunc(fcinfo); + StringInfo res = for_xml_ffunc(fcinfo); + PG_RETURN_TEXT_P(cstring_to_text_with_len(res->data, res->len)); } @@ -121,31 +132,34 @@ static StringInfo for_xml_ffunc(PG_FUNCTION_ARGS) { StringInfo res = makeStringInfo(); - char *state = ((StringInfo) PG_GETARG_POINTER(0))->data; - if (state[0] == '{') /* '{' indicates that root was specified, so add the corresponding end tag */ + char *state = ((StringInfo) PG_GETARG_POINTER(0))->data; + + if (state[0] == '{') /* '{' indicates that root was specified, so + * add the corresponding end tag */ { /* set up regex to match first tag */ - char *pattern = "<([^\\/>]+)[\\/]*>"; - regex_t preg; - regmatch_t match, pmatch[1]; - StringInfoData root; - + char *pattern = "<([^\\/>]+)[\\/]*>"; + regex_t preg; + regmatch_t match, + pmatch[1]; + StringInfoData root; + if (regcomp(&preg, pattern, REG_EXTENDED) != 0) ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("unexpected error parsing xml root tag"))); - + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("unexpected error parsing xml root tag"))); + if (regexec(&preg, state, 1, pmatch, 0) != 0) ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("unexpected error parsing xml root tag"))); - + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("unexpected error parsing xml root tag"))); + match = pmatch[0]; /* we will be bashing the string in state, so copy it into res first */ - appendStringInfoString(res, state+1); + appendStringInfoString(res, state + 1); /* copy the root tag */ - state[match.rm_eo-1] = '\0'; + state[match.rm_eo - 1] = '\0'; initStringInfo(&root); appendStringInfoString(&root, state + match.rm_so + 1); appendStringInfo(res, "", root.data); @@ -161,14 +175,14 @@ for_xml_ffunc(PG_FUNCTION_ARGS) * Map an SQL row to an XML element in RAW mode. */ static void -tsql_row_to_xml_raw(StringInfo state, Datum record, const char* element_name, bool binary_base64) +tsql_row_to_xml_raw(StringInfo state, Datum record, const char *element_name, bool binary_base64) { HeapTupleHeader td; - Oid tupType; - int32 tupTypmod; - TupleDesc tupdesc; - HeapTupleData tmptup; - HeapTuple tuple; + Oid tupType; + int32 tupTypmod; + TupleDesc tupdesc; + HeapTupleData tmptup; + HeapTuple tuple; td = DatumGetHeapTupleHeader(record); @@ -188,10 +202,10 @@ tsql_row_to_xml_raw(StringInfo state, Datum record, const char* element_name, bo /* process the tuple into attributes */ for (int i = 0; i < tupdesc->natts; i++) { - char *colname; - Datum colval; - bool isnull; - Oid datatype_oid; + char *colname; + Datum colval; + bool isnull; + Oid datatype_oid; Form_pg_attribute att = TupleDescAttr(tupdesc, i); if (att->attisdropped) @@ -217,15 +231,15 @@ tsql_row_to_xml_raw(StringInfo state, Datum record, const char* element_name, bo * Map an SQL row to an XML element in PATH mode. */ static void -tsql_row_to_xml_path(StringInfo state, Datum record, const char* element_name, bool binary_base64) +tsql_row_to_xml_path(StringInfo state, Datum record, const char *element_name, bool binary_base64) { HeapTupleHeader td; - Oid tupType; - int32 tupTypmod; - TupleDesc tupdesc; - HeapTupleData tmptup; - HeapTuple tuple; - bool allnull = true; + Oid tupType; + int32 tupTypmod; + TupleDesc tupdesc; + HeapTupleData tmptup; + HeapTuple tuple; + bool allnull = true; td = DatumGetHeapTupleHeader(record); @@ -239,17 +253,21 @@ tsql_row_to_xml_path(StringInfo state, Datum record, const char* element_name, b tmptup.t_data = td; tuple = &tmptup; - /* each tuple is either contained in a "row" tag, or standalone if the element_name is an empty string */ - if (element_name[0] != '\0') // if "''" is the input path, ignore it per SQL Server behavior + /* + * each tuple is either contained in a "row" tag, or standalone if the + * element_name is an empty string + */ + if (element_name[0] != '\0') + /* if "''" is the input path, ignore it per SQL Server behavior */ appendStringInfo(state, "<%s>", element_name); /* process the tuple into tags */ for (int i = 0; i < tupdesc->natts; i++) { - char *colname; - Datum colval; - bool isnull; - Oid datatype_oid; + char *colname; + Datum colval; + bool isnull; + Oid datatype_oid; Form_pg_attribute att = TupleDescAttr(tupdesc, i); if (att->attisdropped) @@ -274,10 +292,11 @@ tsql_row_to_xml_path(StringInfo state, Datum record, const char* element_name, b if (allnull) { /* - * If all the column values are nulls, this element should be , - * modify the already appended to . + * If all the column values are nulls, this element should be + * , modify the already appended to + * . */ - state->data[state->len-1] = '/'; + state->data[state->len - 1] = '/'; appendStringInfoString(state, ">"); } else if (element_name[0] != '\0') @@ -287,60 +306,66 @@ tsql_row_to_xml_path(StringInfo state, Datum record, const char* element_name, b static void update_tsql_datatype_and_val(HeapTuple tuple, TupleDesc tupdesc, Oid *datatype_oid, Datum *colval, bool binary_base64, int i) { - char *typename; - Oid nspoid, tsql_datatype_oid; + char *typename; + Oid nspoid, + tsql_datatype_oid; - /* - * Below is a workaround for is_tsql_x_datatype() which does not work as expected. - * We compare the datatype oid of the columns with the tsql_datatype_oid and - * then specially handle some TSQL-specific datatypes. + /* + * Below is a workaround for is_tsql_x_datatype() which does not work as + * expected. We compare the datatype oid of the columns with the + * tsql_datatype_oid and then specially handle some TSQL-specific + * datatypes. */ - typename = SPI_gettype(tupdesc, i+1); + typename = SPI_gettype(tupdesc, i + 1); nspoid = get_namespace_oid("sys", true); Assert(nspoid != InvalidOid); tsql_datatype_oid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, CStringGetDatum(typename), ObjectIdGetDatum(nspoid)); /* - * tsql_datatype_oid can be different from datatype_oid when there are datatypes in different namespaces - * but with the same name. Examples: bigint, int, etc. + * tsql_datatype_oid can be different from datatype_oid when there are + * datatypes in different namespaces but with the same name. Examples: + * bigint, int, etc. */ if (tsql_datatype_oid == *datatype_oid) { /* binary datatypes are not supported */ if (binary_base64 && (strcmp(typename, "binary") == 0 || - strcmp(typename, "varbinary") == 0 || - strcmp(typename, "image") == 0 || - strcmp(typename, "timestamp") == 0 || - strcmp(typename, "rowversion") == 0)) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("option binary base64 is not supported"))); + strcmp(typename, "varbinary") == 0 || + strcmp(typename, "image") == 0 || + strcmp(typename, "timestamp") == 0 || + strcmp(typename, "rowversion") == 0)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("option binary base64 is not supported"))); + /* - * convert datetime, smalldatetime, and datetime2 to appropriate text values, - * as T-SQL has a different text conversion than postgres. + * convert datetime, smalldatetime, and datetime2 to appropriate text + * values, as T-SQL has a different text conversion than postgres. */ - else if (strcmp(typename, "datetime") == 0 || - strcmp(typename, "smalldatetime") == 0 || - strcmp(typename, "datetime2") == 0) + else if (strcmp(typename, "datetime") == 0 || + strcmp(typename, "smalldatetime") == 0 || + strcmp(typename, "datetime2") == 0) { - char *val = SPI_getvalue(tuple, tupdesc, i+1); - StringInfo format_output = makeStringInfo(); + char *val = SPI_getvalue(tuple, tupdesc, i + 1); + StringInfo format_output = makeStringInfo(); + tsql_for_datetime_format(format_output, val); *colval = CStringGetDatum(format_output->data); *datatype_oid = CSTRINGOID; } + /* - * datetimeoffset has two behaviors: - * if offset is 0, just return the datetime with 'Z' at the end - * otherwise, append the offset + * datetimeoffset has two behaviors: if offset is 0, just return the + * datetime with 'Z' at the end otherwise, append the offset */ else if (strcmp(typename, "datetimeoffset") == 0) { - char *val = SPI_getvalue(tuple, tupdesc, i+1); - StringInfo format_output = makeStringInfo(); + char *val = SPI_getvalue(tuple, tupdesc, i + 1); + StringInfo format_output = makeStringInfo(); + tsql_for_datetimeoffset_format(format_output, val); *colval = CStringGetDatum(format_output->data); diff --git a/contrib/babelfishpg_tsql/src/tsql_for/forxml_old.c b/contrib/babelfishpg_tsql/src/tsql_for/forxml_old.c index 181ef0c9e9..88d3dd08e4 100644 --- a/contrib/babelfishpg_tsql/src/tsql_for/forxml_old.c +++ b/contrib/babelfishpg_tsql/src/tsql_for/forxml_old.c @@ -2,7 +2,7 @@ * * forxml_old.c * For XML clause support for Babel - * + * * This implementation of FOR XML has been deprecated as of v2.4.0. However, * we cannot remove this implementation, as there may be older views that reference * these functions from prior versions, and we do not want to prevent those @@ -25,12 +25,12 @@ static xmltype *stringinfo_to_xmltype(StringInfo buf); static void SPI_sql_row_to_xmlelement_raw(uint64 rownum, StringInfo result, - const char *element_name, bool binary_base64); + const char *element_name, bool binary_base64); static void SPI_sql_row_to_xmlelement_path(uint64 rownum, StringInfo result, - const char* element_name, bool binary_base64); + const char *element_name, bool binary_base64); static StringInfo tsql_query_to_xml_internal(const char *query, int mode, - const char *element_name, bool binary_base64, - const char *root_name); + const char *element_name, bool binary_base64, + const char *root_name); PG_FUNCTION_INFO_V1(tsql_query_to_xml); PG_FUNCTION_INFO_V1(tsql_query_to_xml_text); @@ -44,13 +44,13 @@ stringinfo_to_xmltype(StringInfo buf) Datum tsql_query_to_xml(PG_FUNCTION_ARGS) { - char *query = text_to_cstring(PG_GETARG_TEXT_PP(0)); - int mode = PG_GETARG_INT32(1); - char *element_name = PG_ARGISNULL(2) ? NULL : text_to_cstring(PG_GETARG_TEXT_PP(2)); - bool binary_base64 = PG_GETARG_BOOL(3); - char *root_name = PG_ARGISNULL(4) ? NULL : text_to_cstring(PG_GETARG_TEXT_PP(4)); + char *query = text_to_cstring(PG_GETARG_TEXT_PP(0)); + int mode = PG_GETARG_INT32(1); + char *element_name = PG_ARGISNULL(2) ? NULL : text_to_cstring(PG_GETARG_TEXT_PP(2)); + bool binary_base64 = PG_GETARG_BOOL(3); + char *root_name = PG_ARGISNULL(4) ? NULL : text_to_cstring(PG_GETARG_TEXT_PP(4)); StringInfo result = tsql_query_to_xml_internal(query, mode, - element_name, binary_base64, root_name); + element_name, binary_base64, root_name); ereport(WARNING, (errcode(ERRCODE_WARNING_DEPRECATED_FEATURE), @@ -62,13 +62,13 @@ tsql_query_to_xml(PG_FUNCTION_ARGS) Datum tsql_query_to_xml_text(PG_FUNCTION_ARGS) { - char *query = text_to_cstring(PG_GETARG_TEXT_PP(0)); - int mode = PG_GETARG_INT32(1); - char *element_name = PG_ARGISNULL(2) ? NULL : text_to_cstring(PG_GETARG_TEXT_PP(2)); - bool binary_base64 = PG_GETARG_BOOL(3); - char *root_name = PG_ARGISNULL(4) ? NULL : text_to_cstring(PG_GETARG_TEXT_PP(4)); + char *query = text_to_cstring(PG_GETARG_TEXT_PP(0)); + int mode = PG_GETARG_INT32(1); + char *element_name = PG_ARGISNULL(2) ? NULL : text_to_cstring(PG_GETARG_TEXT_PP(2)); + bool binary_base64 = PG_GETARG_BOOL(3); + char *root_name = PG_ARGISNULL(4) ? NULL : text_to_cstring(PG_GETARG_TEXT_PP(4)); StringInfo result = tsql_query_to_xml_internal(query, mode, - element_name, binary_base64, root_name); + element_name, binary_base64, root_name); ereport(WARNING, (errcode(ERRCODE_WARNING_DEPRECATED_FEATURE), @@ -83,22 +83,23 @@ tsql_query_to_xml_text(PG_FUNCTION_ARGS) */ static void SPI_sql_row_to_xmlelement_raw(uint64 rownum, StringInfo result, - const char* element_name, bool binary_base64) + const char *element_name, bool binary_base64) { int i; if (binary_base64) { /* - * TODO: encode binary/varbinary/image data values using base64 encoding. - * Refer to how BYTEA type is handed in map_sql_value_to_xml_value(). - * Also, pg_b64_encode function might be useful. - * For now report an ERROR if any attribute is binary data type since base64 - * encoding is not implemented yet. + * TODO: encode binary/varbinary/image data values using base64 + * encoding. Refer to how BYTEA type is handed in + * map_sql_value_to_xml_value(). Also, pg_b64_encode function might be + * useful. For now report an ERROR if any attribute is binary data + * type since base64 encoding is not implemented yet. */ for (i = 1; i <= SPI_tuptable->tupdesc->natts; i++) { - char* typename = SPI_gettype(SPI_tuptable->tupdesc, i); + char *typename = SPI_gettype(SPI_tuptable->tupdesc, i); + if (strcmp(typename, "binary") == 0 || strcmp(typename, "varbinary") == 0 || strcmp(typename, "image") == 0) @@ -140,23 +141,24 @@ SPI_sql_row_to_xmlelement_raw(uint64 rownum, StringInfo result, */ static void SPI_sql_row_to_xmlelement_path(uint64 rownum, StringInfo result, - const char* element_name, bool binary_base64) + const char *element_name, bool binary_base64) { - int i; - bool allnull = true; + int i; + bool allnull = true; if (binary_base64) { /* - * TODO: encode binary/varbinary/image data values using base64 encoding. - * Refer to how BYTEA type is handed in map_sql_value_to_xml_value(). - * Also, pg_b64_encode function might be useful. - * For now report an ERROR if any attribute is binary data type since base64 - * encoding is not implemented yet. + * TODO: encode binary/varbinary/image data values using base64 + * encoding. Refer to how BYTEA type is handed in + * map_sql_value_to_xml_value(). Also, pg_b64_encode function might be + * useful. For now report an ERROR if any attribute is binary data + * type since base64 encoding is not implemented yet. */ for (i = 1; i <= SPI_tuptable->tupdesc->natts; i++) { - char* typename = SPI_gettype(SPI_tuptable->tupdesc, i); + char *typename = SPI_gettype(SPI_tuptable->tupdesc, i); + if (strcmp(typename, "binary") == 0 || strcmp(typename, "varbinary") == 0 || strcmp(typename, "image") == 0) @@ -166,7 +168,8 @@ SPI_sql_row_to_xmlelement_path(uint64 rownum, StringInfo result, } } - if (element_name[0] != '\0') // if "''" is the input path, ignore it per SQL Server behavior + if (element_name[0] != '\0') + /* if "''" is the input path, ignore it per SQL Server behavior */ appendStringInfo(result, "<%s>", element_name); for (i = 1; i <= SPI_tuptable->tupdesc->natts; i++) @@ -188,17 +191,19 @@ SPI_sql_row_to_xmlelement_path(uint64 rownum, StringInfo result, colname, map_sql_value_to_xml_value(colval, SPI_gettypeid(SPI_tuptable->tupdesc, i), true), - colname); + colname); } } if (allnull) { /* - * If all the column values are nulls, this element should be , - * modify the already appended to . + * If all the column values are nulls, this element should be + * , modify the already appended to + * . */ - result->data[result->len-1] = '/'; + result ->data[result->len - 1] = '/'; + appendStringInfoString(result, ">"); } else if (element_name[0] != '\0') @@ -207,10 +212,10 @@ SPI_sql_row_to_xmlelement_path(uint64 rownum, StringInfo result, static StringInfo tsql_query_to_xml_internal(const char *query, int mode, - const char *element_name, bool binary_base64, - const char *root_name) + const char *element_name, bool binary_base64, + const char *root_name) { - StringInfo result; + StringInfo result; uint64 i; set_config_option("babelfishpg_tsql.sql_dialect", "tsql", @@ -234,38 +239,41 @@ tsql_query_to_xml_internal(const char *query, int mode, */ switch (mode) { - case TSQL_FORXML_RAW: /* FOR XML RAW */ + case TSQL_FORXML_RAW: /* FOR XML RAW */ for (i = 0; i < SPI_processed; i++) SPI_sql_row_to_xmlelement_raw(i, result, element_name, binary_base64); break; case TSQL_FORXML_AUTO: + /* - * TODO FOR XML AUTO: element_name should be set to relation name of the attribute - * value being processed, but relation id/name is not provided by SPI. We need to make - * relation id available in SPI_tuptable->tupdesc in order to support AUTO mode. + * TODO FOR XML AUTO: element_name should be set to relation name + * of the attribute value being processed, but relation id/name is + * not provided by SPI. We need to make relation id available in + * SPI_tuptable->tupdesc in order to support AUTO mode. */ ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("AUTO mode is not supported"))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("AUTO mode is not supported"))); break; - case TSQL_FORXML_PATH: /* FOR XML PATH */ + case TSQL_FORXML_PATH: /* FOR XML PATH */ for (i = 0; i < SPI_processed; i++) SPI_sql_row_to_xmlelement_path(i, result, element_name, binary_base64); break; case TSQL_FORXML_EXPLICIT: + /* - * TODO: EXPLICIT mode is quite different from the other mode and is - * not supported yet. + * TODO: EXPLICIT mode is quite different from the other mode and + * is not supported yet. */ ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("EXPLICIT mode is not supported"))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("EXPLICIT mode is not supported"))); break; default: /* Invalid mode, should not happen, report internal error */ ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("invalid FOR XML mode"))); + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("invalid FOR XML mode"))); } if (root_name != NULL && strlen(root_name) > 0) diff --git a/contrib/babelfishpg_tsql/src/tsql_for/tsql_for.c b/contrib/babelfishpg_tsql/src/tsql_for/tsql_for.c index 98f59c3023..749c84ad67 100644 --- a/contrib/babelfishpg_tsql/src/tsql_for/tsql_for.c +++ b/contrib/babelfishpg_tsql/src/tsql_for/tsql_for.c @@ -17,9 +17,9 @@ void tsql_for_datetime_format(StringInfo format_output, const char *outputstr) { - char *date; - char *spaceptr = strstr(outputstr, " "); - int len; + char *date; + char *spaceptr = strstr(outputstr, " "); + int len; len = spaceptr - outputstr; date = palloc(len + 1); @@ -39,9 +39,12 @@ tsql_for_datetime_format(StringInfo format_output, const char *outputstr) void tsql_for_datetimeoffset_format(StringInfo format_output, const char *str) { - char *date, *endptr, *time, *offset; - char *spaceptr = strstr(str, " "); - int len; + char *date, + *endptr, + *time, + *offset; + char *spaceptr = strstr(str, " "); + int len; /* append date part of string */ len = spaceptr - str; @@ -59,7 +62,7 @@ tsql_for_datetimeoffset_format(StringInfo format_output, const char *str) strncpy(time, endptr, len); time[len] = '\0'; appendStringInfoString(format_output, time); - + /* append either timezone offset or Z if offset is 0 */ offset = ++spaceptr; if (strcmp(offset, "+00:00") == 0) diff --git a/contrib/babelfishpg_tsql/src/tsql_for/tsql_for.h b/contrib/babelfishpg_tsql/src/tsql_for/tsql_for.h index 7c66d9fd73..1722db60ce 100644 --- a/contrib/babelfishpg_tsql/src/tsql_for/tsql_for.h +++ b/contrib/babelfishpg_tsql/src/tsql_for/tsql_for.h @@ -7,10 +7,10 @@ /* Private struct for the result of tsql_for_clause production */ typedef struct TSQL_ForClause { - int mode; - char *elementName; - List *commonDirectives; - int location; /* token location of FOR, or -1 if unknown */ + int mode; + char *elementName; + List *commonDirectives; + int location; /* token location of FOR, or -1 if unknown */ } TSQL_ForClause; /* Enum declarations to support FOR XML clause */ @@ -20,28 +20,28 @@ typedef enum TSQL_FORXML_AUTO, TSQL_FORXML_PATH, TSQL_FORXML_EXPLICIT -} TSQLFORXMLMode; +} TSQLFORXMLMode; typedef enum { TSQL_XML_DIRECTIVE_BINARY_BASE64, TSQL_XML_DIRECTIVE_TYPE -} TSQLXMLDirective; +} TSQLXMLDirective; /* Enum declarations to support FOR JSON clause */ typedef enum { TSQL_FORJSON_AUTO, TSQL_FORJSON_PATH, -} TSQLFORJSONMode; +} TSQLFORJSONMode; typedef enum { TSQL_JSON_DIRECTIVE_INCLUDE_NULL_VALUES, TSQL_JSON_DIRECTIVE_WITHOUT_ARRAY_WRAPPER -} TSQLJSONDirective; +} TSQLJSONDirective; extern void tsql_for_datetime_format(StringInfo format_output, const char *outputstr); extern void tsql_for_datetimeoffset_format(StringInfo format_output, const char *outputstr); -#endif /* TSQL_FOR_H */ +#endif /* TSQL_FOR_H */ From 2604191c7f5cae0221f23a787e6766a05d6efb38 Mon Sep 17 00:00:00 2001 From: Aditya Verma <45755382+aadityavermaa@users.noreply.github.com> Date: Thu, 23 Mar 2023 16:50:39 +0530 Subject: [PATCH 026/363] add spt_tablecollations_view to upgrade script (#1341) The changes made in #1332 also require adding the sys.spt_tablecollations_view view into the latest upgrade script since the view definition is being changed. In this PR, the view is added to 3.1.0-3.2.0 upgrade script. Signed-off-by: Aditya Verma Co-authored-by: Aditya Verma --- .../babelfishpg_tsql/sql/babelfishpg_tsql.sql | 2 +- .../babelfishpg_tsql--3.1.0--3.2.0.sql | 20 +++++++++++++++++++ .../sp_tablecollations-vu-cleanup.out | 1 + .../expected/sp_tablecollations-vu-verify.out | 15 ++++++++++++++ ....sql => sp_tablecollations-vu-cleanup.mix} | 1 + .../sp_tablecollations-vu-verify.mix | 13 ++++++++++++ .../sp_tablecollations-vu-verify.sql | 3 --- 7 files changed, 51 insertions(+), 4 deletions(-) rename test/JDBC/input/functions/{sp_tablecollations-vu-cleanup.sql => sp_tablecollations-vu-cleanup.mix} (70%) create mode 100644 test/JDBC/input/functions/sp_tablecollations-vu-verify.mix delete mode 100644 test/JDBC/input/functions/sp_tablecollations-vu-verify.sql diff --git a/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql index 1e8b93a46e..c81f72a941 100644 --- a/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql +++ b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql @@ -708,7 +708,7 @@ CREATE OR REPLACE VIEW sys.spt_tablecollations_view AS o.object_id AS object_id, o.schema_id AS schema_id, c.column_id AS colid, - CASE WHEN p.attoptions[1] LIKE 'bbf_original_name=%' THEN CAST(split_part(p.attoptions[1], '=', 2) AS sys.SYSNAME) + CASE WHEN p.attoptions[1] LIKE 'bbf_original_name=%' THEN CAST(split_part(p.attoptions[1], '=', 2) AS sys.VARCHAR) ELSE c.name COLLATE sys.database_default END AS name, CAST(CollationProperty(c.collation_name,'tdscollation') AS binary(5)) AS tds_collation_28, CAST(CollationProperty(c.collation_name,'tdscollation') AS binary(5)) AS tds_collation_90, diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql index 23068dece8..2deb778a1a 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql @@ -701,6 +701,26 @@ FROM (VALUES ('public', 'R'), ('sys', 'S'), ('INFORMATION_SCHEMA', 'S')) as dumm GRANT SELECT ON sys.database_principals TO PUBLIC; CALL sys.babelfish_drop_deprecated_object('view', 'sys', 'database_principals_deprecated_3_2_0'); +CREATE OR REPLACE VIEW sys.spt_tablecollations_view AS + SELECT + o.object_id AS object_id, + o.schema_id AS schema_id, + c.column_id AS colid, + CASE WHEN p.attoptions[1] LIKE 'bbf_original_name=%' THEN CAST(split_part(p.attoptions[1], '=', 2) AS sys.VARCHAR) + ELSE c.name COLLATE sys.database_default END AS name, + CAST(CollationProperty(c.collation_name,'tdscollation') AS binary(5)) AS tds_collation_28, + CAST(CollationProperty(c.collation_name,'tdscollation') AS binary(5)) AS tds_collation_90, + CAST(CollationProperty(c.collation_name,'tdscollation') AS binary(5)) AS tds_collation_100, + CAST(c.collation_name AS nvarchar(128)) AS collation_28, + CAST(c.collation_name AS nvarchar(128)) AS collation_90, + CAST(c.collation_name AS nvarchar(128)) AS collation_100 + FROM + sys.all_columns c INNER JOIN + sys.all_objects o ON (c.object_id = o.object_id) JOIN + pg_attribute p ON (c.name = p.attname COLLATE sys.database_default AND c.object_id = p.attrelid) + WHERE + c.is_sparse = 0 AND p.attnum >= 0; + -- Drops the temporary procedure used by the upgrade script. -- Please have this be one of the last statements executed in this upgrade script. DROP PROCEDURE sys.babelfish_drop_deprecated_object(varchar, varchar, varchar); diff --git a/test/JDBC/expected/sp_tablecollations-vu-cleanup.out b/test/JDBC/expected/sp_tablecollations-vu-cleanup.out index b66537b349..8ff9b86231 100644 --- a/test/JDBC/expected/sp_tablecollations-vu-cleanup.out +++ b/test/JDBC/expected/sp_tablecollations-vu-cleanup.out @@ -1,2 +1,3 @@ +-- tsql DROP TABLE foo; GO diff --git a/test/JDBC/expected/sp_tablecollations-vu-verify.out b/test/JDBC/expected/sp_tablecollations-vu-verify.out index 1e6506f60c..283dba6d71 100644 --- a/test/JDBC/expected/sp_tablecollations-vu-verify.out +++ b/test/JDBC/expected/sp_tablecollations-vu-verify.out @@ -6,3 +6,18 @@ int#!#varchar#!#binary#!#nvarchar ~~END~~ +-- psql +-- Verify if datatype of column 'name' of spt_tablecollations_view used +-- internally is varchar +select + case when atttypid::regtype::text = 'sys."varchar"' then 'true' + else 'false' end +from pg_attribute +where + attrelid = 'sys.spt_tablecollations_view'::regclass and attname = 'name'; +GO +~~START~~ +text +true +~~END~~ + diff --git a/test/JDBC/input/functions/sp_tablecollations-vu-cleanup.sql b/test/JDBC/input/functions/sp_tablecollations-vu-cleanup.mix similarity index 70% rename from test/JDBC/input/functions/sp_tablecollations-vu-cleanup.sql rename to test/JDBC/input/functions/sp_tablecollations-vu-cleanup.mix index b66537b349..8ff9b86231 100644 --- a/test/JDBC/input/functions/sp_tablecollations-vu-cleanup.sql +++ b/test/JDBC/input/functions/sp_tablecollations-vu-cleanup.mix @@ -1,2 +1,3 @@ +-- tsql DROP TABLE foo; GO diff --git a/test/JDBC/input/functions/sp_tablecollations-vu-verify.mix b/test/JDBC/input/functions/sp_tablecollations-vu-verify.mix new file mode 100644 index 0000000000..9f5761f1d0 --- /dev/null +++ b/test/JDBC/input/functions/sp_tablecollations-vu-verify.mix @@ -0,0 +1,13 @@ +exec sp_tablecollations_100 'foo' +GO + +-- psql +-- Verify if datatype of column 'name' of spt_tablecollations_view used +-- internally is varchar +select + case when atttypid::regtype::text = 'sys."varchar"' then 'true' + else 'false' end +from pg_attribute +where + attrelid = 'sys.spt_tablecollations_view'::regclass and attname = 'name'; +GO \ No newline at end of file diff --git a/test/JDBC/input/functions/sp_tablecollations-vu-verify.sql b/test/JDBC/input/functions/sp_tablecollations-vu-verify.sql deleted file mode 100644 index a2caab6031..0000000000 --- a/test/JDBC/input/functions/sp_tablecollations-vu-verify.sql +++ /dev/null @@ -1,3 +0,0 @@ -exec sp_tablecollations_100 'foo' -GO - From 390c16ad1c3ebbeb433a6eabcbd1899c7e5f3003 Mon Sep 17 00:00:00 2001 From: Dipesh Dhameliya Date: Thu, 23 Mar 2023 18:01:37 +0530 Subject: [PATCH 027/363] Add 243e3294c5fee7863e7846b30d8a821b7e4b4242 to .git-blame-ignore-revs (#1360) Authored-by: Dipesh Dhameliya --- .git-blame-ignore-revs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000000..8976000fcf --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,18 @@ +# As of git 2.23, git-blame supports ignoring specific commits. This is useful +# with commits that make bulk formatting changes without truly changing any +# code. +# +# This file lists ignorable pgindent, pgperltidy, and reformat-dat-files +# related commits only. Please don't add commits that are not in this +# category. +# +# You can use the ignore list file by running: +# +# $ git config blame.ignoreRevsFile .git-blame-ignore-revs +# +# Add new entries by adding the output of the following to the top of the file: +# +# $ git log --pretty=format:"%H # %cd%n# %s" $PGINDENTGITHASH -1 --date=iso + +243e3294c5fee7863e7846b30d8a821b7e4b4242 # 2023-03-22 21:34:35 -0700 +# Run pgindent on each babelfish extensions code (#1357) \ No newline at end of file From 561e3a13854532531367960ab262dd396261e01a Mon Sep 17 00:00:00 2001 From: Shlok Kumar Kyal <68871659+skkyal@users.noreply.github.com> Date: Thu, 23 Mar 2023 19:33:51 +0530 Subject: [PATCH 028/363] Create scalar UDFs as STABLE functions by default (#1269) Earlier the tsql functions were created with volatility as volatile by default. From behaviour and performance perspective function should be created as 'stable' by default. Also, When a function is stable, it cannot have DDL or DML inside it. But it possible to DML only in table variables in tsql. With this PR made the default volatility during tsql function creation as stable except for the cases when a function contains a table variable (tvp or tvf). Signed-off-by: Shlok Kumar Kyal (skkyal@amazon.com) --- .../src/backend_parser/gram-tsql-rule.y | 8 +- contrib/babelfishpg_tsql/src/pl_handler.c | 60 +- ..._6__preparation__BABEL-2877-vu-prepare.out | 100 +++ ..._7__preparation__BABEL-2877-vu-prepare.out | 100 +++ ...est-sp_babelfish_volatility-vu-prepare.out | 70 ++ ..._8__preparation__BABEL-2877-vu-prepare.out | 100 +++ ...est-sp_babelfish_volatility-vu-prepare.out | 70 ++ ..._1__preparation__BABEL-2877-vu-prepare.out | 100 +++ ..._2__preparation__BABEL-2877-vu-prepare.out | 100 +++ ...est-sp_babelfish_volatility-vu-prepare.out | 70 ++ test/JDBC/expected/BABEL-2877-vu-verify.out | 6 +- ...Test-sp_babelfish_volatility-vu-verify.out | 132 ++-- ...ate_function_default_stable-vu-cleanup.out | 130 +++ ...ate_function_default_stable-vu-prepare.out | 284 +++++++ ...eate_function_default_stable-vu-verify.out | 389 +++++++++ ...n_cleanup__14_6__BABEL-2877-vu-cleanup.out | 46 ++ ...on_cleanup__14_6__BABEL-2877-vu-verify.out | 229 ++++++ ...n_cleanup__14_7__BABEL-2877-vu-cleanup.out | 46 ++ ...on_cleanup__14_7__BABEL-2877-vu-verify.out | 229 ++++++ ...est-sp_babelfish_volatility-vu-cleanup.out | 65 ++ ...Test-sp_babelfish_volatility-vu-verify.out | 737 ++++++++++++++++++ ...n_cleanup__14_8__BABEL-2877-vu-cleanup.out | 46 ++ ...on_cleanup__14_8__BABEL-2877-vu-verify.out | 229 ++++++ ...est-sp_babelfish_volatility-vu-cleanup.out | 65 ++ ...Test-sp_babelfish_volatility-vu-verify.out | 737 ++++++++++++++++++ ...n_cleanup__15_1__BABEL-2877-vu-cleanup.out | 46 ++ ...on_cleanup__15_1__BABEL-2877-vu-verify.out | 229 ++++++ ...n_cleanup__15_2__BABEL-2877-vu-cleanup.out | 46 ++ ...on_cleanup__15_2__BABEL-2877-vu-verify.out | 229 ++++++ ...est-sp_babelfish_volatility-vu-cleanup.out | 65 ++ ...Test-sp_babelfish_volatility-vu-verify.out | 737 ++++++++++++++++++ ...ate_function_default_stable-vu-cleanup.mix | 130 +++ ...ate_function_default_stable-vu-prepare.mix | 284 +++++++ ...eate_function_default_stable-vu-verify.mix | 168 ++++ ...Test-sp_babelfish_volatility-vu-verify.mix | 34 +- test/JDBC/upgrade/13_6/schedule | 1 - test/JDBC/upgrade/13_7/schedule | 1 - test/JDBC/upgrade/13_8/schedule | 1 - test/JDBC/upgrade/13_9/schedule | 1 - test/JDBC/upgrade/14_3/schedule | 1 - test/JDBC/upgrade/14_5/schedule | 1 - .../preparation/BABEL-2877-vu-prepare.sql | 100 +++ test/JDBC/upgrade/14_6/schedule | 2 - .../preparation/BABEL-2877-vu-prepare.sql | 100 +++ ...est-sp_babelfish_volatility-vu-prepare.sql | 70 ++ test/JDBC/upgrade/14_7/schedule | 2 - .../preparation/BABEL-2877-vu-prepare.sql | 100 +++ ...est-sp_babelfish_volatility-vu-prepare.sql | 70 ++ test/JDBC/upgrade/14_8/schedule | 2 - .../preparation/BABEL-2877-vu-prepare.sql | 100 +++ test/JDBC/upgrade/15_1/schedule | 2 - .../preparation/BABEL-2877-vu-prepare.sql | 100 +++ ...est-sp_babelfish_volatility-vu-prepare.sql | 70 ++ test/JDBC/upgrade/15_2/schedule | 2 - .../14_6/BABEL-2877-vu-cleanup.sql | 42 + .../14_6/BABEL-2877-vu-verify.sql | 102 +++ .../14_7/BABEL-2877-vu-cleanup.sql | 42 + .../14_7/BABEL-2877-vu-verify.sql | 102 +++ ...est-sp_babelfish_volatility-vu-cleanup.sql | 65 ++ ...Test-sp_babelfish_volatility-vu-verify.mix | 314 ++++++++ .../14_8/BABEL-2877-vu-cleanup.sql | 42 + .../14_8/BABEL-2877-vu-verify.sql | 102 +++ ...est-sp_babelfish_volatility-vu-cleanup.sql | 65 ++ ...Test-sp_babelfish_volatility-vu-verify.mix | 314 ++++++++ .../15_1/BABEL-2877-vu-cleanup.sql | 42 + .../15_1/BABEL-2877-vu-verify.sql | 102 +++ .../15_2/BABEL-2877-vu-cleanup.sql | 42 + .../15_2/BABEL-2877-vu-verify.sql | 102 +++ ...est-sp_babelfish_volatility-vu-cleanup.sql | 65 ++ ...Test-sp_babelfish_volatility-vu-verify.mix | 314 ++++++++ 70 files changed, 8594 insertions(+), 105 deletions(-) create mode 100644 test/JDBC/expected/14_6__preparation__BABEL-2877-vu-prepare.out create mode 100644 test/JDBC/expected/14_7__preparation__BABEL-2877-vu-prepare.out create mode 100644 test/JDBC/expected/14_7__preparation__Test-sp_babelfish_volatility-vu-prepare.out create mode 100644 test/JDBC/expected/14_8__preparation__BABEL-2877-vu-prepare.out create mode 100644 test/JDBC/expected/14_8__preparation__Test-sp_babelfish_volatility-vu-prepare.out create mode 100644 test/JDBC/expected/15_1__preparation__BABEL-2877-vu-prepare.out create mode 100644 test/JDBC/expected/15_2__preparation__BABEL-2877-vu-prepare.out create mode 100644 test/JDBC/expected/15_2__preparation__Test-sp_babelfish_volatility-vu-prepare.out create mode 100644 test/JDBC/expected/create_function_default_stable-vu-cleanup.out create mode 100644 test/JDBC/expected/create_function_default_stable-vu-prepare.out create mode 100644 test/JDBC/expected/create_function_default_stable-vu-verify.out create mode 100644 test/JDBC/expected/latest__verification_cleanup__14_6__BABEL-2877-vu-cleanup.out create mode 100644 test/JDBC/expected/latest__verification_cleanup__14_6__BABEL-2877-vu-verify.out create mode 100644 test/JDBC/expected/latest__verification_cleanup__14_7__BABEL-2877-vu-cleanup.out create mode 100644 test/JDBC/expected/latest__verification_cleanup__14_7__BABEL-2877-vu-verify.out create mode 100644 test/JDBC/expected/latest__verification_cleanup__14_7__Test-sp_babelfish_volatility-vu-cleanup.out create mode 100644 test/JDBC/expected/latest__verification_cleanup__14_7__Test-sp_babelfish_volatility-vu-verify.out create mode 100644 test/JDBC/expected/latest__verification_cleanup__14_8__BABEL-2877-vu-cleanup.out create mode 100644 test/JDBC/expected/latest__verification_cleanup__14_8__BABEL-2877-vu-verify.out create mode 100644 test/JDBC/expected/latest__verification_cleanup__14_8__Test-sp_babelfish_volatility-vu-cleanup.out create mode 100644 test/JDBC/expected/latest__verification_cleanup__14_8__Test-sp_babelfish_volatility-vu-verify.out create mode 100644 test/JDBC/expected/latest__verification_cleanup__15_1__BABEL-2877-vu-cleanup.out create mode 100644 test/JDBC/expected/latest__verification_cleanup__15_1__BABEL-2877-vu-verify.out create mode 100644 test/JDBC/expected/latest__verification_cleanup__15_2__BABEL-2877-vu-cleanup.out create mode 100644 test/JDBC/expected/latest__verification_cleanup__15_2__BABEL-2877-vu-verify.out create mode 100644 test/JDBC/expected/latest__verification_cleanup__15_2__Test-sp_babelfish_volatility-vu-cleanup.out create mode 100644 test/JDBC/expected/latest__verification_cleanup__15_2__Test-sp_babelfish_volatility-vu-verify.out create mode 100644 test/JDBC/input/create_function_default_stable-vu-cleanup.mix create mode 100644 test/JDBC/input/create_function_default_stable-vu-prepare.mix create mode 100644 test/JDBC/input/create_function_default_stable-vu-verify.mix create mode 100644 test/JDBC/upgrade/14_6/preparation/BABEL-2877-vu-prepare.sql create mode 100644 test/JDBC/upgrade/14_7/preparation/BABEL-2877-vu-prepare.sql create mode 100644 test/JDBC/upgrade/14_7/preparation/Test-sp_babelfish_volatility-vu-prepare.sql create mode 100644 test/JDBC/upgrade/14_8/preparation/BABEL-2877-vu-prepare.sql create mode 100644 test/JDBC/upgrade/14_8/preparation/Test-sp_babelfish_volatility-vu-prepare.sql create mode 100644 test/JDBC/upgrade/15_1/preparation/BABEL-2877-vu-prepare.sql create mode 100644 test/JDBC/upgrade/15_2/preparation/BABEL-2877-vu-prepare.sql create mode 100644 test/JDBC/upgrade/15_2/preparation/Test-sp_babelfish_volatility-vu-prepare.sql create mode 100644 test/JDBC/upgrade/latest/verification_cleanup/14_6/BABEL-2877-vu-cleanup.sql create mode 100644 test/JDBC/upgrade/latest/verification_cleanup/14_6/BABEL-2877-vu-verify.sql create mode 100644 test/JDBC/upgrade/latest/verification_cleanup/14_7/BABEL-2877-vu-cleanup.sql create mode 100644 test/JDBC/upgrade/latest/verification_cleanup/14_7/BABEL-2877-vu-verify.sql create mode 100644 test/JDBC/upgrade/latest/verification_cleanup/14_7/Test-sp_babelfish_volatility-vu-cleanup.sql create mode 100644 test/JDBC/upgrade/latest/verification_cleanup/14_7/Test-sp_babelfish_volatility-vu-verify.mix create mode 100644 test/JDBC/upgrade/latest/verification_cleanup/14_8/BABEL-2877-vu-cleanup.sql create mode 100644 test/JDBC/upgrade/latest/verification_cleanup/14_8/BABEL-2877-vu-verify.sql create mode 100644 test/JDBC/upgrade/latest/verification_cleanup/14_8/Test-sp_babelfish_volatility-vu-cleanup.sql create mode 100644 test/JDBC/upgrade/latest/verification_cleanup/14_8/Test-sp_babelfish_volatility-vu-verify.mix create mode 100644 test/JDBC/upgrade/latest/verification_cleanup/15_1/BABEL-2877-vu-cleanup.sql create mode 100644 test/JDBC/upgrade/latest/verification_cleanup/15_1/BABEL-2877-vu-verify.sql create mode 100644 test/JDBC/upgrade/latest/verification_cleanup/15_2/BABEL-2877-vu-cleanup.sql create mode 100644 test/JDBC/upgrade/latest/verification_cleanup/15_2/BABEL-2877-vu-verify.sql create mode 100644 test/JDBC/upgrade/latest/verification_cleanup/15_2/Test-sp_babelfish_volatility-vu-cleanup.sql create mode 100644 test/JDBC/upgrade/latest/verification_cleanup/15_2/Test-sp_babelfish_volatility-vu-verify.mix diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y index b7d17e68d2..060a6acfec 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y @@ -3620,12 +3620,18 @@ tsql_CreateFunctionStmt: DefElem *lang = makeDefElem("language", (Node *) makeString("pltsql"), @1); DefElem *body = makeDefElem("as", (Node *) list_make1(makeString($10)), @10); DefElem *location = makeDefElem("location", (Node *) makeInteger(@4), @4); + /* + * Adding a option for volatility with value STABLE. + * Function created from tsql dialect will be created as STABLE + * by default + */ + DefElem *vol = makeDefElem("volatility", (Node *) makeString("stable"), @1); n->is_procedure = false; n->replace = $2; n->funcname = $4; n->parameters = $5; n->returnType = $7; - n->options = list_concat(list_make3(lang, body, location), $8); + n->options = list_concat(list_make4(lang, body, location, vol), $8); $$ = (Node *)n; } | CREATE opt_or_replace proc_keyword tsql_func_name tsql_createproc_args diff --git a/contrib/babelfishpg_tsql/src/pl_handler.c b/contrib/babelfishpg_tsql/src/pl_handler.c index 7bd9d6cb73..3c9221bc16 100644 --- a/contrib/babelfishpg_tsql/src/pl_handler.c +++ b/contrib/babelfishpg_tsql/src/pl_handler.c @@ -4589,11 +4589,15 @@ pltsql_validator(PG_FUNCTION_ARGS) char *argmodes; bool is_dml_trigger = false; bool is_event_trigger = false; + bool has_table_var = false; + char prokind; int i; /* Special handling is neede for Inline Table-Valued Functions */ - bool is_itvf; - char *prosrc = NULL; + bool is_itvf; + char *prosrc = NULL; + bool is_mstvf = false; + MemoryContext oldMemoryContext = CurrentMemoryContext; int saved_dialect = sql_dialect; @@ -4606,6 +4610,8 @@ pltsql_validator(PG_FUNCTION_ARGS) elog(ERROR, "cache lookup failed for function %u", funcoid); proc = (Form_pg_proc) GETSTRUCT(tuple); + prokind = proc->prokind; + /* Disallow text, ntext, and image type result */ if (!babelfish_dump_restore && ((*common_utility_plugin_ptr->is_tsql_text_datatype) (proc->prorettype) || @@ -4738,6 +4744,16 @@ pltsql_validator(PG_FUNCTION_ARGS) else func = pltsql_compile(fake_fcinfo, true); + if(func && func->table_varnos) + { + is_mstvf = func->is_mstvf; + /* + * if a function has tvp declared or as argument in the function + * or it is a TVF has_table_var will be true + */ + has_table_var = true; + } + /* * Disconnect from SPI manager */ @@ -4746,6 +4762,46 @@ pltsql_validator(PG_FUNCTION_ARGS) } ReleaseSysCache(tuple); + + /* + * If the function has TVP in its arguments or function body + * it should be declared as VOLATILE by default + * TVF are VOLATILE by default so we donot need to update tuple for it + */ + if(prokind == PROKIND_FUNCTION && (has_table_var && !is_itvf && !is_mstvf)) + { + Relation rel; + HeapTuple tup; + HeapTuple oldtup; + bool nulls[Natts_pg_proc]; + Datum values[Natts_pg_proc]; + bool replaces[Natts_pg_proc]; + TupleDesc tupDesc; + char volatility = PROVOLATILE_VOLATILE; + + /* Existing atts in pg_proc entry - no need to replace */ + for (i = 0; i < Natts_pg_proc; ++i) + { + nulls[i] = false; + values[i] = PointerGetDatum(NULL); + replaces[i] = false; + } + + rel = table_open(ProcedureRelationId, RowExclusiveLock); + tupDesc = RelationGetDescr(rel); + oldtup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid)); + + values[Anum_pg_proc_provolatile - 1] = CharGetDatum(volatility); + replaces[Anum_pg_proc_provolatile - 1] = true; + + tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces); + CatalogTupleUpdate(rel, &tup->t_self, tup); + + ReleaseSysCache(oldtup); + + heap_freetuple(tup); + table_close(rel, RowExclusiveLock); + } /* * For inline table-valued function, we need to construct the column diff --git a/test/JDBC/expected/14_6__preparation__BABEL-2877-vu-prepare.out b/test/JDBC/expected/14_6__preparation__BABEL-2877-vu-prepare.out new file mode 100644 index 0000000000..aa91e6afde --- /dev/null +++ b/test/JDBC/expected/14_6__preparation__BABEL-2877-vu-prepare.out @@ -0,0 +1,100 @@ +-- Function +-- Defaults at different positions +CREATE FUNCTION babel_2877_vu_prepare_func1 (@a int, @b varchar(10) = 'abc', @c money, @d float = 1.2) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- All parameters with defaults +CREATE FUNCTION babel_2877_vu_prepare_func2 (@a int = 10, @b varchar(10) = 'abc', @c money = $5, @d float = 1.2) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- No defaults +CREATE FUNCTION babel_2877_vu_prepare_func3 (@a int, @b varchar(10), @c money, @d float) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- Procedure +-- Defaults at different positions +CREATE PROCEDURE babel_2877_vu_prepare_proc1 (@a int, @b varchar(10) = 'abc', @c money = $5, @d float) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- All parameters with defaults +CREATE PROCEDURE babel_2877_vu_prepare_proc2 (@a int = 10, @b varchar(10) = 'abc', @c money = $5, @d float = 1.2) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- No defaults +CREATE PROCEDURE babel_2877_vu_prepare_proc3 (@a int, @b varchar(10), @c money, @d float) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- Views +CREATE VIEW babel_2877_vu_prepare_view1 AS SELECT babel_2877_vu_prepare_func1(20, 'def', $5); +GO + +CREATE VIEW babel_2877_vu_prepare_view2 AS SELECT babel_2877_vu_prepare_func2(); +GO + +CREATE VIEW babel_2877_vu_prepare_view3 AS SELECT babel_2877_vu_prepare_func1(20, 'def', $10, 1.8); +GO + +-- CASE: Check for session properties like ANSI_NULLS and QUOTED_IDENTIFIER +-- ANSI_NULLS - Last bit from left in flag_values +-- QUOTED_IDENTIFIER - Second last bit from left in flag_values +SET ANSI_NULLS ON; +GO + +SET QUOTED_IDENTIFIER ON; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDON] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET ANSI_NULLS OFF; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDON] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET QUOTED_IDENTIFIER OFF; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDOFF] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET ANSI_NULLS ON; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDOFF] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +-- reset session properties +SET ANSI_NULLS ON; +GO + +SET QUOTED_IDENTIFIER ON; +GO diff --git a/test/JDBC/expected/14_7__preparation__BABEL-2877-vu-prepare.out b/test/JDBC/expected/14_7__preparation__BABEL-2877-vu-prepare.out new file mode 100644 index 0000000000..aa91e6afde --- /dev/null +++ b/test/JDBC/expected/14_7__preparation__BABEL-2877-vu-prepare.out @@ -0,0 +1,100 @@ +-- Function +-- Defaults at different positions +CREATE FUNCTION babel_2877_vu_prepare_func1 (@a int, @b varchar(10) = 'abc', @c money, @d float = 1.2) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- All parameters with defaults +CREATE FUNCTION babel_2877_vu_prepare_func2 (@a int = 10, @b varchar(10) = 'abc', @c money = $5, @d float = 1.2) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- No defaults +CREATE FUNCTION babel_2877_vu_prepare_func3 (@a int, @b varchar(10), @c money, @d float) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- Procedure +-- Defaults at different positions +CREATE PROCEDURE babel_2877_vu_prepare_proc1 (@a int, @b varchar(10) = 'abc', @c money = $5, @d float) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- All parameters with defaults +CREATE PROCEDURE babel_2877_vu_prepare_proc2 (@a int = 10, @b varchar(10) = 'abc', @c money = $5, @d float = 1.2) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- No defaults +CREATE PROCEDURE babel_2877_vu_prepare_proc3 (@a int, @b varchar(10), @c money, @d float) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- Views +CREATE VIEW babel_2877_vu_prepare_view1 AS SELECT babel_2877_vu_prepare_func1(20, 'def', $5); +GO + +CREATE VIEW babel_2877_vu_prepare_view2 AS SELECT babel_2877_vu_prepare_func2(); +GO + +CREATE VIEW babel_2877_vu_prepare_view3 AS SELECT babel_2877_vu_prepare_func1(20, 'def', $10, 1.8); +GO + +-- CASE: Check for session properties like ANSI_NULLS and QUOTED_IDENTIFIER +-- ANSI_NULLS - Last bit from left in flag_values +-- QUOTED_IDENTIFIER - Second last bit from left in flag_values +SET ANSI_NULLS ON; +GO + +SET QUOTED_IDENTIFIER ON; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDON] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET ANSI_NULLS OFF; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDON] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET QUOTED_IDENTIFIER OFF; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDOFF] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET ANSI_NULLS ON; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDOFF] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +-- reset session properties +SET ANSI_NULLS ON; +GO + +SET QUOTED_IDENTIFIER ON; +GO diff --git a/test/JDBC/expected/14_7__preparation__Test-sp_babelfish_volatility-vu-prepare.out b/test/JDBC/expected/14_7__preparation__Test-sp_babelfish_volatility-vu-prepare.out new file mode 100644 index 0000000000..9be5872d7d --- /dev/null +++ b/test/JDBC/expected/14_7__preparation__Test-sp_babelfish_volatility-vu-prepare.out @@ -0,0 +1,70 @@ +create function test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +go + +create schema test_sp_babelfish_volatility_schema1 +go + +create function test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +go + +create schema [test_sp_babelfish_volatility_schema1 with .dot and spaces] +go + +create function [test_sp_babelfish_volatility_schema1 with .dot and spaces].test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +go + +CREATE LOGIN test_sp_babelfish_volatility_login WITH PASSWORD = '12345678'; +GO + +CREATE DATABASE test_sp_babelfish_volatility_db1 +GO + +USE test_sp_babelfish_volatility_db1 +GO + +CREATE SCHEMA test_sp_babelfish_volatility_schema2 +GO + +create function test_sp_babelfish_volatility_f2() returns int begin declare @a int; set @a = 1; return @a; end +GO + +create function test_sp_babelfish_volatility_duplicate() returns int begin declare @a int; set @a = 1; return @a; end +go + +create function test_sp_babelfish_volatility_duplicate(@b int) returns int begin declare @a int; set @a = 1; return @a; end +go + +create function test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +GO + +create schema test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa; +go + +create function test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa() +returns int begin declare @a int; set @a = 1; return @a; end +go + +create function test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa() +returns int begin declare @a int; set @a = 1; return @a; end +go + +CREATE USER test_sp_babelfish_volatility_user FOR LOGIN test_sp_babelfish_volatility_login +GO + +use master +go + +create table test_bbf_vol_t1(a int) +go + +create function test_bbf_vol_f1() returns int begin declare @a int; set @a = 1; return @a; end +go + +create function [test_bbf_vol_f1;drop table test_bbf_vol_t1;]() returns int begin declare @a int; set @a = 1; return @a; end +go + +use test_sp_babelfish_volatility_db1 +go + +CREATE LOGIN test_sp_babelfish_volatility_login_2 WITH PASSWORD = '12345678' +GO diff --git a/test/JDBC/expected/14_8__preparation__BABEL-2877-vu-prepare.out b/test/JDBC/expected/14_8__preparation__BABEL-2877-vu-prepare.out new file mode 100644 index 0000000000..aa91e6afde --- /dev/null +++ b/test/JDBC/expected/14_8__preparation__BABEL-2877-vu-prepare.out @@ -0,0 +1,100 @@ +-- Function +-- Defaults at different positions +CREATE FUNCTION babel_2877_vu_prepare_func1 (@a int, @b varchar(10) = 'abc', @c money, @d float = 1.2) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- All parameters with defaults +CREATE FUNCTION babel_2877_vu_prepare_func2 (@a int = 10, @b varchar(10) = 'abc', @c money = $5, @d float = 1.2) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- No defaults +CREATE FUNCTION babel_2877_vu_prepare_func3 (@a int, @b varchar(10), @c money, @d float) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- Procedure +-- Defaults at different positions +CREATE PROCEDURE babel_2877_vu_prepare_proc1 (@a int, @b varchar(10) = 'abc', @c money = $5, @d float) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- All parameters with defaults +CREATE PROCEDURE babel_2877_vu_prepare_proc2 (@a int = 10, @b varchar(10) = 'abc', @c money = $5, @d float = 1.2) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- No defaults +CREATE PROCEDURE babel_2877_vu_prepare_proc3 (@a int, @b varchar(10), @c money, @d float) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- Views +CREATE VIEW babel_2877_vu_prepare_view1 AS SELECT babel_2877_vu_prepare_func1(20, 'def', $5); +GO + +CREATE VIEW babel_2877_vu_prepare_view2 AS SELECT babel_2877_vu_prepare_func2(); +GO + +CREATE VIEW babel_2877_vu_prepare_view3 AS SELECT babel_2877_vu_prepare_func1(20, 'def', $10, 1.8); +GO + +-- CASE: Check for session properties like ANSI_NULLS and QUOTED_IDENTIFIER +-- ANSI_NULLS - Last bit from left in flag_values +-- QUOTED_IDENTIFIER - Second last bit from left in flag_values +SET ANSI_NULLS ON; +GO + +SET QUOTED_IDENTIFIER ON; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDON] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET ANSI_NULLS OFF; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDON] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET QUOTED_IDENTIFIER OFF; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDOFF] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET ANSI_NULLS ON; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDOFF] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +-- reset session properties +SET ANSI_NULLS ON; +GO + +SET QUOTED_IDENTIFIER ON; +GO diff --git a/test/JDBC/expected/14_8__preparation__Test-sp_babelfish_volatility-vu-prepare.out b/test/JDBC/expected/14_8__preparation__Test-sp_babelfish_volatility-vu-prepare.out new file mode 100644 index 0000000000..9be5872d7d --- /dev/null +++ b/test/JDBC/expected/14_8__preparation__Test-sp_babelfish_volatility-vu-prepare.out @@ -0,0 +1,70 @@ +create function test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +go + +create schema test_sp_babelfish_volatility_schema1 +go + +create function test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +go + +create schema [test_sp_babelfish_volatility_schema1 with .dot and spaces] +go + +create function [test_sp_babelfish_volatility_schema1 with .dot and spaces].test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +go + +CREATE LOGIN test_sp_babelfish_volatility_login WITH PASSWORD = '12345678'; +GO + +CREATE DATABASE test_sp_babelfish_volatility_db1 +GO + +USE test_sp_babelfish_volatility_db1 +GO + +CREATE SCHEMA test_sp_babelfish_volatility_schema2 +GO + +create function test_sp_babelfish_volatility_f2() returns int begin declare @a int; set @a = 1; return @a; end +GO + +create function test_sp_babelfish_volatility_duplicate() returns int begin declare @a int; set @a = 1; return @a; end +go + +create function test_sp_babelfish_volatility_duplicate(@b int) returns int begin declare @a int; set @a = 1; return @a; end +go + +create function test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +GO + +create schema test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa; +go + +create function test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa() +returns int begin declare @a int; set @a = 1; return @a; end +go + +create function test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa() +returns int begin declare @a int; set @a = 1; return @a; end +go + +CREATE USER test_sp_babelfish_volatility_user FOR LOGIN test_sp_babelfish_volatility_login +GO + +use master +go + +create table test_bbf_vol_t1(a int) +go + +create function test_bbf_vol_f1() returns int begin declare @a int; set @a = 1; return @a; end +go + +create function [test_bbf_vol_f1;drop table test_bbf_vol_t1;]() returns int begin declare @a int; set @a = 1; return @a; end +go + +use test_sp_babelfish_volatility_db1 +go + +CREATE LOGIN test_sp_babelfish_volatility_login_2 WITH PASSWORD = '12345678' +GO diff --git a/test/JDBC/expected/15_1__preparation__BABEL-2877-vu-prepare.out b/test/JDBC/expected/15_1__preparation__BABEL-2877-vu-prepare.out new file mode 100644 index 0000000000..aa91e6afde --- /dev/null +++ b/test/JDBC/expected/15_1__preparation__BABEL-2877-vu-prepare.out @@ -0,0 +1,100 @@ +-- Function +-- Defaults at different positions +CREATE FUNCTION babel_2877_vu_prepare_func1 (@a int, @b varchar(10) = 'abc', @c money, @d float = 1.2) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- All parameters with defaults +CREATE FUNCTION babel_2877_vu_prepare_func2 (@a int = 10, @b varchar(10) = 'abc', @c money = $5, @d float = 1.2) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- No defaults +CREATE FUNCTION babel_2877_vu_prepare_func3 (@a int, @b varchar(10), @c money, @d float) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- Procedure +-- Defaults at different positions +CREATE PROCEDURE babel_2877_vu_prepare_proc1 (@a int, @b varchar(10) = 'abc', @c money = $5, @d float) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- All parameters with defaults +CREATE PROCEDURE babel_2877_vu_prepare_proc2 (@a int = 10, @b varchar(10) = 'abc', @c money = $5, @d float = 1.2) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- No defaults +CREATE PROCEDURE babel_2877_vu_prepare_proc3 (@a int, @b varchar(10), @c money, @d float) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- Views +CREATE VIEW babel_2877_vu_prepare_view1 AS SELECT babel_2877_vu_prepare_func1(20, 'def', $5); +GO + +CREATE VIEW babel_2877_vu_prepare_view2 AS SELECT babel_2877_vu_prepare_func2(); +GO + +CREATE VIEW babel_2877_vu_prepare_view3 AS SELECT babel_2877_vu_prepare_func1(20, 'def', $10, 1.8); +GO + +-- CASE: Check for session properties like ANSI_NULLS and QUOTED_IDENTIFIER +-- ANSI_NULLS - Last bit from left in flag_values +-- QUOTED_IDENTIFIER - Second last bit from left in flag_values +SET ANSI_NULLS ON; +GO + +SET QUOTED_IDENTIFIER ON; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDON] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET ANSI_NULLS OFF; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDON] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET QUOTED_IDENTIFIER OFF; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDOFF] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET ANSI_NULLS ON; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDOFF] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +-- reset session properties +SET ANSI_NULLS ON; +GO + +SET QUOTED_IDENTIFIER ON; +GO diff --git a/test/JDBC/expected/15_2__preparation__BABEL-2877-vu-prepare.out b/test/JDBC/expected/15_2__preparation__BABEL-2877-vu-prepare.out new file mode 100644 index 0000000000..aa91e6afde --- /dev/null +++ b/test/JDBC/expected/15_2__preparation__BABEL-2877-vu-prepare.out @@ -0,0 +1,100 @@ +-- Function +-- Defaults at different positions +CREATE FUNCTION babel_2877_vu_prepare_func1 (@a int, @b varchar(10) = 'abc', @c money, @d float = 1.2) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- All parameters with defaults +CREATE FUNCTION babel_2877_vu_prepare_func2 (@a int = 10, @b varchar(10) = 'abc', @c money = $5, @d float = 1.2) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- No defaults +CREATE FUNCTION babel_2877_vu_prepare_func3 (@a int, @b varchar(10), @c money, @d float) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- Procedure +-- Defaults at different positions +CREATE PROCEDURE babel_2877_vu_prepare_proc1 (@a int, @b varchar(10) = 'abc', @c money = $5, @d float) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- All parameters with defaults +CREATE PROCEDURE babel_2877_vu_prepare_proc2 (@a int = 10, @b varchar(10) = 'abc', @c money = $5, @d float = 1.2) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- No defaults +CREATE PROCEDURE babel_2877_vu_prepare_proc3 (@a int, @b varchar(10), @c money, @d float) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- Views +CREATE VIEW babel_2877_vu_prepare_view1 AS SELECT babel_2877_vu_prepare_func1(20, 'def', $5); +GO + +CREATE VIEW babel_2877_vu_prepare_view2 AS SELECT babel_2877_vu_prepare_func2(); +GO + +CREATE VIEW babel_2877_vu_prepare_view3 AS SELECT babel_2877_vu_prepare_func1(20, 'def', $10, 1.8); +GO + +-- CASE: Check for session properties like ANSI_NULLS and QUOTED_IDENTIFIER +-- ANSI_NULLS - Last bit from left in flag_values +-- QUOTED_IDENTIFIER - Second last bit from left in flag_values +SET ANSI_NULLS ON; +GO + +SET QUOTED_IDENTIFIER ON; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDON] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET ANSI_NULLS OFF; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDON] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET QUOTED_IDENTIFIER OFF; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDOFF] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET ANSI_NULLS ON; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDOFF] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +-- reset session properties +SET ANSI_NULLS ON; +GO + +SET QUOTED_IDENTIFIER ON; +GO diff --git a/test/JDBC/expected/15_2__preparation__Test-sp_babelfish_volatility-vu-prepare.out b/test/JDBC/expected/15_2__preparation__Test-sp_babelfish_volatility-vu-prepare.out new file mode 100644 index 0000000000..9be5872d7d --- /dev/null +++ b/test/JDBC/expected/15_2__preparation__Test-sp_babelfish_volatility-vu-prepare.out @@ -0,0 +1,70 @@ +create function test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +go + +create schema test_sp_babelfish_volatility_schema1 +go + +create function test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +go + +create schema [test_sp_babelfish_volatility_schema1 with .dot and spaces] +go + +create function [test_sp_babelfish_volatility_schema1 with .dot and spaces].test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +go + +CREATE LOGIN test_sp_babelfish_volatility_login WITH PASSWORD = '12345678'; +GO + +CREATE DATABASE test_sp_babelfish_volatility_db1 +GO + +USE test_sp_babelfish_volatility_db1 +GO + +CREATE SCHEMA test_sp_babelfish_volatility_schema2 +GO + +create function test_sp_babelfish_volatility_f2() returns int begin declare @a int; set @a = 1; return @a; end +GO + +create function test_sp_babelfish_volatility_duplicate() returns int begin declare @a int; set @a = 1; return @a; end +go + +create function test_sp_babelfish_volatility_duplicate(@b int) returns int begin declare @a int; set @a = 1; return @a; end +go + +create function test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +GO + +create schema test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa; +go + +create function test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa() +returns int begin declare @a int; set @a = 1; return @a; end +go + +create function test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa() +returns int begin declare @a int; set @a = 1; return @a; end +go + +CREATE USER test_sp_babelfish_volatility_user FOR LOGIN test_sp_babelfish_volatility_login +GO + +use master +go + +create table test_bbf_vol_t1(a int) +go + +create function test_bbf_vol_f1() returns int begin declare @a int; set @a = 1; return @a; end +go + +create function [test_bbf_vol_f1;drop table test_bbf_vol_t1;]() returns int begin declare @a int; set @a = 1; return @a; end +go + +use test_sp_babelfish_volatility_db1 +go + +CREATE LOGIN test_sp_babelfish_volatility_login_2 WITH PASSWORD = '12345678' +GO diff --git a/test/JDBC/expected/BABEL-2877-vu-verify.out b/test/JDBC/expected/BABEL-2877-vu-verify.out index 5970f8ab19..de27044b49 100644 --- a/test/JDBC/expected/BABEL-2877-vu-verify.out +++ b/test/JDBC/expected/BABEL-2877-vu-verify.out @@ -2,7 +2,7 @@ SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func1' as regproc)); GO ~~START~~ text -CREATE OR REPLACE FUNCTION master_dbo.babel_2877_vu_prepare_func1("@a" integer, "@b" "varchar" DEFAULT 'abc'::"varchar", "@c" money, "@d" double precision DEFAULT 1.2) RETURNS "varchar" LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1", "100"], "original_probin": ""}', $function$BEGIN RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10));END$function$ +CREATE OR REPLACE FUNCTION master_dbo.babel_2877_vu_prepare_func1("@a" integer, "@b" "varchar" DEFAULT 'abc'::"varchar", "@c" money, "@d" double precision DEFAULT 1.2) RETURNS "varchar" LANGUAGE pltsql STABLEAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1", "100"], "original_probin": ""}', $function$BEGIN RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10));END$function$ ~~END~~ @@ -10,7 +10,7 @@ SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func2' as regproc)); GO ~~START~~ text -CREATE OR REPLACE FUNCTION master_dbo.babel_2877_vu_prepare_func2("@a" integer DEFAULT 10, "@b" "varchar" DEFAULT 'abc'::"varchar", "@c" money DEFAULT 5, "@d" double precision DEFAULT 1.2) RETURNS "varchar" LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1", "100"], "original_probin": ""}', $function$BEGIN RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10));END$function$ +CREATE OR REPLACE FUNCTION master_dbo.babel_2877_vu_prepare_func2("@a" integer DEFAULT 10, "@b" "varchar" DEFAULT 'abc'::"varchar", "@c" money DEFAULT 5, "@d" double precision DEFAULT 1.2) RETURNS "varchar" LANGUAGE pltsql STABLEAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1", "100"], "original_probin": ""}', $function$BEGIN RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10));END$function$ ~~END~~ @@ -18,7 +18,7 @@ SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func3' as regproc)); GO ~~START~~ text -CREATE OR REPLACE FUNCTION master_dbo.babel_2877_vu_prepare_func3("@a" integer, "@b" "varchar", "@c" money, "@d" double precision) RETURNS "varchar" LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1", "100"], "original_probin": ""}', $function$BEGIN RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10));END$function$ +CREATE OR REPLACE FUNCTION master_dbo.babel_2877_vu_prepare_func3("@a" integer, "@b" "varchar", "@c" money, "@d" double precision) RETURNS "varchar" LANGUAGE pltsql STABLEAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1", "100"], "original_probin": ""}', $function$BEGIN RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10));END$function$ ~~END~~ diff --git a/test/JDBC/expected/Test-sp_babelfish_volatility-vu-verify.out b/test/JDBC/expected/Test-sp_babelfish_volatility-vu-verify.out index 6f5ddef81a..2fc0e813d1 100644 --- a/test/JDBC/expected/Test-sp_babelfish_volatility-vu-verify.out +++ b/test/JDBC/expected/Test-sp_babelfish_volatility-vu-verify.out @@ -6,25 +6,25 @@ exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' go ~~START~~ nvarchar#!#varchar#!#text -dbo#!#test_sp_babelfish_volatility_f1#!#volatile +dbo#!#test_sp_babelfish_volatility_f1#!#stable ~~END~~ -exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'stable' +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable' go exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' go ~~START~~ nvarchar#!#varchar#!#text -dbo#!#test_sp_babelfish_volatility_f1#!#stable +dbo#!#test_sp_babelfish_volatility_f1#!#immutable ~~END~~ -exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable' +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'stable' go exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' go ~~START~~ nvarchar#!#varchar#!#text -dbo#!#test_sp_babelfish_volatility_f1#!#immutable +dbo#!#test_sp_babelfish_volatility_f1#!#stable ~~END~~ exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'volatile' @@ -56,22 +56,22 @@ nvarchar#!#varchar#!#text dbo#!#test_sp_babelfish_volatility_f1#!#volatile ~~END~~ -sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'stable' +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable' go sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' go ~~START~~ nvarchar#!#varchar#!#text -dbo#!#test_sp_babelfish_volatility_f1#!#stable +dbo#!#test_sp_babelfish_volatility_f1#!#immutable ~~END~~ -sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable' +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'stable' go sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' go ~~START~~ nvarchar#!#varchar#!#text -dbo#!#test_sp_babelfish_volatility_f1#!#immutable +dbo#!#test_sp_babelfish_volatility_f1#!#stable ~~END~~ sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'volatile' @@ -102,25 +102,25 @@ exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_b go ~~START~~ nvarchar#!#varchar#!#text -test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#volatile +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#stable ~~END~~ -exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'stable' +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'immutable' go exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' go ~~START~~ nvarchar#!#varchar#!#text -test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#stable +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#immutable ~~END~~ -exec sys.sp_babelfish_volatility '"test_sp_babelfish_volatility_schema1".test_sp_babelfish_volatility_f1', 'immutable' +exec sys.sp_babelfish_volatility '"test_sp_babelfish_volatility_schema1".test_sp_babelfish_volatility_f1', 'stable' go exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' go ~~START~~ nvarchar#!#varchar#!#text -test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#immutable +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#stable ~~END~~ exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1].test_sp_babelfish_volatility_f1', 'volatile' @@ -152,22 +152,22 @@ nvarchar#!#varchar#!#text test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#volatile ~~END~~ -sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'stable' +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'immutable' go sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' go ~~START~~ nvarchar#!#varchar#!#text -test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#stable +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#immutable ~~END~~ -sp_babelfish_volatility '"test_sp_babelfish_volatility_schema1".test_sp_babelfish_volatility_f1', 'immutable' +sp_babelfish_volatility '"test_sp_babelfish_volatility_schema1".test_sp_babelfish_volatility_f1', 'stable' go sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' go ~~START~~ nvarchar#!#varchar#!#text -test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#immutable +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#stable ~~END~~ sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1].test_sp_babelfish_volatility_f1', 'volatile' @@ -312,30 +312,30 @@ exec sys.sp_babelfish_volatility 'test_bbf_vol_f1' go ~~START~~ nvarchar#!#varchar#!#text -dbo#!#test_bbf_vol_f1#!#volatile +dbo#!#test_bbf_vol_f1#!#stable ~~END~~ exec sys.sp_babelfish_volatility '[test_bbf_vol_f1;drop table test_bbf_vol_t1;]' go ~~START~~ nvarchar#!#varchar#!#text -dbo#!#test_bbf_vol_f1;drop table test_bbf_vol_t1;#!#volatile +dbo#!#test_bbf_vol_f1;drop table test_bbf_vol_t1;#!#stable ~~END~~ -exec sys.sp_babelfish_volatility '[test_bbf_vol_f1;drop table test_bbf_vol_t1;]', 'stable' +exec sys.sp_babelfish_volatility '[test_bbf_vol_f1;drop table test_bbf_vol_t1;]', 'immutable' go exec sys.sp_babelfish_volatility '[test_bbf_vol_f1;drop table test_bbf_vol_t1;]' go ~~START~~ nvarchar#!#varchar#!#text -dbo#!#test_bbf_vol_f1;drop table test_bbf_vol_t1;#!#stable +dbo#!#test_bbf_vol_f1;drop table test_bbf_vol_t1;#!#immutable ~~END~~ exec sys.sp_babelfish_volatility 'test_bbf_vol_f1' go ~~START~~ nvarchar#!#varchar#!#text -dbo#!#test_bbf_vol_f1#!#volatile +dbo#!#test_bbf_vol_f1#!#stable ~~END~~ select * from test_bbf_vol_t1 @@ -357,13 +357,13 @@ dbo#!#test_sp_babelfish_volatility_f1#!#volatile /* testing with dot and spaces in schema name */ -exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1 with .dot and spaces].test_sp_babelfish_volatility_f1', 'stable' +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1 with .dot and spaces].test_sp_babelfish_volatility_f1', 'immutable' go exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1 with .dot and spaces]."test_sp_babelfish_volatility_f1"' go ~~START~~ nvarchar#!#varchar#!#text -test_sp_babelfish_volatility_schema1 with .dot and spaces#!#test_sp_babelfish_volatility_f1#!#stable +test_sp_babelfish_volatility_schema1 with .dot and spaces#!#test_sp_babelfish_volatility_f1#!#immutable ~~END~~ @@ -380,16 +380,16 @@ exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_b go ~~START~~ nvarchar#!#varchar#!#text -test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#volatile +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#stable ~~END~~ -exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1', 'stable' +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1', 'immutable' go exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' go ~~START~~ nvarchar#!#varchar#!#text -test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#stable +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable ~~END~~ /* test with duplicate function name */ @@ -404,32 +404,32 @@ exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_very_lon go ~~START~~ nvarchar#!#varchar#!#text -dbo#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#volatile +dbo#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#stable ~~END~~ -exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa', 'stable' +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa', 'immutable' go exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa]' go ~~START~~ nvarchar#!#varchar#!#text -dbo#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#stable +dbo#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#immutable ~~END~~ exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa' go ~~START~~ nvarchar#!#varchar#!#text -test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#volatile +test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#stable ~~END~~ -exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa', 'stable' +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa', 'immutable' go exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa].[test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa]' go ~~START~~ nvarchar#!#varchar#!#text -test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#stable +test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#immutable ~~END~~ /* test with trucated names */ @@ -437,60 +437,60 @@ exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_fu563bc8b23212e98 go ~~START~~ nvarchar#!#varchar#!#text -dbo#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#stable +dbo#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#immutable ~~END~~ -exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7', 'immutable' +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7', 'volatile' go exec sys.sp_babelfish_volatility '"test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7"' go ~~START~~ nvarchar#!#varchar#!#text -dbo#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#immutable +dbo#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#volatile ~~END~~ exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_scc62ee1eb13f7c4857c426f2affcc9a16.test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7' go ~~START~~ nvarchar#!#varchar#!#text -test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#stable +test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#immutable ~~END~~ -exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_scc62ee1eb13f7c4857c426f2affcc9a16.test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7', 'immutable' +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_scc62ee1eb13f7c4857c426f2affcc9a16.test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7', 'volatile' go exec sys.sp_babelfish_volatility '"test_sp_babelfish_volatility_scc62ee1eb13f7c4857c426f2affcc9a16".[test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7]' go ~~START~~ nvarchar#!#varchar#!#text -test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#immutable +test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#volatile ~~END~~ exec sys.sp_babelfish_volatility go ~~START~~ nvarchar#!#varchar#!#text -dbo#!#test_sp_babelfish_volatility_duplicate#!#volatile -dbo#!#test_sp_babelfish_volatility_duplicate#!#volatile -dbo#!#test_sp_babelfish_volatility_f2#!#volatile -dbo#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#immutable -test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#immutable -test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#stable +dbo#!#test_sp_babelfish_volatility_duplicate#!#stable +dbo#!#test_sp_babelfish_volatility_duplicate#!#stable +dbo#!#test_sp_babelfish_volatility_f2#!#stable +dbo#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#volatile +test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#volatile +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable ~~END~~ exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' go ~~START~~ nvarchar#!#varchar#!#text -dbo#!#test_sp_babelfish_volatility_f2#!#volatile +dbo#!#test_sp_babelfish_volatility_f2#!#stable ~~END~~ -exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2', 'stable' +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2', 'immutable' go exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' go ~~START~~ nvarchar#!#varchar#!#text -dbo#!#test_sp_babelfish_volatility_f2#!#stable +dbo#!#test_sp_babelfish_volatility_f2#!#immutable ~~END~~ @@ -558,44 +558,44 @@ exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_b go ~~START~~ nvarchar#!#varchar#!#text -test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#stable +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable ~~END~~ exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' go ~~START~~ nvarchar#!#varchar#!#text -dbo#!#test_sp_babelfish_volatility_f2#!#stable +dbo#!#test_sp_babelfish_volatility_f2#!#immutable ~~END~~ exec sys.sp_babelfish_volatility go ~~START~~ nvarchar#!#varchar#!#text -dbo#!#test_sp_babelfish_volatility_f2#!#stable -test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#stable +dbo#!#test_sp_babelfish_volatility_f2#!#immutable +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable ~~END~~ sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' go ~~START~~ nvarchar#!#varchar#!#text -test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#stable +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable ~~END~~ sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' go ~~START~~ nvarchar#!#varchar#!#text -dbo#!#test_sp_babelfish_volatility_f2#!#stable +dbo#!#test_sp_babelfish_volatility_f2#!#immutable ~~END~~ sp_babelfish_volatility go ~~START~~ nvarchar#!#varchar#!#text -dbo#!#test_sp_babelfish_volatility_f2#!#stable -test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#stable +dbo#!#test_sp_babelfish_volatility_f2#!#immutable +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable ~~END~~ @@ -620,14 +620,14 @@ exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' go ~~START~~ nvarchar#!#varchar#!#text -test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#stable +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable ~~END~~ exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1 ' go ~~START~~ nvarchar#!#varchar#!#text -test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#stable +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable ~~END~~ exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' @@ -640,15 +640,15 @@ exec sys.sp_babelfish_volatility 'dbo.test_sp_babelfish_volatility_f2' go ~~START~~ nvarchar#!#varchar#!#text -dbo#!#test_sp_babelfish_volatility_f2#!#stable +dbo#!#test_sp_babelfish_volatility_f2#!#immutable ~~END~~ exec sys.sp_babelfish_volatility go ~~START~~ nvarchar#!#varchar#!#text -dbo#!#test_sp_babelfish_volatility_f2#!#stable -test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#stable +dbo#!#test_sp_babelfish_volatility_f2#!#immutable +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable ~~END~~ @@ -684,16 +684,16 @@ sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' go ~~START~~ nvarchar#!#varchar#!#text -guest#!#test_sp_babelfish_volatility_f1#!#volatile +guest#!#test_sp_babelfish_volatility_f1#!#stable ~~END~~ -sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'stable'; +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable'; go sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' go ~~START~~ nvarchar#!#varchar#!#text -guest#!#test_sp_babelfish_volatility_f1#!#stable +guest#!#test_sp_babelfish_volatility_f1#!#immutable ~~END~~ sp_babelfish_volatility 'dbo.test_sp_babelfish_volatility_f2' @@ -706,7 +706,7 @@ sp_babelfish_volatility go ~~START~~ nvarchar#!#varchar#!#text -guest#!#test_sp_babelfish_volatility_f1#!#stable +guest#!#test_sp_babelfish_volatility_f1#!#immutable ~~END~~ drop function test_sp_babelfish_volatility_f1 diff --git a/test/JDBC/expected/create_function_default_stable-vu-cleanup.out b/test/JDBC/expected/create_function_default_stable-vu-cleanup.out new file mode 100644 index 0000000000..2726a4e97c --- /dev/null +++ b/test/JDBC/expected/create_function_default_stable-vu-cleanup.out @@ -0,0 +1,130 @@ +-- tsql + +use test_create_function_default_stable_db +go + +drop function test_create_function_default_stable_f1 +go + +drop function test_create_function_default_stable_f2 +go + +drop function test_create_function_default_stable_tvp_f1 +go + +drop function test_create_function_default_stable_tvp_f2 +go + +drop function test_create_function_default_stable_tvp_f3 +go + +drop function test_create_function_default_stable_tvp_f4 +go + +drop function test_create_function_default_stable_tvp_f5 +go + +drop function test_create_function_default_stable_tvf_f1 +go + +drop function test_create_function_default_stable_tvf_f2 +go + +drop function test_create_function_default_stable_tvptvf_f1 +go + +drop function test_create_function_default_stable_tvptvf_f2 +go + +drop function test_create_function_default_stable_nested_f1 +go + +drop function test_create_function_default_stable_nested_f2 +go + +drop function test_create_function_default_stable_nested_f3 +go + +drop function test_create_function_default_stable_nested_f4 +go + +drop function test_create_function_default_stable_nested_f5 +go + +drop function test_create_function_default_stable_nested_f6 +go + +drop function test_create_function_default_stable_nested_f7 +go + +-- psql +drop function test_create_function_default_stable_tsql_f1 +go + +drop function test_create_function_default_stable_tsql_f2 +go + +drop function test_create_function_default_stable_tsql_f3 +go + +drop function test_create_function_default_stable_tsql_f4 +go + +drop function test_create_function_default_stable_tsql_f5 +go + +drop table test_create_function_default_stable_tsql_t1 +go + +drop type test_create_function_default_stable_tsql_type +go + +-- tsql +drop table test_create_function_default_stable_t1 +go + +drop type test_create_function_default_stable_type +go + +use master +go + +drop database test_create_function_default_stable_db +go + +-- psql +drop function test_create_function_default_stable_psql_f1; +go + +drop function test_create_function_default_stable_psql_f2; +go + +drop function test_create_function_default_stable_psql_f3; +go + +drop function test_create_function_default_stable_psql_f4; +go + +drop function test_create_function_default_stable_psql_f5; +go + +drop function test_create_function_default_stable_psql_f6; +go + +drop function test_create_function_default_stable_psql_f7; +go + +drop function test_create_function_default_stable_psql_f8; +go + +drop function test_create_function_default_stable_psql_f9; +go + +drop function test_create_function_default_stable_psql_f10; +go + +drop function test_create_function_default_stable_psql_f11; +go + +drop function test_create_function_default_stable_psql_f12; +go diff --git a/test/JDBC/expected/create_function_default_stable-vu-prepare.out b/test/JDBC/expected/create_function_default_stable-vu-prepare.out new file mode 100644 index 0000000000..cb76fc4326 --- /dev/null +++ b/test/JDBC/expected/create_function_default_stable-vu-prepare.out @@ -0,0 +1,284 @@ +-- tsql +create database test_create_function_default_stable_db +go + +use test_create_function_default_stable_db +go + +create table test_create_function_default_stable_t1(a int) +go + +create type test_create_function_default_stable_type AS TABLE(a int) +go + +-- create functions not having tvp or tvf +create function test_create_function_default_stable_f1() returns int as begin return 0; end +go + +create function test_create_function_default_stable_f2(@a int, @b char, @c date, @d money, @e float, @f text, @g xml) +returns int as begin return 0; end +go + +-- create functions with tvp +-- 1. tvp is declared inside the function +create function test_create_function_default_stable_tvp_f1() +returns int as begin declare @tvp table(a int); +insert into @tvp values(1); return 0; end +go + +create function test_create_function_default_stable_tvp_f2() +returns int as begin declare @tvp test_create_function_default_stable_type; +insert into @tvp values(1); return 0; end +go + +create function test_create_function_default_stable_tvp_f3() +returns int as begin declare @tvp test_create_function_default_stable_type; +return 0; end +go + +-- 2. tvp passed as argument +create function test_create_function_default_stable_tvp_f4(@tvp test_create_function_default_stable_type readonly) +returns int as begin return 0; end +go + +create function test_create_function_default_stable_tvp_f5(@tvp test_create_function_default_stable_type readonly) +returns int as begin insert into @tvp values(1) return 0;end +go + +-- create functions with tvf +create function test_create_function_default_stable_tvf_f1() returns table as return (SELECT * from test_create_function_default_stable_t1) +go + +create function test_create_function_default_stable_tvf_f2(@a int) +returns @tv table(b int) +AS BEGIN +update @tv set b = 1 where b = 2 +return end +go + +-- create function having both tvp and tvf +create function test_create_function_default_stable_tvptvf_f1(@tvp test_create_function_default_stable_type readonly) +returns table as return (SELECT * from test_create_function_default_stable_t1) +go + +create function test_create_function_default_stable_tvptvf_f2(@a int, @tvp1 test_create_function_default_stable_type readonly) +returns @tvp2 table(b int) +AS BEGIN +update @tvp2 set b = 1 where b = 2 +return end +go + +-- nested functions +create function test_create_function_default_stable_nested_f1() +returns int as begin +exec test_create_function_default_stable_tvp_f1; +return 0; end +go + +create function test_create_function_default_stable_nested_f2() +returns int as begin +declare @tvp test_create_function_default_stable_type +exec test_create_function_default_stable_tvp_f4 @tvp; +return 0; end +go + +create function test_create_function_default_stable_nested_f3() +returns table as +return (SELECT * from test_create_function_default_stable_tvf_f2(1)) +go + +create function test_create_function_default_stable_nested_f4() +returns table as +return (SELECT * from test_create_function_default_stable_tvp_f1()) +go + +create function test_create_function_default_stable_nested_f5() +returns table as +return (SELECT * from test_create_function_default_stable_f1()) +go + +create function test_create_function_default_stable_nested_f6(@a int) +returns @tv table(b int) +AS BEGIN +Declare @b int; +exec test_create_function_default_stable_f1; +update @tv set b = 1 where b = 2 +return end +go + +create function test_create_function_default_stable_nested_f7() +returns int as begin +exec test_create_function_default_stable_f1; +return 0; end +go + +-- create procedure and check +create procedure test_create_function_default_stable_p1 +as +declare @a int; +go + +create procedure test_create_function_default_stable_p2 +as +select * from test_create_function_default_stable_t1; +go + +create procedure test_create_function_default_stable_p3 +as +declare @tvp test_create_function_default_stable_type; +select * from @tvp; +go + +-- psql +-- create function in tsql dialect +set babelfishpg_tsql.sql_dialect = "tsql"; +go + +create table test_create_function_default_stable_tsql_t1(a int) +go + +create type test_create_function_default_stable_tsql_type AS TABLE(a int) +go + +create function test_create_function_default_stable_tsql_f1() +returns int +as begin +return 0 +end +go + +create function test_create_function_default_stable_tsql_f2() +returns int +as begin +declare @tvp table(a int) +insert into @tvp values(1) +return 0 +end +go + +create function test_create_function_default_stable_tsql_f3(@tvp test_create_function_default_stable_tsql_type readonly) +returns int +as begin +return 0 +end +go + +create function test_create_function_default_stable_tsql_f4() returns table as return (SELECT * from test_create_function_default_stable_tsql_t1); +go + +create function test_create_function_default_stable_tsql_f5(@a int) +returns @tv table(b int) +AS BEGIN +update @tv set b = 1 where b = 2 +return end +go + +reset babelfishpg_tsql.sql_dialect; +go + +-- psql + +-- create function in psql endpoint +-- with language plpgsql +create function test_create_function_default_stable_psql_f1() +returns int +language plpgsql +as +$$ +declare a int; +begin + a := 1; +return a; +end; +$$; +go + +-- with language sql +create function test_create_function_default_stable_psql_f2() RETURNS char(20) language SQL return 'abc'; +go + +-- with language pltsql +CREATE OR REPLACE FUNCTION test_create_function_default_stable_psql_f3() RETURNS int AS $$ +BEGIN + DECLARE @a int = 1; + RETURN @a +END; +$$ LANGUAGE pltsql; +go + +CREATE OR REPLACE FUNCTION test_create_function_default_stable_psql_f4() RETURNS int AS $$ +BEGIN + DECLARE @a int = 1; + RETURN @a +END; +$$ LANGUAGE pltsql VOLATILE; +go + +CREATE OR REPLACE FUNCTION test_create_function_default_stable_psql_f5() RETURNS int AS $$ +BEGIN + DECLARE @a int = 1; + RETURN @a +END; +$$ LANGUAGE pltsql STABLE; +go + +CREATE OR REPLACE FUNCTION test_create_function_default_stable_psql_f6() RETURNS int AS $$ +BEGIN + DECLARE @a int = 1; + RETURN @a +END; +$$ LANGUAGE pltsql IMMUTABLE; +go + +-- with table variable +CREATE OR REPLACE FUNCTION test_create_function_default_stable_psql_f7() RETURNS int AS $$ +BEGIN + DECLARE @a int = 1; + declare @tvp table(a int); + RETURN @a +END; +$$ LANGUAGE pltsql; +go + +CREATE OR REPLACE FUNCTION test_create_function_default_stable_psql_f8() RETURNS int AS $$ +BEGIN + DECLARE @a int = 1; + declare @tvp table(a int); + RETURN @a +END; +$$ LANGUAGE pltsql VOLATILE; +go + +CREATE OR REPLACE FUNCTION test_create_function_default_stable_psql_f9() RETURNS int AS $$ +BEGIN + DECLARE @a int = 1; + declare @tvp table(a int); + RETURN @a +END; +$$ LANGUAGE pltsql STABLE; +go + +CREATE OR REPLACE FUNCTION test_create_function_default_stable_psql_f10() RETURNS int AS $$ +BEGIN + DECLARE @a int = 1; + declare @tvp table(a int); + RETURN @a +END; +$$ LANGUAGE pltsql IMMUTABLE; +go + +-- with record datatypes +CREATE OR REPLACE FUNCTION test_create_function_default_stable_psql_f11() RETURNS int AS $$ +declare rec record; +begin +return 1; +end; +$$ LANGUAGE plpgsql; +go + +CREATE OR REPLACE FUNCTION test_create_function_default_stable_psql_f12(rec record) RETURNS int AS $$ +begin +return 1; +end; +$$ LANGUAGE pltsql; +go diff --git a/test/JDBC/expected/create_function_default_stable-vu-verify.out b/test/JDBC/expected/create_function_default_stable-vu-verify.out new file mode 100644 index 0000000000..46e0f9b3b3 --- /dev/null +++ b/test/JDBC/expected/create_function_default_stable-vu-verify.out @@ -0,0 +1,389 @@ +-- tsql +use test_create_function_default_stable_db +go + +-- not having tvp or tvf +sp_babelfish_volatility 'test_create_function_default_stable_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_create_function_default_stable_f1#!#stable +~~END~~ + +exec test_create_function_default_stable_f1 +go + +sp_babelfish_volatility 'test_create_function_default_stable_f2' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_create_function_default_stable_f2#!#stable +~~END~~ + +exec test_create_function_default_stable_f2 1, 'a', '10/10/10', 1, 1.1, 'abcd', 'aaa' +go + +-- functions with tvp +sp_babelfish_volatility 'test_create_function_default_stable_tvp_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_create_function_default_stable_tvp_f1#!#volatile +~~END~~ + +exec test_create_function_default_stable_tvp_f1 +go + +sp_babelfish_volatility 'test_create_function_default_stable_tvp_f2' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_create_function_default_stable_tvp_f2#!#volatile +~~END~~ + +exec test_create_function_default_stable_tvp_f2 +go + +sp_babelfish_volatility 'test_create_function_default_stable_tvp_f3' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_create_function_default_stable_tvp_f3#!#volatile +~~END~~ + +exec test_create_function_default_stable_tvp_f3 +go + +sp_babelfish_volatility 'test_create_function_default_stable_tvp_f4' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_create_function_default_stable_tvp_f4#!#volatile +~~END~~ + +declare @tvp test_create_function_default_stable_type +exec test_create_function_default_stable_tvp_f4 @tvp +go + +sp_babelfish_volatility 'test_create_function_default_stable_tvp_f5' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_create_function_default_stable_tvp_f5#!#volatile +~~END~~ + +declare @tvp test_create_function_default_stable_type +exec test_create_function_default_stable_tvp_f5 @tvp +go + +-- functions with tvf +sp_babelfish_volatility 'test_create_function_default_stable_tvf_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_create_function_default_stable_tvf_f1#!#volatile +~~END~~ + +exec test_create_function_default_stable_tvf_f1 +go + +sp_babelfish_volatility 'test_create_function_default_stable_tvf_f2' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_create_function_default_stable_tvf_f2#!#volatile +~~END~~ + +select * from test_create_function_default_stable_tvf_f2(1) +go +~~START~~ +int +~~END~~ + + +-- function with both tvp and tvf +sp_babelfish_volatility 'test_create_function_default_stable_tvptvf_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_create_function_default_stable_tvptvf_f1#!#volatile +~~END~~ + +declare @tvp test_create_function_default_stable_type +exec test_create_function_default_stable_tvptvf_f1 @tvp +go + +sp_babelfish_volatility 'test_create_function_default_stable_tvptvf_f2' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_create_function_default_stable_tvptvf_f2#!#volatile +~~END~~ + +declare @tvp test_create_function_default_stable_type +select * from test_create_function_default_stable_tvptvf_f2(1, @tvp) +go +~~START~~ +int +~~END~~ + + +-- nested functions +sp_babelfish_volatility 'test_create_function_default_stable_nested_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_create_function_default_stable_nested_f1#!#stable +~~END~~ + +exec test_create_function_default_stable_nested_f1 +go + +sp_babelfish_volatility 'test_create_function_default_stable_nested_f2' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_create_function_default_stable_nested_f2#!#volatile +~~END~~ + +exec test_create_function_default_stable_nested_f2 +go + +sp_babelfish_volatility 'test_create_function_default_stable_nested_f3' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_create_function_default_stable_nested_f3#!#volatile +~~END~~ + +select * from test_create_function_default_stable_nested_f3() +go +~~START~~ +int +~~END~~ + + +sp_babelfish_volatility 'test_create_function_default_stable_nested_f4' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_create_function_default_stable_nested_f4#!#volatile +~~END~~ + +select * from test_create_function_default_stable_nested_f4() +go +~~START~~ +int +0 +~~END~~ + + +sp_babelfish_volatility 'test_create_function_default_stable_nested_f5' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_create_function_default_stable_nested_f5#!#volatile +~~END~~ + +select * from test_create_function_default_stable_nested_f5() +go +~~START~~ +int +0 +~~END~~ + + +sp_babelfish_volatility 'test_create_function_default_stable_nested_f6' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_create_function_default_stable_nested_f6#!#volatile +~~END~~ + +select * from test_create_function_default_stable_nested_f6(1) +go +~~START~~ +int +~~END~~ + + +sp_babelfish_volatility 'test_create_function_default_stable_nested_f7' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_create_function_default_stable_nested_f7#!#stable +~~END~~ + +select test_create_function_default_stable_nested_f7() +go +~~START~~ +int +0 +~~END~~ + + +-- check with procedure +select provolatile from pg_proc where proname = 'test_create_function_default_stable_p1' +go +~~START~~ +varchar +v +~~END~~ + + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_p2' +go +~~START~~ +varchar +v +~~END~~ + + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_p3' +go +~~START~~ +varchar +v +~~END~~ + + +-- psql +-- check for tsql dialect +select provolatile from pg_proc where proname = 'test_create_function_default_stable_tsql_f1' +go +~~START~~ +char +s +~~END~~ + + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_tsql_f2' +go +~~START~~ +char +v +~~END~~ + + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_tsql_f3' +go +~~START~~ +char +v +~~END~~ + + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_tsql_f4' +go +~~START~~ +char +v +~~END~~ + + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_tsql_f5' +go +~~START~~ +char +v +~~END~~ + + + +-- psql +-- check volatility for psql functions +select provolatile from pg_proc where proname = 'test_create_function_default_stable_psql_f1'; +go +~~START~~ +char +v +~~END~~ + + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_psql_f2'; +go +~~START~~ +char +v +~~END~~ + + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_psql_f3'; +go +~~START~~ +char +v +~~END~~ + + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_psql_f4'; +go +~~START~~ +char +v +~~END~~ + + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_psql_f5'; +go +~~START~~ +char +s +~~END~~ + + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_psql_f6'; +go +~~START~~ +char +i +~~END~~ + + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_psql_f7'; +go +~~START~~ +char +v +~~END~~ + + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_psql_f8'; +go +~~START~~ +char +v +~~END~~ + + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_psql_f9'; +go +~~START~~ +char +v +~~END~~ + + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_psql_f10'; +go +~~START~~ +char +v +~~END~~ + + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_psql_f11'; +go +~~START~~ +char +v +~~END~~ + + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_psql_f12'; +go +~~START~~ +char +v +~~END~~ + diff --git a/test/JDBC/expected/latest__verification_cleanup__14_6__BABEL-2877-vu-cleanup.out b/test/JDBC/expected/latest__verification_cleanup__14_6__BABEL-2877-vu-cleanup.out new file mode 100644 index 0000000000..2b3ac2c392 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__14_6__BABEL-2877-vu-cleanup.out @@ -0,0 +1,46 @@ +DROP VIEW babel_2877_vu_prepare_view1; +GO + +DROP VIEW babel_2877_vu_prepare_view2; +GO + +DROP VIEW babel_2877_vu_prepare_view3; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func1; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func2; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func3; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc1; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc2; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc3; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDON]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDON]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDOFF]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDOFF]; +GO + +-- babelfish_function_ext entry should have been removed after dropping all these functions/procedure +SELECT * FROM sys.babelfish_function_ext WHERE funcname LIKE 'babel_2877_vu_prepare%'; +GO +~~START~~ +varchar#!#varchar#!#nvarchar#!#text#!#text#!#bigint#!#bigint#!#datetime#!#datetime#!#ntext +~~END~~ + diff --git a/test/JDBC/expected/latest__verification_cleanup__14_6__BABEL-2877-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__14_6__BABEL-2877-vu-verify.out new file mode 100644 index 0000000000..5970f8ab19 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__14_6__BABEL-2877-vu-verify.out @@ -0,0 +1,229 @@ +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func1' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE FUNCTION master_dbo.babel_2877_vu_prepare_func1("@a" integer, "@b" "varchar" DEFAULT 'abc'::"varchar", "@c" money, "@d" double precision DEFAULT 1.2) RETURNS "varchar" LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1", "100"], "original_probin": ""}', $function$BEGIN RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10));END$function$ +~~END~~ + + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func2' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE FUNCTION master_dbo.babel_2877_vu_prepare_func2("@a" integer DEFAULT 10, "@b" "varchar" DEFAULT 'abc'::"varchar", "@c" money DEFAULT 5, "@d" double precision DEFAULT 1.2) RETURNS "varchar" LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1", "100"], "original_probin": ""}', $function$BEGIN RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10));END$function$ +~~END~~ + + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func3' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE FUNCTION master_dbo.babel_2877_vu_prepare_func3("@a" integer, "@b" "varchar", "@c" money, "@d" double precision) RETURNS "varchar" LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1", "100"], "original_probin": ""}', $function$BEGIN RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10));END$function$ +~~END~~ + + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc1' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE PROCEDURE master_dbo.babel_2877_vu_prepare_proc1(IN "@a" integer, IN "@b" "varchar" DEFAULT 'abc'::"varchar", IN "@c" money DEFAULT 5, IN "@d" double precision) LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1"], "original_probin": ""}', $procedure$BEGIN SELECT @a, @b, @c, @d;END$procedure$ +~~END~~ + + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc2' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE PROCEDURE master_dbo.babel_2877_vu_prepare_proc2(IN "@a" integer DEFAULT 10, IN "@b" "varchar" DEFAULT 'abc'::"varchar", IN "@c" money DEFAULT 5, IN "@d" double precision DEFAULT 1.2) LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1"], "original_probin": ""}', $procedure$BEGIN SELECT @a, @b, @c, @d;END$procedure$ +~~END~~ + + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc3' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE PROCEDURE master_dbo.babel_2877_vu_prepare_proc3(IN "@a" integer, IN "@b" "varchar", IN "@c" money, IN "@d" double precision) LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1"], "original_probin": ""}', $procedure$BEGIN SELECT @a, @b, @c, @d;END$procedure$ +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_func1(10); -- should fail, required argument @c not supplied +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: function babel_2877_vu_prepare_func1 expects parameter "@c", which was not supplied.)~~ + + +SELECT * FROM babel_2877_vu_prepare_func1(10, 'abc', $5); +GO +~~START~~ +varchar +10abc5.00001.2 +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_func2(); +GO +~~START~~ +varchar +10abc5.00001.2 +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_func3(); -- should fail, all parameters are required +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: function babel_2877_vu_prepare_func3 expects parameter "@a", which was not supplied.)~~ + + +SELECT * FROM babel_2877_vu_prepare_func3(10, 'abc', $5, 1.2); +GO +~~START~~ +varchar +10abc5.00001.2 +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_view1; +GO +~~START~~ +varchar +20def5.00001.2 +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_view2; +GO +~~START~~ +varchar +10abc5.00001.2 +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_view3; +GO +~~START~~ +varchar +20def10.00001.8 +~~END~~ + + +EXEC babel_2877_vu_prepare_proc1; -- should fail, required arguments @a and @d not supplied +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: procedure babel_2877_vu_prepare_proc1 expects parameter "@a", which was not supplied.)~~ + + +EXEC babel_2877_vu_prepare_proc1 10; -- should fail, required argument @d not supplied +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: procedure babel_2877_vu_prepare_proc1 expects parameter "@d", which was not supplied.)~~ + + +EXEC babel_2877_vu_prepare_proc1 @d=40; -- should fail, required argument @a not supplied +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: procedure babel_2877_vu_prepare_proc1 expects parameter "@a", which was not supplied.)~~ + + +EXEC babel_2877_vu_prepare_proc1 @a = 10, @d = 1.8; +GO +~~START~~ +int#!#varchar#!#money#!#float +10#!#abc#!#5.0000#!#1.8 +~~END~~ + + +EXEC babel_2877_vu_prepare_proc1 @a = 10, @b = 20, @c = 30, @d = 40; +GO +~~START~~ +int#!#varchar#!#money#!#float +10#!#20#!#30.0000#!#40.0 +~~END~~ + + +EXEC babel_2877_vu_prepare_proc2; +GO +~~START~~ +int#!#varchar#!#money#!#float +10#!#abc#!#5.0000#!#1.2 +~~END~~ + + +EXEC babel_2877_vu_prepare_proc2 @d = 1.5; +GO +~~START~~ +int#!#varchar#!#money#!#float +10#!#abc#!#5.0000#!#1.5 +~~END~~ + + +EXEC babel_2877_vu_prepare_proc3; -- should fail, all parameters are required +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: procedure babel_2877_vu_prepare_proc3 expects parameter "@a", which was not supplied.)~~ + + +EXEC babel_2877_vu_prepare_proc3 10, 'def', $10, 1.8; -- should fail, all parameters are required +GO +~~START~~ +int#!#varchar#!#money#!#float +10#!#def#!#10.0000#!#1.8 +~~END~~ + + +-- babelfish_function_ext table should have entry for all the above functions and procedures +SELECT nspname, + funcname, + funcsignature, + default_positions +FROM sys.babelfish_function_ext + WHERE funcname LIKE 'babel_2877_vu_prepare%' + AND funcname NOT LIKE '%ansi%' ORDER BY funcname; +GO +~~START~~ +varchar#!#varchar#!#text#!#text +master_dbo#!#babel_2877_vu_prepare_func1#!#babel_2877_vu_prepare_func1(integer, "sys"."varchar", "sys"."money", double precision)#!#(1 3) +master_dbo#!#babel_2877_vu_prepare_func2#!#babel_2877_vu_prepare_func2(integer, "sys"."varchar", "sys"."money", double precision)#!#(0 1 2 3) +master_dbo#!#babel_2877_vu_prepare_func3#!#babel_2877_vu_prepare_func3(integer, "sys"."varchar", "sys"."money", double precision)#!# +master_dbo#!#babel_2877_vu_prepare_proc1#!#babel_2877_vu_prepare_proc1(integer, "sys"."varchar", "sys"."money", double precision)#!#(1 2) +master_dbo#!#babel_2877_vu_prepare_proc2#!#babel_2877_vu_prepare_proc2(integer, "sys"."varchar", "sys"."money", double precision)#!#(0 1 2 3) +master_dbo#!#babel_2877_vu_prepare_proc3#!#babel_2877_vu_prepare_proc3(integer, "sys"."varchar", "sys"."money", double precision)#!# +~~END~~ + + +SELECT orig_name, + CASE flag_validity & 1 + WHEN 0 + THEN NULL + ELSE + CASE flag_values & 1 + WHEN 0 + THEN 0 + ELSE 1 + END + END AS ansi_null, + CASE flag_validity & 2 + WHEN 0 + THEN NULL + ELSE + CASE flag_values & 2 + WHEN 0 + THEN 0 + ELSE 1 + END + END AS quoted_identifier +FROM sys.babelfish_function_ext WHERE funcname LIKE 'babel-2877-vu-prepare%' ORDER BY funcname; +GO +~~START~~ +nvarchar#!#int#!#int +BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDOFF#!#0#!#0 +BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDON#!#0#!#1 +BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDOFF#!#1#!#0 +BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDON#!#1#!#1 +~~END~~ + diff --git a/test/JDBC/expected/latest__verification_cleanup__14_7__BABEL-2877-vu-cleanup.out b/test/JDBC/expected/latest__verification_cleanup__14_7__BABEL-2877-vu-cleanup.out new file mode 100644 index 0000000000..2b3ac2c392 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__14_7__BABEL-2877-vu-cleanup.out @@ -0,0 +1,46 @@ +DROP VIEW babel_2877_vu_prepare_view1; +GO + +DROP VIEW babel_2877_vu_prepare_view2; +GO + +DROP VIEW babel_2877_vu_prepare_view3; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func1; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func2; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func3; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc1; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc2; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc3; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDON]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDON]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDOFF]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDOFF]; +GO + +-- babelfish_function_ext entry should have been removed after dropping all these functions/procedure +SELECT * FROM sys.babelfish_function_ext WHERE funcname LIKE 'babel_2877_vu_prepare%'; +GO +~~START~~ +varchar#!#varchar#!#nvarchar#!#text#!#text#!#bigint#!#bigint#!#datetime#!#datetime#!#ntext +~~END~~ + diff --git a/test/JDBC/expected/latest__verification_cleanup__14_7__BABEL-2877-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__14_7__BABEL-2877-vu-verify.out new file mode 100644 index 0000000000..5970f8ab19 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__14_7__BABEL-2877-vu-verify.out @@ -0,0 +1,229 @@ +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func1' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE FUNCTION master_dbo.babel_2877_vu_prepare_func1("@a" integer, "@b" "varchar" DEFAULT 'abc'::"varchar", "@c" money, "@d" double precision DEFAULT 1.2) RETURNS "varchar" LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1", "100"], "original_probin": ""}', $function$BEGIN RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10));END$function$ +~~END~~ + + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func2' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE FUNCTION master_dbo.babel_2877_vu_prepare_func2("@a" integer DEFAULT 10, "@b" "varchar" DEFAULT 'abc'::"varchar", "@c" money DEFAULT 5, "@d" double precision DEFAULT 1.2) RETURNS "varchar" LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1", "100"], "original_probin": ""}', $function$BEGIN RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10));END$function$ +~~END~~ + + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func3' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE FUNCTION master_dbo.babel_2877_vu_prepare_func3("@a" integer, "@b" "varchar", "@c" money, "@d" double precision) RETURNS "varchar" LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1", "100"], "original_probin": ""}', $function$BEGIN RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10));END$function$ +~~END~~ + + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc1' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE PROCEDURE master_dbo.babel_2877_vu_prepare_proc1(IN "@a" integer, IN "@b" "varchar" DEFAULT 'abc'::"varchar", IN "@c" money DEFAULT 5, IN "@d" double precision) LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1"], "original_probin": ""}', $procedure$BEGIN SELECT @a, @b, @c, @d;END$procedure$ +~~END~~ + + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc2' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE PROCEDURE master_dbo.babel_2877_vu_prepare_proc2(IN "@a" integer DEFAULT 10, IN "@b" "varchar" DEFAULT 'abc'::"varchar", IN "@c" money DEFAULT 5, IN "@d" double precision DEFAULT 1.2) LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1"], "original_probin": ""}', $procedure$BEGIN SELECT @a, @b, @c, @d;END$procedure$ +~~END~~ + + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc3' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE PROCEDURE master_dbo.babel_2877_vu_prepare_proc3(IN "@a" integer, IN "@b" "varchar", IN "@c" money, IN "@d" double precision) LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1"], "original_probin": ""}', $procedure$BEGIN SELECT @a, @b, @c, @d;END$procedure$ +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_func1(10); -- should fail, required argument @c not supplied +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: function babel_2877_vu_prepare_func1 expects parameter "@c", which was not supplied.)~~ + + +SELECT * FROM babel_2877_vu_prepare_func1(10, 'abc', $5); +GO +~~START~~ +varchar +10abc5.00001.2 +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_func2(); +GO +~~START~~ +varchar +10abc5.00001.2 +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_func3(); -- should fail, all parameters are required +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: function babel_2877_vu_prepare_func3 expects parameter "@a", which was not supplied.)~~ + + +SELECT * FROM babel_2877_vu_prepare_func3(10, 'abc', $5, 1.2); +GO +~~START~~ +varchar +10abc5.00001.2 +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_view1; +GO +~~START~~ +varchar +20def5.00001.2 +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_view2; +GO +~~START~~ +varchar +10abc5.00001.2 +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_view3; +GO +~~START~~ +varchar +20def10.00001.8 +~~END~~ + + +EXEC babel_2877_vu_prepare_proc1; -- should fail, required arguments @a and @d not supplied +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: procedure babel_2877_vu_prepare_proc1 expects parameter "@a", which was not supplied.)~~ + + +EXEC babel_2877_vu_prepare_proc1 10; -- should fail, required argument @d not supplied +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: procedure babel_2877_vu_prepare_proc1 expects parameter "@d", which was not supplied.)~~ + + +EXEC babel_2877_vu_prepare_proc1 @d=40; -- should fail, required argument @a not supplied +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: procedure babel_2877_vu_prepare_proc1 expects parameter "@a", which was not supplied.)~~ + + +EXEC babel_2877_vu_prepare_proc1 @a = 10, @d = 1.8; +GO +~~START~~ +int#!#varchar#!#money#!#float +10#!#abc#!#5.0000#!#1.8 +~~END~~ + + +EXEC babel_2877_vu_prepare_proc1 @a = 10, @b = 20, @c = 30, @d = 40; +GO +~~START~~ +int#!#varchar#!#money#!#float +10#!#20#!#30.0000#!#40.0 +~~END~~ + + +EXEC babel_2877_vu_prepare_proc2; +GO +~~START~~ +int#!#varchar#!#money#!#float +10#!#abc#!#5.0000#!#1.2 +~~END~~ + + +EXEC babel_2877_vu_prepare_proc2 @d = 1.5; +GO +~~START~~ +int#!#varchar#!#money#!#float +10#!#abc#!#5.0000#!#1.5 +~~END~~ + + +EXEC babel_2877_vu_prepare_proc3; -- should fail, all parameters are required +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: procedure babel_2877_vu_prepare_proc3 expects parameter "@a", which was not supplied.)~~ + + +EXEC babel_2877_vu_prepare_proc3 10, 'def', $10, 1.8; -- should fail, all parameters are required +GO +~~START~~ +int#!#varchar#!#money#!#float +10#!#def#!#10.0000#!#1.8 +~~END~~ + + +-- babelfish_function_ext table should have entry for all the above functions and procedures +SELECT nspname, + funcname, + funcsignature, + default_positions +FROM sys.babelfish_function_ext + WHERE funcname LIKE 'babel_2877_vu_prepare%' + AND funcname NOT LIKE '%ansi%' ORDER BY funcname; +GO +~~START~~ +varchar#!#varchar#!#text#!#text +master_dbo#!#babel_2877_vu_prepare_func1#!#babel_2877_vu_prepare_func1(integer, "sys"."varchar", "sys"."money", double precision)#!#(1 3) +master_dbo#!#babel_2877_vu_prepare_func2#!#babel_2877_vu_prepare_func2(integer, "sys"."varchar", "sys"."money", double precision)#!#(0 1 2 3) +master_dbo#!#babel_2877_vu_prepare_func3#!#babel_2877_vu_prepare_func3(integer, "sys"."varchar", "sys"."money", double precision)#!# +master_dbo#!#babel_2877_vu_prepare_proc1#!#babel_2877_vu_prepare_proc1(integer, "sys"."varchar", "sys"."money", double precision)#!#(1 2) +master_dbo#!#babel_2877_vu_prepare_proc2#!#babel_2877_vu_prepare_proc2(integer, "sys"."varchar", "sys"."money", double precision)#!#(0 1 2 3) +master_dbo#!#babel_2877_vu_prepare_proc3#!#babel_2877_vu_prepare_proc3(integer, "sys"."varchar", "sys"."money", double precision)#!# +~~END~~ + + +SELECT orig_name, + CASE flag_validity & 1 + WHEN 0 + THEN NULL + ELSE + CASE flag_values & 1 + WHEN 0 + THEN 0 + ELSE 1 + END + END AS ansi_null, + CASE flag_validity & 2 + WHEN 0 + THEN NULL + ELSE + CASE flag_values & 2 + WHEN 0 + THEN 0 + ELSE 1 + END + END AS quoted_identifier +FROM sys.babelfish_function_ext WHERE funcname LIKE 'babel-2877-vu-prepare%' ORDER BY funcname; +GO +~~START~~ +nvarchar#!#int#!#int +BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDOFF#!#0#!#0 +BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDON#!#0#!#1 +BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDOFF#!#1#!#0 +BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDON#!#1#!#1 +~~END~~ + diff --git a/test/JDBC/expected/latest__verification_cleanup__14_7__Test-sp_babelfish_volatility-vu-cleanup.out b/test/JDBC/expected/latest__verification_cleanup__14_7__Test-sp_babelfish_volatility-vu-cleanup.out new file mode 100644 index 0000000000..80a368ffa7 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__14_7__Test-sp_babelfish_volatility-vu-cleanup.out @@ -0,0 +1,65 @@ +drop function test_sp_babelfish_volatility_f1 +go + +drop function test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1 +go + +drop schema test_sp_babelfish_volatility_schema1 +go + +drop function [test_sp_babelfish_volatility_schema1 with .dot and spaces].test_sp_babelfish_volatility_f1 +go + +drop schema [test_sp_babelfish_volatility_schema1 with .dot and spaces] +go + +use test_sp_babelfish_volatility_db1 +go + +drop function test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1 +go + +drop function test_sp_babelfish_volatility_f2 +go + +drop function test_sp_babelfish_volatility_duplicate() +go + +drop function test_sp_babelfish_volatility_duplicate(@b int) +go + +drop schema test_sp_babelfish_volatility_schema2 +go + +drop function test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa; +go + +drop function test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa; +go + +drop schema test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa; +go + +drop user test_sp_babelfish_volatility_user +go + +drop login test_sp_babelfish_volatility_login_2 +go + +use master +go + +drop database test_sp_babelfish_volatility_db1 +go + +drop login test_sp_babelfish_volatility_login +go + +drop table test_bbf_vol_t1 +go + +drop function test_bbf_vol_f1 +go + +drop function [test_bbf_vol_f1;drop table test_bbf_vol_t1;] +go diff --git a/test/JDBC/expected/latest__verification_cleanup__14_7__Test-sp_babelfish_volatility-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__14_7__Test-sp_babelfish_volatility-vu-verify.out new file mode 100644 index 0000000000..566b7301e4 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__14_7__Test-sp_babelfish_volatility-vu-verify.out @@ -0,0 +1,737 @@ +-- tsql +/* test without schema name */ +use master +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'stable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#stable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'volatile' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'random' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: "random" is not a valid volatility)~~ + +exec sys.sp_babelfish_volatility '.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'stable' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#stable +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'volatile' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'random' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: "random" is not a valid volatility)~~ + +sp_babelfish_volatility '.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + + +/* test with schema name */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility '"test_sp_babelfish_volatility_schema1".test_sp_babelfish_volatility_f1', 'stable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#stable +~~END~~ + +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1].test_sp_babelfish_volatility_f1', 'volatile' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'random' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: "random" is not a valid volatility)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'immutable' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +sp_babelfish_volatility '"test_sp_babelfish_volatility_schema1".test_sp_babelfish_volatility_f1', 'stable' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#stable +~~END~~ + +sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1].test_sp_babelfish_volatility_f1', 'volatile' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'random' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: "random" is not a valid volatility)~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + + +/* testing for trailing spaces */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1 ', 'stable ' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#stable +~~END~~ + + +/* testing for leading space should give error */ +exec sys.sp_babelfish_volatility ' test_sp_babelfish_volatility_f1', 'immutable' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', ' immutable' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: input value is too long for volatility)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#stable +~~END~~ + + +/* testing for some invalid cases */ +exec sys.sp_babelfish_volatility 'master.test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function "master.test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1" is not a valid two part name)~~ + +exec sys.sp_babelfish_volatility 'random_function' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +exec sys.sp_babelfish_volatility '','immutable' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function name is not valid)~~ + +exec sys.sp_babelfish_volatility '' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function name is not valid)~~ + +exec sys.sp_babelfish_volatility NULL, 'stable' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function name cannot be NULL)~~ + +exec sys.sp_babelfish_volatility '. test_sp_babelfish_volatility_f1' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function name is not valid)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_name_for_a_very_long_function_name_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_name_for_a_very_long_function_name_more_longer_longer_than_4000_characters_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: input value is too long for function name)~~ + + +/* testing for injection */ +exec sys.sp_babelfish_volatility 'ran;dom' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable; some random text' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: input value is too long for volatility)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#stable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'rand;om' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: "rand;om" is not a valid volatility)~~ + +/* testing injection in function name */ +exec sys.sp_babelfish_volatility 'test_bbf_vol_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_bbf_vol_f1#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility '[test_bbf_vol_f1;drop table test_bbf_vol_t1;]' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_bbf_vol_f1;drop table test_bbf_vol_t1;#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility '[test_bbf_vol_f1;drop table test_bbf_vol_t1;]', 'immutable' +go +exec sys.sp_babelfish_volatility '[test_bbf_vol_f1;drop table test_bbf_vol_t1;]' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_bbf_vol_f1;drop table test_bbf_vol_t1;#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_bbf_vol_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_bbf_vol_f1#!#volatile +~~END~~ + +select * from test_bbf_vol_t1 +go +~~START~~ +int +~~END~~ + + +/* testing for case insensitive */ +exec sys.sp_babelfish_volatility 'TesT_SP_babelfish_Volatility_f1', 'VolatILe' +go +exec sys.sp_babelfish_volatility 'TesT_Sp_babelfish_Volatility_F1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + + +/* testing with dot and spaces in schema name */ +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1 with .dot and spaces].test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1 with .dot and spaces]."test_sp_babelfish_volatility_f1"' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1 with .dot and spaces#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + + +/* test in a database */ +use test_sp_babelfish_volatility_db1 +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +/* test with duplicate function name */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_duplicate' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: multiple functions with same function name exits)~~ + +/* test with long names */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa', 'immutable' +go +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa]' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa', 'immutable' +go +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa].[test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa]' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#immutable +~~END~~ + +/* test with trucated names */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7', 'volatile' +go +exec sys.sp_babelfish_volatility '"test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7"' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_scc62ee1eb13f7c4857c426f2affcc9a16.test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_scc62ee1eb13f7c4857c426f2affcc9a16.test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7', 'volatile' +go +exec sys.sp_babelfish_volatility '"test_sp_babelfish_volatility_scc62ee1eb13f7c4857c426f2affcc9a16".[test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7]' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_duplicate#!#volatile +dbo#!#test_sp_babelfish_volatility_duplicate#!#volatile +dbo#!#test_sp_babelfish_volatility_f2#!#volatile +dbo#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#volatile +test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#volatile +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f2#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f2#!#immutable +~~END~~ + + +-- tsql user=test_sp_babelfish_volatility_login password=12345678 +/* function on which user has privilege is only visible */ +use test_sp_babelfish_volatility_db1 +go +select current_user +go +~~START~~ +varchar +test_sp_babelfish_volatility_user +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +exec sys.sp_babelfish_volatility 'dbo.test_sp_babelfish_volatility_f2' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: current user does not have priviledges on the function)~~ + +exec sys.sp_babelfish_volatility +go +~~START~~ +nvarchar#!#varchar#!#text +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +sp_babelfish_volatility 'dbo.test_sp_babelfish_volatility_f2' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: current user does not have priviledges on the function)~~ + +sp_babelfish_volatility +go +~~START~~ +nvarchar#!#varchar#!#text +~~END~~ + + +-- tsql +/* grant access to current user */ +use test_sp_babelfish_volatility_db1 +go +grant execute on test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1 to test_sp_babelfish_volatility_user +go +grant execute on test_sp_babelfish_volatility_f2 to test_sp_babelfish_volatility_user +go + +-- tsql user=test_sp_babelfish_volatility_login password=12345678 +use test_sp_babelfish_volatility_db1 +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f2#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f2#!#immutable +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f2#!#immutable +~~END~~ + +sp_babelfish_volatility +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f2#!#immutable +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + + +-- tsql +/* test for default schema */ +use test_sp_babelfish_volatility_db1 +go +ALTER USER test_sp_babelfish_volatility_user WITH DEFAULT_SCHEMA=test_sp_babelfish_volatility_schema2 +GO + +-- tsql user=test_sp_babelfish_volatility_login password=12345678 +use test_sp_babelfish_volatility_db1 +go +select current_user +go +~~START~~ +varchar +test_sp_babelfish_volatility_user +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1 ' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +exec sys.sp_babelfish_volatility 'dbo.test_sp_babelfish_volatility_f2' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f2#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f2#!#immutable +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + + +-- tsql +/* revoke the priviledges to the user */ +use test_sp_babelfish_volatility_db1 +go +revoke execute on test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1 from test_sp_babelfish_volatility_user +go +revoke execute on test_sp_babelfish_volatility_f2 from test_sp_babelfish_volatility_user +go + +-- tsql +/* test default schema in guest user */ +use test_sp_babelfish_volatility_db1 +go +grant connect to guest +go + +-- tsql user=test_sp_babelfish_volatility_login_2 password=12345678 +use test_sp_babelfish_volatility_db1 +go +SELECT current_user +go +~~START~~ +varchar +guest +~~END~~ + +create function test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +guest#!#test_sp_babelfish_volatility_f1#!#stable +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable'; +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +guest#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +sp_babelfish_volatility 'dbo.test_sp_babelfish_volatility_f2' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: current user does not have priviledges on the function)~~ + +sp_babelfish_volatility +go +~~START~~ +nvarchar#!#varchar#!#text +guest#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +drop function test_sp_babelfish_volatility_f1 +go + +-- tsql +use test_sp_babelfish_volatility_db1 +go +revoke connect from guest +go + +-- psql +-- Need to terminate active session before cleaning up the login +SELECT pg_terminate_backend(pid) FROM pg_stat_get_activity(NULL) +WHERE sys.suser_name(usesysid) = 'test_sp_babelfish_volatility_user' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +GO +~~START~~ +bool +~~END~~ + +-- Wait to sync with another session +SELECT pg_sleep(1); +GO +~~START~~ +void + +~~END~~ + diff --git a/test/JDBC/expected/latest__verification_cleanup__14_8__BABEL-2877-vu-cleanup.out b/test/JDBC/expected/latest__verification_cleanup__14_8__BABEL-2877-vu-cleanup.out new file mode 100644 index 0000000000..2b3ac2c392 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__14_8__BABEL-2877-vu-cleanup.out @@ -0,0 +1,46 @@ +DROP VIEW babel_2877_vu_prepare_view1; +GO + +DROP VIEW babel_2877_vu_prepare_view2; +GO + +DROP VIEW babel_2877_vu_prepare_view3; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func1; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func2; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func3; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc1; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc2; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc3; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDON]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDON]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDOFF]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDOFF]; +GO + +-- babelfish_function_ext entry should have been removed after dropping all these functions/procedure +SELECT * FROM sys.babelfish_function_ext WHERE funcname LIKE 'babel_2877_vu_prepare%'; +GO +~~START~~ +varchar#!#varchar#!#nvarchar#!#text#!#text#!#bigint#!#bigint#!#datetime#!#datetime#!#ntext +~~END~~ + diff --git a/test/JDBC/expected/latest__verification_cleanup__14_8__BABEL-2877-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__14_8__BABEL-2877-vu-verify.out new file mode 100644 index 0000000000..5970f8ab19 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__14_8__BABEL-2877-vu-verify.out @@ -0,0 +1,229 @@ +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func1' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE FUNCTION master_dbo.babel_2877_vu_prepare_func1("@a" integer, "@b" "varchar" DEFAULT 'abc'::"varchar", "@c" money, "@d" double precision DEFAULT 1.2) RETURNS "varchar" LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1", "100"], "original_probin": ""}', $function$BEGIN RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10));END$function$ +~~END~~ + + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func2' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE FUNCTION master_dbo.babel_2877_vu_prepare_func2("@a" integer DEFAULT 10, "@b" "varchar" DEFAULT 'abc'::"varchar", "@c" money DEFAULT 5, "@d" double precision DEFAULT 1.2) RETURNS "varchar" LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1", "100"], "original_probin": ""}', $function$BEGIN RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10));END$function$ +~~END~~ + + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func3' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE FUNCTION master_dbo.babel_2877_vu_prepare_func3("@a" integer, "@b" "varchar", "@c" money, "@d" double precision) RETURNS "varchar" LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1", "100"], "original_probin": ""}', $function$BEGIN RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10));END$function$ +~~END~~ + + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc1' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE PROCEDURE master_dbo.babel_2877_vu_prepare_proc1(IN "@a" integer, IN "@b" "varchar" DEFAULT 'abc'::"varchar", IN "@c" money DEFAULT 5, IN "@d" double precision) LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1"], "original_probin": ""}', $procedure$BEGIN SELECT @a, @b, @c, @d;END$procedure$ +~~END~~ + + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc2' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE PROCEDURE master_dbo.babel_2877_vu_prepare_proc2(IN "@a" integer DEFAULT 10, IN "@b" "varchar" DEFAULT 'abc'::"varchar", IN "@c" money DEFAULT 5, IN "@d" double precision DEFAULT 1.2) LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1"], "original_probin": ""}', $procedure$BEGIN SELECT @a, @b, @c, @d;END$procedure$ +~~END~~ + + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc3' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE PROCEDURE master_dbo.babel_2877_vu_prepare_proc3(IN "@a" integer, IN "@b" "varchar", IN "@c" money, IN "@d" double precision) LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1"], "original_probin": ""}', $procedure$BEGIN SELECT @a, @b, @c, @d;END$procedure$ +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_func1(10); -- should fail, required argument @c not supplied +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: function babel_2877_vu_prepare_func1 expects parameter "@c", which was not supplied.)~~ + + +SELECT * FROM babel_2877_vu_prepare_func1(10, 'abc', $5); +GO +~~START~~ +varchar +10abc5.00001.2 +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_func2(); +GO +~~START~~ +varchar +10abc5.00001.2 +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_func3(); -- should fail, all parameters are required +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: function babel_2877_vu_prepare_func3 expects parameter "@a", which was not supplied.)~~ + + +SELECT * FROM babel_2877_vu_prepare_func3(10, 'abc', $5, 1.2); +GO +~~START~~ +varchar +10abc5.00001.2 +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_view1; +GO +~~START~~ +varchar +20def5.00001.2 +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_view2; +GO +~~START~~ +varchar +10abc5.00001.2 +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_view3; +GO +~~START~~ +varchar +20def10.00001.8 +~~END~~ + + +EXEC babel_2877_vu_prepare_proc1; -- should fail, required arguments @a and @d not supplied +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: procedure babel_2877_vu_prepare_proc1 expects parameter "@a", which was not supplied.)~~ + + +EXEC babel_2877_vu_prepare_proc1 10; -- should fail, required argument @d not supplied +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: procedure babel_2877_vu_prepare_proc1 expects parameter "@d", which was not supplied.)~~ + + +EXEC babel_2877_vu_prepare_proc1 @d=40; -- should fail, required argument @a not supplied +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: procedure babel_2877_vu_prepare_proc1 expects parameter "@a", which was not supplied.)~~ + + +EXEC babel_2877_vu_prepare_proc1 @a = 10, @d = 1.8; +GO +~~START~~ +int#!#varchar#!#money#!#float +10#!#abc#!#5.0000#!#1.8 +~~END~~ + + +EXEC babel_2877_vu_prepare_proc1 @a = 10, @b = 20, @c = 30, @d = 40; +GO +~~START~~ +int#!#varchar#!#money#!#float +10#!#20#!#30.0000#!#40.0 +~~END~~ + + +EXEC babel_2877_vu_prepare_proc2; +GO +~~START~~ +int#!#varchar#!#money#!#float +10#!#abc#!#5.0000#!#1.2 +~~END~~ + + +EXEC babel_2877_vu_prepare_proc2 @d = 1.5; +GO +~~START~~ +int#!#varchar#!#money#!#float +10#!#abc#!#5.0000#!#1.5 +~~END~~ + + +EXEC babel_2877_vu_prepare_proc3; -- should fail, all parameters are required +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: procedure babel_2877_vu_prepare_proc3 expects parameter "@a", which was not supplied.)~~ + + +EXEC babel_2877_vu_prepare_proc3 10, 'def', $10, 1.8; -- should fail, all parameters are required +GO +~~START~~ +int#!#varchar#!#money#!#float +10#!#def#!#10.0000#!#1.8 +~~END~~ + + +-- babelfish_function_ext table should have entry for all the above functions and procedures +SELECT nspname, + funcname, + funcsignature, + default_positions +FROM sys.babelfish_function_ext + WHERE funcname LIKE 'babel_2877_vu_prepare%' + AND funcname NOT LIKE '%ansi%' ORDER BY funcname; +GO +~~START~~ +varchar#!#varchar#!#text#!#text +master_dbo#!#babel_2877_vu_prepare_func1#!#babel_2877_vu_prepare_func1(integer, "sys"."varchar", "sys"."money", double precision)#!#(1 3) +master_dbo#!#babel_2877_vu_prepare_func2#!#babel_2877_vu_prepare_func2(integer, "sys"."varchar", "sys"."money", double precision)#!#(0 1 2 3) +master_dbo#!#babel_2877_vu_prepare_func3#!#babel_2877_vu_prepare_func3(integer, "sys"."varchar", "sys"."money", double precision)#!# +master_dbo#!#babel_2877_vu_prepare_proc1#!#babel_2877_vu_prepare_proc1(integer, "sys"."varchar", "sys"."money", double precision)#!#(1 2) +master_dbo#!#babel_2877_vu_prepare_proc2#!#babel_2877_vu_prepare_proc2(integer, "sys"."varchar", "sys"."money", double precision)#!#(0 1 2 3) +master_dbo#!#babel_2877_vu_prepare_proc3#!#babel_2877_vu_prepare_proc3(integer, "sys"."varchar", "sys"."money", double precision)#!# +~~END~~ + + +SELECT orig_name, + CASE flag_validity & 1 + WHEN 0 + THEN NULL + ELSE + CASE flag_values & 1 + WHEN 0 + THEN 0 + ELSE 1 + END + END AS ansi_null, + CASE flag_validity & 2 + WHEN 0 + THEN NULL + ELSE + CASE flag_values & 2 + WHEN 0 + THEN 0 + ELSE 1 + END + END AS quoted_identifier +FROM sys.babelfish_function_ext WHERE funcname LIKE 'babel-2877-vu-prepare%' ORDER BY funcname; +GO +~~START~~ +nvarchar#!#int#!#int +BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDOFF#!#0#!#0 +BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDON#!#0#!#1 +BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDOFF#!#1#!#0 +BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDON#!#1#!#1 +~~END~~ + diff --git a/test/JDBC/expected/latest__verification_cleanup__14_8__Test-sp_babelfish_volatility-vu-cleanup.out b/test/JDBC/expected/latest__verification_cleanup__14_8__Test-sp_babelfish_volatility-vu-cleanup.out new file mode 100644 index 0000000000..80a368ffa7 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__14_8__Test-sp_babelfish_volatility-vu-cleanup.out @@ -0,0 +1,65 @@ +drop function test_sp_babelfish_volatility_f1 +go + +drop function test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1 +go + +drop schema test_sp_babelfish_volatility_schema1 +go + +drop function [test_sp_babelfish_volatility_schema1 with .dot and spaces].test_sp_babelfish_volatility_f1 +go + +drop schema [test_sp_babelfish_volatility_schema1 with .dot and spaces] +go + +use test_sp_babelfish_volatility_db1 +go + +drop function test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1 +go + +drop function test_sp_babelfish_volatility_f2 +go + +drop function test_sp_babelfish_volatility_duplicate() +go + +drop function test_sp_babelfish_volatility_duplicate(@b int) +go + +drop schema test_sp_babelfish_volatility_schema2 +go + +drop function test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa; +go + +drop function test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa; +go + +drop schema test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa; +go + +drop user test_sp_babelfish_volatility_user +go + +drop login test_sp_babelfish_volatility_login_2 +go + +use master +go + +drop database test_sp_babelfish_volatility_db1 +go + +drop login test_sp_babelfish_volatility_login +go + +drop table test_bbf_vol_t1 +go + +drop function test_bbf_vol_f1 +go + +drop function [test_bbf_vol_f1;drop table test_bbf_vol_t1;] +go diff --git a/test/JDBC/expected/latest__verification_cleanup__14_8__Test-sp_babelfish_volatility-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__14_8__Test-sp_babelfish_volatility-vu-verify.out new file mode 100644 index 0000000000..566b7301e4 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__14_8__Test-sp_babelfish_volatility-vu-verify.out @@ -0,0 +1,737 @@ +-- tsql +/* test without schema name */ +use master +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'stable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#stable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'volatile' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'random' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: "random" is not a valid volatility)~~ + +exec sys.sp_babelfish_volatility '.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'stable' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#stable +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'volatile' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'random' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: "random" is not a valid volatility)~~ + +sp_babelfish_volatility '.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + + +/* test with schema name */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility '"test_sp_babelfish_volatility_schema1".test_sp_babelfish_volatility_f1', 'stable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#stable +~~END~~ + +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1].test_sp_babelfish_volatility_f1', 'volatile' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'random' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: "random" is not a valid volatility)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'immutable' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +sp_babelfish_volatility '"test_sp_babelfish_volatility_schema1".test_sp_babelfish_volatility_f1', 'stable' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#stable +~~END~~ + +sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1].test_sp_babelfish_volatility_f1', 'volatile' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'random' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: "random" is not a valid volatility)~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + + +/* testing for trailing spaces */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1 ', 'stable ' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#stable +~~END~~ + + +/* testing for leading space should give error */ +exec sys.sp_babelfish_volatility ' test_sp_babelfish_volatility_f1', 'immutable' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', ' immutable' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: input value is too long for volatility)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#stable +~~END~~ + + +/* testing for some invalid cases */ +exec sys.sp_babelfish_volatility 'master.test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function "master.test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1" is not a valid two part name)~~ + +exec sys.sp_babelfish_volatility 'random_function' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +exec sys.sp_babelfish_volatility '','immutable' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function name is not valid)~~ + +exec sys.sp_babelfish_volatility '' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function name is not valid)~~ + +exec sys.sp_babelfish_volatility NULL, 'stable' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function name cannot be NULL)~~ + +exec sys.sp_babelfish_volatility '. test_sp_babelfish_volatility_f1' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function name is not valid)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_name_for_a_very_long_function_name_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_name_for_a_very_long_function_name_more_longer_longer_than_4000_characters_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: input value is too long for function name)~~ + + +/* testing for injection */ +exec sys.sp_babelfish_volatility 'ran;dom' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable; some random text' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: input value is too long for volatility)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#stable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'rand;om' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: "rand;om" is not a valid volatility)~~ + +/* testing injection in function name */ +exec sys.sp_babelfish_volatility 'test_bbf_vol_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_bbf_vol_f1#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility '[test_bbf_vol_f1;drop table test_bbf_vol_t1;]' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_bbf_vol_f1;drop table test_bbf_vol_t1;#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility '[test_bbf_vol_f1;drop table test_bbf_vol_t1;]', 'immutable' +go +exec sys.sp_babelfish_volatility '[test_bbf_vol_f1;drop table test_bbf_vol_t1;]' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_bbf_vol_f1;drop table test_bbf_vol_t1;#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_bbf_vol_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_bbf_vol_f1#!#volatile +~~END~~ + +select * from test_bbf_vol_t1 +go +~~START~~ +int +~~END~~ + + +/* testing for case insensitive */ +exec sys.sp_babelfish_volatility 'TesT_SP_babelfish_Volatility_f1', 'VolatILe' +go +exec sys.sp_babelfish_volatility 'TesT_Sp_babelfish_Volatility_F1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + + +/* testing with dot and spaces in schema name */ +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1 with .dot and spaces].test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1 with .dot and spaces]."test_sp_babelfish_volatility_f1"' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1 with .dot and spaces#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + + +/* test in a database */ +use test_sp_babelfish_volatility_db1 +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +/* test with duplicate function name */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_duplicate' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: multiple functions with same function name exits)~~ + +/* test with long names */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa', 'immutable' +go +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa]' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa', 'immutable' +go +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa].[test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa]' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#immutable +~~END~~ + +/* test with trucated names */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7', 'volatile' +go +exec sys.sp_babelfish_volatility '"test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7"' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_scc62ee1eb13f7c4857c426f2affcc9a16.test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_scc62ee1eb13f7c4857c426f2affcc9a16.test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7', 'volatile' +go +exec sys.sp_babelfish_volatility '"test_sp_babelfish_volatility_scc62ee1eb13f7c4857c426f2affcc9a16".[test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7]' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_duplicate#!#volatile +dbo#!#test_sp_babelfish_volatility_duplicate#!#volatile +dbo#!#test_sp_babelfish_volatility_f2#!#volatile +dbo#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#volatile +test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#volatile +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f2#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f2#!#immutable +~~END~~ + + +-- tsql user=test_sp_babelfish_volatility_login password=12345678 +/* function on which user has privilege is only visible */ +use test_sp_babelfish_volatility_db1 +go +select current_user +go +~~START~~ +varchar +test_sp_babelfish_volatility_user +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +exec sys.sp_babelfish_volatility 'dbo.test_sp_babelfish_volatility_f2' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: current user does not have priviledges on the function)~~ + +exec sys.sp_babelfish_volatility +go +~~START~~ +nvarchar#!#varchar#!#text +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +sp_babelfish_volatility 'dbo.test_sp_babelfish_volatility_f2' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: current user does not have priviledges on the function)~~ + +sp_babelfish_volatility +go +~~START~~ +nvarchar#!#varchar#!#text +~~END~~ + + +-- tsql +/* grant access to current user */ +use test_sp_babelfish_volatility_db1 +go +grant execute on test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1 to test_sp_babelfish_volatility_user +go +grant execute on test_sp_babelfish_volatility_f2 to test_sp_babelfish_volatility_user +go + +-- tsql user=test_sp_babelfish_volatility_login password=12345678 +use test_sp_babelfish_volatility_db1 +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f2#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f2#!#immutable +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f2#!#immutable +~~END~~ + +sp_babelfish_volatility +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f2#!#immutable +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + + +-- tsql +/* test for default schema */ +use test_sp_babelfish_volatility_db1 +go +ALTER USER test_sp_babelfish_volatility_user WITH DEFAULT_SCHEMA=test_sp_babelfish_volatility_schema2 +GO + +-- tsql user=test_sp_babelfish_volatility_login password=12345678 +use test_sp_babelfish_volatility_db1 +go +select current_user +go +~~START~~ +varchar +test_sp_babelfish_volatility_user +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1 ' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +exec sys.sp_babelfish_volatility 'dbo.test_sp_babelfish_volatility_f2' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f2#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f2#!#immutable +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + + +-- tsql +/* revoke the priviledges to the user */ +use test_sp_babelfish_volatility_db1 +go +revoke execute on test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1 from test_sp_babelfish_volatility_user +go +revoke execute on test_sp_babelfish_volatility_f2 from test_sp_babelfish_volatility_user +go + +-- tsql +/* test default schema in guest user */ +use test_sp_babelfish_volatility_db1 +go +grant connect to guest +go + +-- tsql user=test_sp_babelfish_volatility_login_2 password=12345678 +use test_sp_babelfish_volatility_db1 +go +SELECT current_user +go +~~START~~ +varchar +guest +~~END~~ + +create function test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +guest#!#test_sp_babelfish_volatility_f1#!#stable +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable'; +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +guest#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +sp_babelfish_volatility 'dbo.test_sp_babelfish_volatility_f2' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: current user does not have priviledges on the function)~~ + +sp_babelfish_volatility +go +~~START~~ +nvarchar#!#varchar#!#text +guest#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +drop function test_sp_babelfish_volatility_f1 +go + +-- tsql +use test_sp_babelfish_volatility_db1 +go +revoke connect from guest +go + +-- psql +-- Need to terminate active session before cleaning up the login +SELECT pg_terminate_backend(pid) FROM pg_stat_get_activity(NULL) +WHERE sys.suser_name(usesysid) = 'test_sp_babelfish_volatility_user' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +GO +~~START~~ +bool +~~END~~ + +-- Wait to sync with another session +SELECT pg_sleep(1); +GO +~~START~~ +void + +~~END~~ + diff --git a/test/JDBC/expected/latest__verification_cleanup__15_1__BABEL-2877-vu-cleanup.out b/test/JDBC/expected/latest__verification_cleanup__15_1__BABEL-2877-vu-cleanup.out new file mode 100644 index 0000000000..2b3ac2c392 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__15_1__BABEL-2877-vu-cleanup.out @@ -0,0 +1,46 @@ +DROP VIEW babel_2877_vu_prepare_view1; +GO + +DROP VIEW babel_2877_vu_prepare_view2; +GO + +DROP VIEW babel_2877_vu_prepare_view3; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func1; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func2; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func3; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc1; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc2; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc3; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDON]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDON]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDOFF]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDOFF]; +GO + +-- babelfish_function_ext entry should have been removed after dropping all these functions/procedure +SELECT * FROM sys.babelfish_function_ext WHERE funcname LIKE 'babel_2877_vu_prepare%'; +GO +~~START~~ +varchar#!#varchar#!#nvarchar#!#text#!#text#!#bigint#!#bigint#!#datetime#!#datetime#!#ntext +~~END~~ + diff --git a/test/JDBC/expected/latest__verification_cleanup__15_1__BABEL-2877-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__15_1__BABEL-2877-vu-verify.out new file mode 100644 index 0000000000..5970f8ab19 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__15_1__BABEL-2877-vu-verify.out @@ -0,0 +1,229 @@ +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func1' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE FUNCTION master_dbo.babel_2877_vu_prepare_func1("@a" integer, "@b" "varchar" DEFAULT 'abc'::"varchar", "@c" money, "@d" double precision DEFAULT 1.2) RETURNS "varchar" LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1", "100"], "original_probin": ""}', $function$BEGIN RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10));END$function$ +~~END~~ + + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func2' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE FUNCTION master_dbo.babel_2877_vu_prepare_func2("@a" integer DEFAULT 10, "@b" "varchar" DEFAULT 'abc'::"varchar", "@c" money DEFAULT 5, "@d" double precision DEFAULT 1.2) RETURNS "varchar" LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1", "100"], "original_probin": ""}', $function$BEGIN RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10));END$function$ +~~END~~ + + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func3' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE FUNCTION master_dbo.babel_2877_vu_prepare_func3("@a" integer, "@b" "varchar", "@c" money, "@d" double precision) RETURNS "varchar" LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1", "100"], "original_probin": ""}', $function$BEGIN RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10));END$function$ +~~END~~ + + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc1' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE PROCEDURE master_dbo.babel_2877_vu_prepare_proc1(IN "@a" integer, IN "@b" "varchar" DEFAULT 'abc'::"varchar", IN "@c" money DEFAULT 5, IN "@d" double precision) LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1"], "original_probin": ""}', $procedure$BEGIN SELECT @a, @b, @c, @d;END$procedure$ +~~END~~ + + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc2' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE PROCEDURE master_dbo.babel_2877_vu_prepare_proc2(IN "@a" integer DEFAULT 10, IN "@b" "varchar" DEFAULT 'abc'::"varchar", IN "@c" money DEFAULT 5, IN "@d" double precision DEFAULT 1.2) LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1"], "original_probin": ""}', $procedure$BEGIN SELECT @a, @b, @c, @d;END$procedure$ +~~END~~ + + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc3' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE PROCEDURE master_dbo.babel_2877_vu_prepare_proc3(IN "@a" integer, IN "@b" "varchar", IN "@c" money, IN "@d" double precision) LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1"], "original_probin": ""}', $procedure$BEGIN SELECT @a, @b, @c, @d;END$procedure$ +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_func1(10); -- should fail, required argument @c not supplied +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: function babel_2877_vu_prepare_func1 expects parameter "@c", which was not supplied.)~~ + + +SELECT * FROM babel_2877_vu_prepare_func1(10, 'abc', $5); +GO +~~START~~ +varchar +10abc5.00001.2 +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_func2(); +GO +~~START~~ +varchar +10abc5.00001.2 +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_func3(); -- should fail, all parameters are required +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: function babel_2877_vu_prepare_func3 expects parameter "@a", which was not supplied.)~~ + + +SELECT * FROM babel_2877_vu_prepare_func3(10, 'abc', $5, 1.2); +GO +~~START~~ +varchar +10abc5.00001.2 +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_view1; +GO +~~START~~ +varchar +20def5.00001.2 +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_view2; +GO +~~START~~ +varchar +10abc5.00001.2 +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_view3; +GO +~~START~~ +varchar +20def10.00001.8 +~~END~~ + + +EXEC babel_2877_vu_prepare_proc1; -- should fail, required arguments @a and @d not supplied +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: procedure babel_2877_vu_prepare_proc1 expects parameter "@a", which was not supplied.)~~ + + +EXEC babel_2877_vu_prepare_proc1 10; -- should fail, required argument @d not supplied +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: procedure babel_2877_vu_prepare_proc1 expects parameter "@d", which was not supplied.)~~ + + +EXEC babel_2877_vu_prepare_proc1 @d=40; -- should fail, required argument @a not supplied +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: procedure babel_2877_vu_prepare_proc1 expects parameter "@a", which was not supplied.)~~ + + +EXEC babel_2877_vu_prepare_proc1 @a = 10, @d = 1.8; +GO +~~START~~ +int#!#varchar#!#money#!#float +10#!#abc#!#5.0000#!#1.8 +~~END~~ + + +EXEC babel_2877_vu_prepare_proc1 @a = 10, @b = 20, @c = 30, @d = 40; +GO +~~START~~ +int#!#varchar#!#money#!#float +10#!#20#!#30.0000#!#40.0 +~~END~~ + + +EXEC babel_2877_vu_prepare_proc2; +GO +~~START~~ +int#!#varchar#!#money#!#float +10#!#abc#!#5.0000#!#1.2 +~~END~~ + + +EXEC babel_2877_vu_prepare_proc2 @d = 1.5; +GO +~~START~~ +int#!#varchar#!#money#!#float +10#!#abc#!#5.0000#!#1.5 +~~END~~ + + +EXEC babel_2877_vu_prepare_proc3; -- should fail, all parameters are required +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: procedure babel_2877_vu_prepare_proc3 expects parameter "@a", which was not supplied.)~~ + + +EXEC babel_2877_vu_prepare_proc3 10, 'def', $10, 1.8; -- should fail, all parameters are required +GO +~~START~~ +int#!#varchar#!#money#!#float +10#!#def#!#10.0000#!#1.8 +~~END~~ + + +-- babelfish_function_ext table should have entry for all the above functions and procedures +SELECT nspname, + funcname, + funcsignature, + default_positions +FROM sys.babelfish_function_ext + WHERE funcname LIKE 'babel_2877_vu_prepare%' + AND funcname NOT LIKE '%ansi%' ORDER BY funcname; +GO +~~START~~ +varchar#!#varchar#!#text#!#text +master_dbo#!#babel_2877_vu_prepare_func1#!#babel_2877_vu_prepare_func1(integer, "sys"."varchar", "sys"."money", double precision)#!#(1 3) +master_dbo#!#babel_2877_vu_prepare_func2#!#babel_2877_vu_prepare_func2(integer, "sys"."varchar", "sys"."money", double precision)#!#(0 1 2 3) +master_dbo#!#babel_2877_vu_prepare_func3#!#babel_2877_vu_prepare_func3(integer, "sys"."varchar", "sys"."money", double precision)#!# +master_dbo#!#babel_2877_vu_prepare_proc1#!#babel_2877_vu_prepare_proc1(integer, "sys"."varchar", "sys"."money", double precision)#!#(1 2) +master_dbo#!#babel_2877_vu_prepare_proc2#!#babel_2877_vu_prepare_proc2(integer, "sys"."varchar", "sys"."money", double precision)#!#(0 1 2 3) +master_dbo#!#babel_2877_vu_prepare_proc3#!#babel_2877_vu_prepare_proc3(integer, "sys"."varchar", "sys"."money", double precision)#!# +~~END~~ + + +SELECT orig_name, + CASE flag_validity & 1 + WHEN 0 + THEN NULL + ELSE + CASE flag_values & 1 + WHEN 0 + THEN 0 + ELSE 1 + END + END AS ansi_null, + CASE flag_validity & 2 + WHEN 0 + THEN NULL + ELSE + CASE flag_values & 2 + WHEN 0 + THEN 0 + ELSE 1 + END + END AS quoted_identifier +FROM sys.babelfish_function_ext WHERE funcname LIKE 'babel-2877-vu-prepare%' ORDER BY funcname; +GO +~~START~~ +nvarchar#!#int#!#int +BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDOFF#!#0#!#0 +BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDON#!#0#!#1 +BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDOFF#!#1#!#0 +BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDON#!#1#!#1 +~~END~~ + diff --git a/test/JDBC/expected/latest__verification_cleanup__15_2__BABEL-2877-vu-cleanup.out b/test/JDBC/expected/latest__verification_cleanup__15_2__BABEL-2877-vu-cleanup.out new file mode 100644 index 0000000000..2b3ac2c392 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__15_2__BABEL-2877-vu-cleanup.out @@ -0,0 +1,46 @@ +DROP VIEW babel_2877_vu_prepare_view1; +GO + +DROP VIEW babel_2877_vu_prepare_view2; +GO + +DROP VIEW babel_2877_vu_prepare_view3; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func1; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func2; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func3; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc1; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc2; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc3; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDON]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDON]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDOFF]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDOFF]; +GO + +-- babelfish_function_ext entry should have been removed after dropping all these functions/procedure +SELECT * FROM sys.babelfish_function_ext WHERE funcname LIKE 'babel_2877_vu_prepare%'; +GO +~~START~~ +varchar#!#varchar#!#nvarchar#!#text#!#text#!#bigint#!#bigint#!#datetime#!#datetime#!#ntext +~~END~~ + diff --git a/test/JDBC/expected/latest__verification_cleanup__15_2__BABEL-2877-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__15_2__BABEL-2877-vu-verify.out new file mode 100644 index 0000000000..5970f8ab19 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__15_2__BABEL-2877-vu-verify.out @@ -0,0 +1,229 @@ +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func1' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE FUNCTION master_dbo.babel_2877_vu_prepare_func1("@a" integer, "@b" "varchar" DEFAULT 'abc'::"varchar", "@c" money, "@d" double precision DEFAULT 1.2) RETURNS "varchar" LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1", "100"], "original_probin": ""}', $function$BEGIN RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10));END$function$ +~~END~~ + + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func2' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE FUNCTION master_dbo.babel_2877_vu_prepare_func2("@a" integer DEFAULT 10, "@b" "varchar" DEFAULT 'abc'::"varchar", "@c" money DEFAULT 5, "@d" double precision DEFAULT 1.2) RETURNS "varchar" LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1", "100"], "original_probin": ""}', $function$BEGIN RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10));END$function$ +~~END~~ + + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func3' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE FUNCTION master_dbo.babel_2877_vu_prepare_func3("@a" integer, "@b" "varchar", "@c" money, "@d" double precision) RETURNS "varchar" LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1", "100"], "original_probin": ""}', $function$BEGIN RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10));END$function$ +~~END~~ + + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc1' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE PROCEDURE master_dbo.babel_2877_vu_prepare_proc1(IN "@a" integer, IN "@b" "varchar" DEFAULT 'abc'::"varchar", IN "@c" money DEFAULT 5, IN "@d" double precision) LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1"], "original_probin": ""}', $procedure$BEGIN SELECT @a, @b, @c, @d;END$procedure$ +~~END~~ + + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc2' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE PROCEDURE master_dbo.babel_2877_vu_prepare_proc2(IN "@a" integer DEFAULT 10, IN "@b" "varchar" DEFAULT 'abc'::"varchar", IN "@c" money DEFAULT 5, IN "@d" double precision DEFAULT 1.2) LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1"], "original_probin": ""}', $procedure$BEGIN SELECT @a, @b, @c, @d;END$procedure$ +~~END~~ + + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc3' as regproc)); +GO +~~START~~ +text +CREATE OR REPLACE PROCEDURE master_dbo.babel_2877_vu_prepare_proc3(IN "@a" integer, IN "@b" "varchar", IN "@c" money, IN "@d" double precision) LANGUAGE pltsqlAS '{"version_num": "1", "typmod_array": ["-1", "10", "-1", "-1"], "original_probin": ""}', $procedure$BEGIN SELECT @a, @b, @c, @d;END$procedure$ +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_func1(10); -- should fail, required argument @c not supplied +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: function babel_2877_vu_prepare_func1 expects parameter "@c", which was not supplied.)~~ + + +SELECT * FROM babel_2877_vu_prepare_func1(10, 'abc', $5); +GO +~~START~~ +varchar +10abc5.00001.2 +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_func2(); +GO +~~START~~ +varchar +10abc5.00001.2 +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_func3(); -- should fail, all parameters are required +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: function babel_2877_vu_prepare_func3 expects parameter "@a", which was not supplied.)~~ + + +SELECT * FROM babel_2877_vu_prepare_func3(10, 'abc', $5, 1.2); +GO +~~START~~ +varchar +10abc5.00001.2 +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_view1; +GO +~~START~~ +varchar +20def5.00001.2 +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_view2; +GO +~~START~~ +varchar +10abc5.00001.2 +~~END~~ + + +SELECT * FROM babel_2877_vu_prepare_view3; +GO +~~START~~ +varchar +20def10.00001.8 +~~END~~ + + +EXEC babel_2877_vu_prepare_proc1; -- should fail, required arguments @a and @d not supplied +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: procedure babel_2877_vu_prepare_proc1 expects parameter "@a", which was not supplied.)~~ + + +EXEC babel_2877_vu_prepare_proc1 10; -- should fail, required argument @d not supplied +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: procedure babel_2877_vu_prepare_proc1 expects parameter "@d", which was not supplied.)~~ + + +EXEC babel_2877_vu_prepare_proc1 @d=40; -- should fail, required argument @a not supplied +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: procedure babel_2877_vu_prepare_proc1 expects parameter "@a", which was not supplied.)~~ + + +EXEC babel_2877_vu_prepare_proc1 @a = 10, @d = 1.8; +GO +~~START~~ +int#!#varchar#!#money#!#float +10#!#abc#!#5.0000#!#1.8 +~~END~~ + + +EXEC babel_2877_vu_prepare_proc1 @a = 10, @b = 20, @c = 30, @d = 40; +GO +~~START~~ +int#!#varchar#!#money#!#float +10#!#20#!#30.0000#!#40.0 +~~END~~ + + +EXEC babel_2877_vu_prepare_proc2; +GO +~~START~~ +int#!#varchar#!#money#!#float +10#!#abc#!#5.0000#!#1.2 +~~END~~ + + +EXEC babel_2877_vu_prepare_proc2 @d = 1.5; +GO +~~START~~ +int#!#varchar#!#money#!#float +10#!#abc#!#5.0000#!#1.5 +~~END~~ + + +EXEC babel_2877_vu_prepare_proc3; -- should fail, all parameters are required +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: procedure babel_2877_vu_prepare_proc3 expects parameter "@a", which was not supplied.)~~ + + +EXEC babel_2877_vu_prepare_proc3 10, 'def', $10, 1.8; -- should fail, all parameters are required +GO +~~START~~ +int#!#varchar#!#money#!#float +10#!#def#!#10.0000#!#1.8 +~~END~~ + + +-- babelfish_function_ext table should have entry for all the above functions and procedures +SELECT nspname, + funcname, + funcsignature, + default_positions +FROM sys.babelfish_function_ext + WHERE funcname LIKE 'babel_2877_vu_prepare%' + AND funcname NOT LIKE '%ansi%' ORDER BY funcname; +GO +~~START~~ +varchar#!#varchar#!#text#!#text +master_dbo#!#babel_2877_vu_prepare_func1#!#babel_2877_vu_prepare_func1(integer, "sys"."varchar", "sys"."money", double precision)#!#(1 3) +master_dbo#!#babel_2877_vu_prepare_func2#!#babel_2877_vu_prepare_func2(integer, "sys"."varchar", "sys"."money", double precision)#!#(0 1 2 3) +master_dbo#!#babel_2877_vu_prepare_func3#!#babel_2877_vu_prepare_func3(integer, "sys"."varchar", "sys"."money", double precision)#!# +master_dbo#!#babel_2877_vu_prepare_proc1#!#babel_2877_vu_prepare_proc1(integer, "sys"."varchar", "sys"."money", double precision)#!#(1 2) +master_dbo#!#babel_2877_vu_prepare_proc2#!#babel_2877_vu_prepare_proc2(integer, "sys"."varchar", "sys"."money", double precision)#!#(0 1 2 3) +master_dbo#!#babel_2877_vu_prepare_proc3#!#babel_2877_vu_prepare_proc3(integer, "sys"."varchar", "sys"."money", double precision)#!# +~~END~~ + + +SELECT orig_name, + CASE flag_validity & 1 + WHEN 0 + THEN NULL + ELSE + CASE flag_values & 1 + WHEN 0 + THEN 0 + ELSE 1 + END + END AS ansi_null, + CASE flag_validity & 2 + WHEN 0 + THEN NULL + ELSE + CASE flag_values & 2 + WHEN 0 + THEN 0 + ELSE 1 + END + END AS quoted_identifier +FROM sys.babelfish_function_ext WHERE funcname LIKE 'babel-2877-vu-prepare%' ORDER BY funcname; +GO +~~START~~ +nvarchar#!#int#!#int +BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDOFF#!#0#!#0 +BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDON#!#0#!#1 +BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDOFF#!#1#!#0 +BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDON#!#1#!#1 +~~END~~ + diff --git a/test/JDBC/expected/latest__verification_cleanup__15_2__Test-sp_babelfish_volatility-vu-cleanup.out b/test/JDBC/expected/latest__verification_cleanup__15_2__Test-sp_babelfish_volatility-vu-cleanup.out new file mode 100644 index 0000000000..80a368ffa7 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__15_2__Test-sp_babelfish_volatility-vu-cleanup.out @@ -0,0 +1,65 @@ +drop function test_sp_babelfish_volatility_f1 +go + +drop function test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1 +go + +drop schema test_sp_babelfish_volatility_schema1 +go + +drop function [test_sp_babelfish_volatility_schema1 with .dot and spaces].test_sp_babelfish_volatility_f1 +go + +drop schema [test_sp_babelfish_volatility_schema1 with .dot and spaces] +go + +use test_sp_babelfish_volatility_db1 +go + +drop function test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1 +go + +drop function test_sp_babelfish_volatility_f2 +go + +drop function test_sp_babelfish_volatility_duplicate() +go + +drop function test_sp_babelfish_volatility_duplicate(@b int) +go + +drop schema test_sp_babelfish_volatility_schema2 +go + +drop function test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa; +go + +drop function test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa; +go + +drop schema test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa; +go + +drop user test_sp_babelfish_volatility_user +go + +drop login test_sp_babelfish_volatility_login_2 +go + +use master +go + +drop database test_sp_babelfish_volatility_db1 +go + +drop login test_sp_babelfish_volatility_login +go + +drop table test_bbf_vol_t1 +go + +drop function test_bbf_vol_f1 +go + +drop function [test_bbf_vol_f1;drop table test_bbf_vol_t1;] +go diff --git a/test/JDBC/expected/latest__verification_cleanup__15_2__Test-sp_babelfish_volatility-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__15_2__Test-sp_babelfish_volatility-vu-verify.out new file mode 100644 index 0000000000..566b7301e4 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__15_2__Test-sp_babelfish_volatility-vu-verify.out @@ -0,0 +1,737 @@ +-- tsql +/* test without schema name */ +use master +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'stable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#stable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'volatile' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'random' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: "random" is not a valid volatility)~~ + +exec sys.sp_babelfish_volatility '.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'stable' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#stable +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'volatile' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'random' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: "random" is not a valid volatility)~~ + +sp_babelfish_volatility '.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + + +/* test with schema name */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility '"test_sp_babelfish_volatility_schema1".test_sp_babelfish_volatility_f1', 'stable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#stable +~~END~~ + +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1].test_sp_babelfish_volatility_f1', 'volatile' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'random' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: "random" is not a valid volatility)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'immutable' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +sp_babelfish_volatility '"test_sp_babelfish_volatility_schema1".test_sp_babelfish_volatility_f1', 'stable' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#stable +~~END~~ + +sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1].test_sp_babelfish_volatility_f1', 'volatile' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'random' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: "random" is not a valid volatility)~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + + +/* testing for trailing spaces */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1 ', 'stable ' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#stable +~~END~~ + + +/* testing for leading space should give error */ +exec sys.sp_babelfish_volatility ' test_sp_babelfish_volatility_f1', 'immutable' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', ' immutable' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: input value is too long for volatility)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#stable +~~END~~ + + +/* testing for some invalid cases */ +exec sys.sp_babelfish_volatility 'master.test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function "master.test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1" is not a valid two part name)~~ + +exec sys.sp_babelfish_volatility 'random_function' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +exec sys.sp_babelfish_volatility '','immutable' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function name is not valid)~~ + +exec sys.sp_babelfish_volatility '' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function name is not valid)~~ + +exec sys.sp_babelfish_volatility NULL, 'stable' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function name cannot be NULL)~~ + +exec sys.sp_babelfish_volatility '. test_sp_babelfish_volatility_f1' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function name is not valid)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_name_for_a_very_long_function_name_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_name_for_a_very_long_function_name_more_longer_longer_than_4000_characters_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: input value is too long for function name)~~ + + +/* testing for injection */ +exec sys.sp_babelfish_volatility 'ran;dom' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable; some random text' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: input value is too long for volatility)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#stable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'rand;om' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: "rand;om" is not a valid volatility)~~ + +/* testing injection in function name */ +exec sys.sp_babelfish_volatility 'test_bbf_vol_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_bbf_vol_f1#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility '[test_bbf_vol_f1;drop table test_bbf_vol_t1;]' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_bbf_vol_f1;drop table test_bbf_vol_t1;#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility '[test_bbf_vol_f1;drop table test_bbf_vol_t1;]', 'immutable' +go +exec sys.sp_babelfish_volatility '[test_bbf_vol_f1;drop table test_bbf_vol_t1;]' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_bbf_vol_f1;drop table test_bbf_vol_t1;#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_bbf_vol_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_bbf_vol_f1#!#volatile +~~END~~ + +select * from test_bbf_vol_t1 +go +~~START~~ +int +~~END~~ + + +/* testing for case insensitive */ +exec sys.sp_babelfish_volatility 'TesT_SP_babelfish_Volatility_f1', 'VolatILe' +go +exec sys.sp_babelfish_volatility 'TesT_Sp_babelfish_Volatility_F1' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + + +/* testing with dot and spaces in schema name */ +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1 with .dot and spaces].test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1 with .dot and spaces]."test_sp_babelfish_volatility_f1"' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema1 with .dot and spaces#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + + +/* test in a database */ +use test_sp_babelfish_volatility_db1 +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +/* test with duplicate function name */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_duplicate' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: multiple functions with same function name exits)~~ + +/* test with long names */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa', 'immutable' +go +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa]' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa', 'immutable' +go +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa].[test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa]' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#immutable +~~END~~ + +/* test with trucated names */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7', 'volatile' +go +exec sys.sp_babelfish_volatility '"test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7"' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_scc62ee1eb13f7c4857c426f2affcc9a16.test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_scc62ee1eb13f7c4857c426f2affcc9a16.test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7', 'volatile' +go +exec sys.sp_babelfish_volatility '"test_sp_babelfish_volatility_scc62ee1eb13f7c4857c426f2affcc9a16".[test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7]' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_duplicate#!#volatile +dbo#!#test_sp_babelfish_volatility_duplicate#!#volatile +dbo#!#test_sp_babelfish_volatility_f2#!#volatile +dbo#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#volatile +test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa#!#test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7#!#volatile +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f2#!#volatile +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f2#!#immutable +~~END~~ + + +-- tsql user=test_sp_babelfish_volatility_login password=12345678 +/* function on which user has privilege is only visible */ +use test_sp_babelfish_volatility_db1 +go +select current_user +go +~~START~~ +varchar +test_sp_babelfish_volatility_user +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +exec sys.sp_babelfish_volatility 'dbo.test_sp_babelfish_volatility_f2' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: current user does not have priviledges on the function)~~ + +exec sys.sp_babelfish_volatility +go +~~START~~ +nvarchar#!#varchar#!#text +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +sp_babelfish_volatility 'dbo.test_sp_babelfish_volatility_f2' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: current user does not have priviledges on the function)~~ + +sp_babelfish_volatility +go +~~START~~ +nvarchar#!#varchar#!#text +~~END~~ + + +-- tsql +/* grant access to current user */ +use test_sp_babelfish_volatility_db1 +go +grant execute on test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1 to test_sp_babelfish_volatility_user +go +grant execute on test_sp_babelfish_volatility_f2 to test_sp_babelfish_volatility_user +go + +-- tsql user=test_sp_babelfish_volatility_login password=12345678 +use test_sp_babelfish_volatility_db1 +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f2#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f2#!#immutable +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f2#!#immutable +~~END~~ + +sp_babelfish_volatility +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f2#!#immutable +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + + +-- tsql +/* test for default schema */ +use test_sp_babelfish_volatility_db1 +go +ALTER USER test_sp_babelfish_volatility_user WITH DEFAULT_SCHEMA=test_sp_babelfish_volatility_schema2 +GO + +-- tsql user=test_sp_babelfish_volatility_login password=12345678 +use test_sp_babelfish_volatility_db1 +go +select current_user +go +~~START~~ +varchar +test_sp_babelfish_volatility_user +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1 ' +go +~~START~~ +nvarchar#!#varchar#!#text +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function does not exist)~~ + +exec sys.sp_babelfish_volatility 'dbo.test_sp_babelfish_volatility_f2' +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f2#!#immutable +~~END~~ + +exec sys.sp_babelfish_volatility +go +~~START~~ +nvarchar#!#varchar#!#text +dbo#!#test_sp_babelfish_volatility_f2#!#immutable +test_sp_babelfish_volatility_schema2#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + + +-- tsql +/* revoke the priviledges to the user */ +use test_sp_babelfish_volatility_db1 +go +revoke execute on test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1 from test_sp_babelfish_volatility_user +go +revoke execute on test_sp_babelfish_volatility_f2 from test_sp_babelfish_volatility_user +go + +-- tsql +/* test default schema in guest user */ +use test_sp_babelfish_volatility_db1 +go +grant connect to guest +go + +-- tsql user=test_sp_babelfish_volatility_login_2 password=12345678 +use test_sp_babelfish_volatility_db1 +go +SELECT current_user +go +~~START~~ +varchar +guest +~~END~~ + +create function test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +guest#!#test_sp_babelfish_volatility_f1#!#stable +~~END~~ + +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable'; +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +~~START~~ +nvarchar#!#varchar#!#text +guest#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +sp_babelfish_volatility 'dbo.test_sp_babelfish_volatility_f2' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: current user does not have priviledges on the function)~~ + +sp_babelfish_volatility +go +~~START~~ +nvarchar#!#varchar#!#text +guest#!#test_sp_babelfish_volatility_f1#!#immutable +~~END~~ + +drop function test_sp_babelfish_volatility_f1 +go + +-- tsql +use test_sp_babelfish_volatility_db1 +go +revoke connect from guest +go + +-- psql +-- Need to terminate active session before cleaning up the login +SELECT pg_terminate_backend(pid) FROM pg_stat_get_activity(NULL) +WHERE sys.suser_name(usesysid) = 'test_sp_babelfish_volatility_user' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +GO +~~START~~ +bool +~~END~~ + +-- Wait to sync with another session +SELECT pg_sleep(1); +GO +~~START~~ +void + +~~END~~ + diff --git a/test/JDBC/input/create_function_default_stable-vu-cleanup.mix b/test/JDBC/input/create_function_default_stable-vu-cleanup.mix new file mode 100644 index 0000000000..6de66b213f --- /dev/null +++ b/test/JDBC/input/create_function_default_stable-vu-cleanup.mix @@ -0,0 +1,130 @@ +-- tsql + +use test_create_function_default_stable_db +go + +drop function test_create_function_default_stable_f1 +go + +drop function test_create_function_default_stable_f2 +go + +drop function test_create_function_default_stable_tvp_f1 +go + +drop function test_create_function_default_stable_tvp_f2 +go + +drop function test_create_function_default_stable_tvp_f3 +go + +drop function test_create_function_default_stable_tvp_f4 +go + +drop function test_create_function_default_stable_tvp_f5 +go + +drop function test_create_function_default_stable_tvf_f1 +go + +drop function test_create_function_default_stable_tvf_f2 +go + +drop function test_create_function_default_stable_tvptvf_f1 +go + +drop function test_create_function_default_stable_tvptvf_f2 +go + +drop function test_create_function_default_stable_nested_f1 +go + +drop function test_create_function_default_stable_nested_f2 +go + +drop function test_create_function_default_stable_nested_f3 +go + +drop function test_create_function_default_stable_nested_f4 +go + +drop function test_create_function_default_stable_nested_f5 +go + +drop function test_create_function_default_stable_nested_f6 +go + +drop function test_create_function_default_stable_nested_f7 +go + +-- psql +drop function test_create_function_default_stable_tsql_f1 +go + +drop function test_create_function_default_stable_tsql_f2 +go + +drop function test_create_function_default_stable_tsql_f3 +go + +drop function test_create_function_default_stable_tsql_f4 +go + +drop function test_create_function_default_stable_tsql_f5 +go + +drop table test_create_function_default_stable_tsql_t1 +go + +drop type test_create_function_default_stable_tsql_type +go + +-- tsql +drop table test_create_function_default_stable_t1 +go + +drop type test_create_function_default_stable_type +go + +use master +go + +drop database test_create_function_default_stable_db +go + +-- psql +drop function test_create_function_default_stable_psql_f1; +go + +drop function test_create_function_default_stable_psql_f2; +go + +drop function test_create_function_default_stable_psql_f3; +go + +drop function test_create_function_default_stable_psql_f4; +go + +drop function test_create_function_default_stable_psql_f5; +go + +drop function test_create_function_default_stable_psql_f6; +go + +drop function test_create_function_default_stable_psql_f7; +go + +drop function test_create_function_default_stable_psql_f8; +go + +drop function test_create_function_default_stable_psql_f9; +go + +drop function test_create_function_default_stable_psql_f10; +go + +drop function test_create_function_default_stable_psql_f11; +go + +drop function test_create_function_default_stable_psql_f12; +go \ No newline at end of file diff --git a/test/JDBC/input/create_function_default_stable-vu-prepare.mix b/test/JDBC/input/create_function_default_stable-vu-prepare.mix new file mode 100644 index 0000000000..4111986e74 --- /dev/null +++ b/test/JDBC/input/create_function_default_stable-vu-prepare.mix @@ -0,0 +1,284 @@ +-- tsql +create database test_create_function_default_stable_db +go + +use test_create_function_default_stable_db +go + +create table test_create_function_default_stable_t1(a int) +go + +create type test_create_function_default_stable_type AS TABLE(a int) +go + +-- create functions not having tvp or tvf +create function test_create_function_default_stable_f1() returns int as begin return 0; end +go + +create function test_create_function_default_stable_f2(@a int, @b char, @c date, @d money, @e float, @f text, @g xml) +returns int as begin return 0; end +go + +-- create functions with tvp +-- 1. tvp is declared inside the function +create function test_create_function_default_stable_tvp_f1() +returns int as begin declare @tvp table(a int); +insert into @tvp values(1); return 0; end +go + +create function test_create_function_default_stable_tvp_f2() +returns int as begin declare @tvp test_create_function_default_stable_type; +insert into @tvp values(1); return 0; end +go + +create function test_create_function_default_stable_tvp_f3() +returns int as begin declare @tvp test_create_function_default_stable_type; +return 0; end +go + +-- 2. tvp passed as argument +create function test_create_function_default_stable_tvp_f4(@tvp test_create_function_default_stable_type readonly) +returns int as begin return 0; end +go + +create function test_create_function_default_stable_tvp_f5(@tvp test_create_function_default_stable_type readonly) +returns int as begin insert into @tvp values(1) return 0;end +go + +-- create functions with tvf +create function test_create_function_default_stable_tvf_f1() returns table as return (SELECT * from test_create_function_default_stable_t1) +go + +create function test_create_function_default_stable_tvf_f2(@a int) +returns @tv table(b int) +AS BEGIN +update @tv set b = 1 where b = 2 +return end +go + +-- create function having both tvp and tvf +create function test_create_function_default_stable_tvptvf_f1(@tvp test_create_function_default_stable_type readonly) +returns table as return (SELECT * from test_create_function_default_stable_t1) +go + +create function test_create_function_default_stable_tvptvf_f2(@a int, @tvp1 test_create_function_default_stable_type readonly) +returns @tvp2 table(b int) +AS BEGIN +update @tvp2 set b = 1 where b = 2 +return end +go + +-- nested functions +create function test_create_function_default_stable_nested_f1() +returns int as begin +exec test_create_function_default_stable_tvp_f1; +return 0; end +go + +create function test_create_function_default_stable_nested_f2() +returns int as begin +declare @tvp test_create_function_default_stable_type +exec test_create_function_default_stable_tvp_f4 @tvp; +return 0; end +go + +create function test_create_function_default_stable_nested_f3() +returns table as +return (SELECT * from test_create_function_default_stable_tvf_f2(1)) +go + +create function test_create_function_default_stable_nested_f4() +returns table as +return (SELECT * from test_create_function_default_stable_tvp_f1()) +go + +create function test_create_function_default_stable_nested_f5() +returns table as +return (SELECT * from test_create_function_default_stable_f1()) +go + +create function test_create_function_default_stable_nested_f6(@a int) +returns @tv table(b int) +AS BEGIN +Declare @b int; +exec test_create_function_default_stable_f1; +update @tv set b = 1 where b = 2 +return end +go + +create function test_create_function_default_stable_nested_f7() +returns int as begin +exec test_create_function_default_stable_f1; +return 0; end +go + +-- create procedure and check +create procedure test_create_function_default_stable_p1 +as +declare @a int; +go + +create procedure test_create_function_default_stable_p2 +as +select * from test_create_function_default_stable_t1; +go + +create procedure test_create_function_default_stable_p3 +as +declare @tvp test_create_function_default_stable_type; +select * from @tvp; +go + +-- psql +-- create function in tsql dialect +set babelfishpg_tsql.sql_dialect = "tsql"; +go + +create table test_create_function_default_stable_tsql_t1(a int) +go + +create type test_create_function_default_stable_tsql_type AS TABLE(a int) +go + +create function test_create_function_default_stable_tsql_f1() +returns int +as begin +return 0 +end +go + +create function test_create_function_default_stable_tsql_f2() +returns int +as begin +declare @tvp table(a int) +insert into @tvp values(1) +return 0 +end +go + +create function test_create_function_default_stable_tsql_f3(@tvp test_create_function_default_stable_tsql_type readonly) +returns int +as begin +return 0 +end +go + +create function test_create_function_default_stable_tsql_f4() returns table as return (SELECT * from test_create_function_default_stable_tsql_t1); +go + +create function test_create_function_default_stable_tsql_f5(@a int) +returns @tv table(b int) +AS BEGIN +update @tv set b = 1 where b = 2 +return end +go + +reset babelfishpg_tsql.sql_dialect; +go + +-- psql +-- create function in psql endpoint + +-- with language plpgsql +create function test_create_function_default_stable_psql_f1() +returns int +language plpgsql +as +$$ +declare a int; +begin + a := 1; +return a; +end; +$$; +go + +-- with language sql +create function test_create_function_default_stable_psql_f2() RETURNS char(20) language SQL return 'abc'; +go + +-- with language pltsql +CREATE OR REPLACE FUNCTION test_create_function_default_stable_psql_f3() RETURNS int AS $$ +BEGIN + DECLARE @a int = 1; + RETURN @a +END; +$$ LANGUAGE pltsql; +go + +CREATE OR REPLACE FUNCTION test_create_function_default_stable_psql_f4() RETURNS int AS $$ +BEGIN + DECLARE @a int = 1; + RETURN @a +END; +$$ LANGUAGE pltsql VOLATILE; +go + +CREATE OR REPLACE FUNCTION test_create_function_default_stable_psql_f5() RETURNS int AS $$ +BEGIN + DECLARE @a int = 1; + RETURN @a +END; +$$ LANGUAGE pltsql STABLE; +go + +CREATE OR REPLACE FUNCTION test_create_function_default_stable_psql_f6() RETURNS int AS $$ +BEGIN + DECLARE @a int = 1; + RETURN @a +END; +$$ LANGUAGE pltsql IMMUTABLE; +go + +-- with table variable +CREATE OR REPLACE FUNCTION test_create_function_default_stable_psql_f7() RETURNS int AS $$ +BEGIN + DECLARE @a int = 1; + declare @tvp table(a int); + RETURN @a +END; +$$ LANGUAGE pltsql; +go + +CREATE OR REPLACE FUNCTION test_create_function_default_stable_psql_f8() RETURNS int AS $$ +BEGIN + DECLARE @a int = 1; + declare @tvp table(a int); + RETURN @a +END; +$$ LANGUAGE pltsql VOLATILE; +go + +CREATE OR REPLACE FUNCTION test_create_function_default_stable_psql_f9() RETURNS int AS $$ +BEGIN + DECLARE @a int = 1; + declare @tvp table(a int); + RETURN @a +END; +$$ LANGUAGE pltsql STABLE; +go + +CREATE OR REPLACE FUNCTION test_create_function_default_stable_psql_f10() RETURNS int AS $$ +BEGIN + DECLARE @a int = 1; + declare @tvp table(a int); + RETURN @a +END; +$$ LANGUAGE pltsql IMMUTABLE; +go + +-- with record datatypes +CREATE OR REPLACE FUNCTION test_create_function_default_stable_psql_f11() RETURNS int AS $$ +declare rec record; +begin +return 1; +end; +$$ LANGUAGE plpgsql; +go + +CREATE OR REPLACE FUNCTION test_create_function_default_stable_psql_f12(rec record) RETURNS int AS $$ +begin +return 1; +end; +$$ LANGUAGE pltsql; +go \ No newline at end of file diff --git a/test/JDBC/input/create_function_default_stable-vu-verify.mix b/test/JDBC/input/create_function_default_stable-vu-verify.mix new file mode 100644 index 0000000000..2e8fab77c8 --- /dev/null +++ b/test/JDBC/input/create_function_default_stable-vu-verify.mix @@ -0,0 +1,168 @@ +-- tsql +use test_create_function_default_stable_db +go + +-- not having tvp or tvf +sp_babelfish_volatility 'test_create_function_default_stable_f1' +go +exec test_create_function_default_stable_f1 +go + +sp_babelfish_volatility 'test_create_function_default_stable_f2' +go +exec test_create_function_default_stable_f2 1, 'a', '10/10/10', 1, 1.1, 'abcd', 'aaa' +go + +-- functions with tvp +sp_babelfish_volatility 'test_create_function_default_stable_tvp_f1' +go +exec test_create_function_default_stable_tvp_f1 +go + +sp_babelfish_volatility 'test_create_function_default_stable_tvp_f2' +go +exec test_create_function_default_stable_tvp_f2 +go + +sp_babelfish_volatility 'test_create_function_default_stable_tvp_f3' +go +exec test_create_function_default_stable_tvp_f3 +go + +sp_babelfish_volatility 'test_create_function_default_stable_tvp_f4' +go +declare @tvp test_create_function_default_stable_type +exec test_create_function_default_stable_tvp_f4 @tvp +go + +sp_babelfish_volatility 'test_create_function_default_stable_tvp_f5' +go +declare @tvp test_create_function_default_stable_type +exec test_create_function_default_stable_tvp_f5 @tvp +go + +-- functions with tvf +sp_babelfish_volatility 'test_create_function_default_stable_tvf_f1' +go +exec test_create_function_default_stable_tvf_f1 +go + +sp_babelfish_volatility 'test_create_function_default_stable_tvf_f2' +go +select * from test_create_function_default_stable_tvf_f2(1) +go + +-- function with both tvp and tvf +sp_babelfish_volatility 'test_create_function_default_stable_tvptvf_f1' +go +declare @tvp test_create_function_default_stable_type +exec test_create_function_default_stable_tvptvf_f1 @tvp +go + +sp_babelfish_volatility 'test_create_function_default_stable_tvptvf_f2' +go +declare @tvp test_create_function_default_stable_type +select * from test_create_function_default_stable_tvptvf_f2(1, @tvp) +go + +-- nested functions +sp_babelfish_volatility 'test_create_function_default_stable_nested_f1' +go +exec test_create_function_default_stable_nested_f1 +go + +sp_babelfish_volatility 'test_create_function_default_stable_nested_f2' +go +exec test_create_function_default_stable_nested_f2 +go + +sp_babelfish_volatility 'test_create_function_default_stable_nested_f3' +go +select * from test_create_function_default_stable_nested_f3() +go + +sp_babelfish_volatility 'test_create_function_default_stable_nested_f4' +go +select * from test_create_function_default_stable_nested_f4() +go + +sp_babelfish_volatility 'test_create_function_default_stable_nested_f5' +go +select * from test_create_function_default_stable_nested_f5() +go + +sp_babelfish_volatility 'test_create_function_default_stable_nested_f6' +go +select * from test_create_function_default_stable_nested_f6(1) +go + +sp_babelfish_volatility 'test_create_function_default_stable_nested_f7' +go +select test_create_function_default_stable_nested_f7() +go + +-- check with procedure +select provolatile from pg_proc where proname = 'test_create_function_default_stable_p1' +go + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_p2' +go + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_p3' +go + +-- psql +-- check for tsql dialect +select provolatile from pg_proc where proname = 'test_create_function_default_stable_tsql_f1' +go + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_tsql_f2' +go + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_tsql_f3' +go + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_tsql_f4' +go + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_tsql_f5' +go + + +-- psql +-- check volatility for psql functions +select provolatile from pg_proc where proname = 'test_create_function_default_stable_psql_f1'; +go + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_psql_f2'; +go + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_psql_f3'; +go + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_psql_f4'; +go + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_psql_f5'; +go + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_psql_f6'; +go + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_psql_f7'; +go + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_psql_f8'; +go + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_psql_f9'; +go + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_psql_f10'; +go + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_psql_f11'; +go + +select provolatile from pg_proc where proname = 'test_create_function_default_stable_psql_f12'; +go \ No newline at end of file diff --git a/test/JDBC/input/storedProcedures/Test-sp_babelfish_volatility-vu-verify.mix b/test/JDBC/input/storedProcedures/Test-sp_babelfish_volatility-vu-verify.mix index e4b193f4fd..3f453cf070 100644 --- a/test/JDBC/input/storedProcedures/Test-sp_babelfish_volatility-vu-verify.mix +++ b/test/JDBC/input/storedProcedures/Test-sp_babelfish_volatility-vu-verify.mix @@ -4,11 +4,11 @@ use master go exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' go -exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'stable' +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable' go exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' go -exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable' +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'stable' go exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' go @@ -22,11 +22,11 @@ exec sys.sp_babelfish_volatility '.test_sp_babelfish_volatility_f1' go sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' go -sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'stable' +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable' go sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' go -sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable' +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'stable' go sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' go @@ -42,11 +42,11 @@ go /* test with schema name */ exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' go -exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'stable' +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'immutable' go exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' go -exec sys.sp_babelfish_volatility '"test_sp_babelfish_volatility_schema1".test_sp_babelfish_volatility_f1', 'immutable' +exec sys.sp_babelfish_volatility '"test_sp_babelfish_volatility_schema1".test_sp_babelfish_volatility_f1', 'stable' go exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' go @@ -60,11 +60,11 @@ exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_b go sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' go -sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'stable' +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'immutable' go sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' go -sp_babelfish_volatility '"test_sp_babelfish_volatility_schema1".test_sp_babelfish_volatility_f1', 'immutable' +sp_babelfish_volatility '"test_sp_babelfish_volatility_schema1".test_sp_babelfish_volatility_f1', 'stable' go sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' go @@ -125,7 +125,7 @@ exec sys.sp_babelfish_volatility 'test_bbf_vol_f1' go exec sys.sp_babelfish_volatility '[test_bbf_vol_f1;drop table test_bbf_vol_t1;]' go -exec sys.sp_babelfish_volatility '[test_bbf_vol_f1;drop table test_bbf_vol_t1;]', 'stable' +exec sys.sp_babelfish_volatility '[test_bbf_vol_f1;drop table test_bbf_vol_t1;]', 'immutable' go exec sys.sp_babelfish_volatility '[test_bbf_vol_f1;drop table test_bbf_vol_t1;]' go @@ -141,7 +141,7 @@ exec sys.sp_babelfish_volatility 'TesT_Sp_babelfish_Volatility_F1' go /* testing with dot and spaces in schema name */ -exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1 with .dot and spaces].test_sp_babelfish_volatility_f1', 'stable' +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1 with .dot and spaces].test_sp_babelfish_volatility_f1', 'immutable' go exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1 with .dot and spaces]."test_sp_babelfish_volatility_f1"' go @@ -153,7 +153,7 @@ exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' go exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' go -exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1', 'stable' +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1', 'immutable' go exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' go @@ -163,26 +163,26 @@ go /* test with long names */ exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa' go -exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa', 'stable' +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa', 'immutable' go exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa]' go exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa' go -exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa', 'stable' +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa', 'immutable' go exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa].[test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa]' go /* test with trucated names */ exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7' go -exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7', 'immutable' +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7', 'volatile' go exec sys.sp_babelfish_volatility '"test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7"' go exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_scc62ee1eb13f7c4857c426f2affcc9a16.test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7' go -exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_scc62ee1eb13f7c4857c426f2affcc9a16.test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7', 'immutable' +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_scc62ee1eb13f7c4857c426f2affcc9a16.test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7', 'volatile' go exec sys.sp_babelfish_volatility '"test_sp_babelfish_volatility_scc62ee1eb13f7c4857c426f2affcc9a16".[test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7]' go @@ -190,7 +190,7 @@ exec sys.sp_babelfish_volatility go exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' go -exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2', 'stable' +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2', 'immutable' go exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' go @@ -287,7 +287,7 @@ create function test_sp_babelfish_volatility_f1() returns int begin declare @a i go sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' go -sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'stable'; +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable'; go sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' go diff --git a/test/JDBC/upgrade/13_6/schedule b/test/JDBC/upgrade/13_6/schedule index 7ece90d9e2..2e74e8f8b7 100644 --- a/test/JDBC/upgrade/13_6/schedule +++ b/test/JDBC/upgrade/13_6/schedule @@ -305,7 +305,6 @@ BABEL_SCHEMATA BABEL-SP_FKEYS BABEL-SP_FKEYS-dep BABEL_OBJECT_NAME -Test-sp_babelfish_volatility BABEL-3657 BABEL-3938 rowcount diff --git a/test/JDBC/upgrade/13_7/schedule b/test/JDBC/upgrade/13_7/schedule index 19aba12c0f..b42b9a1e08 100644 --- a/test/JDBC/upgrade/13_7/schedule +++ b/test/JDBC/upgrade/13_7/schedule @@ -299,7 +299,6 @@ sys-all_sql_modules_before-14_5 BABEL_OBJECT_ID test_windows_login_before_15_2 BABEL_OBJECT_NAME -Test-sp_babelfish_volatility BABEL_SCHEMATA BABEL-3657 BABEL-3938 diff --git a/test/JDBC/upgrade/13_8/schedule b/test/JDBC/upgrade/13_8/schedule index 19aba12c0f..b42b9a1e08 100644 --- a/test/JDBC/upgrade/13_8/schedule +++ b/test/JDBC/upgrade/13_8/schedule @@ -299,7 +299,6 @@ sys-all_sql_modules_before-14_5 BABEL_OBJECT_ID test_windows_login_before_15_2 BABEL_OBJECT_NAME -Test-sp_babelfish_volatility BABEL_SCHEMATA BABEL-3657 BABEL-3938 diff --git a/test/JDBC/upgrade/13_9/schedule b/test/JDBC/upgrade/13_9/schedule index d16ab0cf6d..bf2092985f 100644 --- a/test/JDBC/upgrade/13_9/schedule +++ b/test/JDBC/upgrade/13_9/schedule @@ -303,7 +303,6 @@ BABEL_SCHEMATA BABEL-SP_FKEYS BABEL-SP_FKEYS-dep BABEL_OBJECT_NAME -Test-sp_babelfish_volatility BABEL-3657 BABEL-3938 rowcount diff --git a/test/JDBC/upgrade/14_3/schedule b/test/JDBC/upgrade/14_3/schedule index b027049bd9..4c5f507317 100644 --- a/test/JDBC/upgrade/14_3/schedule +++ b/test/JDBC/upgrade/14_3/schedule @@ -317,7 +317,6 @@ BABEL_SCHEMATA BABEL-SP_FKEYS BABEL-SP_FKEYS-dep BABEL_OBJECT_NAME -Test-sp_babelfish_volatility BABEL-3657 BABEL-3938 binary-index diff --git a/test/JDBC/upgrade/14_5/schedule b/test/JDBC/upgrade/14_5/schedule index d835422d98..c0a0f5e4fd 100644 --- a/test/JDBC/upgrade/14_5/schedule +++ b/test/JDBC/upgrade/14_5/schedule @@ -331,7 +331,6 @@ BABEL_SCHEMATA BABEL-SP_FKEYS BABEL-SP_FKEYS-dep BABEL_OBJECT_NAME -Test-sp_babelfish_volatility BABEL-3657 BABEL-3938 binary-index diff --git a/test/JDBC/upgrade/14_6/preparation/BABEL-2877-vu-prepare.sql b/test/JDBC/upgrade/14_6/preparation/BABEL-2877-vu-prepare.sql new file mode 100644 index 0000000000..b740c68c1e --- /dev/null +++ b/test/JDBC/upgrade/14_6/preparation/BABEL-2877-vu-prepare.sql @@ -0,0 +1,100 @@ +-- Function +-- Defaults at different positions +CREATE FUNCTION babel_2877_vu_prepare_func1 (@a int, @b varchar(10) = 'abc', @c money, @d float = 1.2) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- All parameters with defaults +CREATE FUNCTION babel_2877_vu_prepare_func2 (@a int = 10, @b varchar(10) = 'abc', @c money = $5, @d float = 1.2) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- No defaults +CREATE FUNCTION babel_2877_vu_prepare_func3 (@a int, @b varchar(10), @c money, @d float) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- Procedure +-- Defaults at different positions +CREATE PROCEDURE babel_2877_vu_prepare_proc1 (@a int, @b varchar(10) = 'abc', @c money = $5, @d float) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- All parameters with defaults +CREATE PROCEDURE babel_2877_vu_prepare_proc2 (@a int = 10, @b varchar(10) = 'abc', @c money = $5, @d float = 1.2) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- No defaults +CREATE PROCEDURE babel_2877_vu_prepare_proc3 (@a int, @b varchar(10), @c money, @d float) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- Views +CREATE VIEW babel_2877_vu_prepare_view1 AS SELECT babel_2877_vu_prepare_func1(20, 'def', $5); +GO + +CREATE VIEW babel_2877_vu_prepare_view2 AS SELECT babel_2877_vu_prepare_func2(); +GO + +CREATE VIEW babel_2877_vu_prepare_view3 AS SELECT babel_2877_vu_prepare_func1(20, 'def', $10, 1.8); +GO + +-- CASE: Check for session properties like ANSI_NULLS and QUOTED_IDENTIFIER +-- ANSI_NULLS - Last bit from left in flag_values +-- QUOTED_IDENTIFIER - Second last bit from left in flag_values +SET ANSI_NULLS ON; +GO + +SET QUOTED_IDENTIFIER ON; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDON] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET ANSI_NULLS OFF; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDON] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET QUOTED_IDENTIFIER OFF; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDOFF] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET ANSI_NULLS ON; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDOFF] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +-- reset session properties +SET ANSI_NULLS ON; +GO + +SET QUOTED_IDENTIFIER ON; +GO \ No newline at end of file diff --git a/test/JDBC/upgrade/14_6/schedule b/test/JDBC/upgrade/14_6/schedule index 3f24322f90..02bbdc0d5e 100644 --- a/test/JDBC/upgrade/14_6/schedule +++ b/test/JDBC/upgrade/14_6/schedule @@ -231,7 +231,6 @@ sys-all_sql_modules-dep sys-sql_modules-dep sys-system_sql_modules-dep sys-triggers-dep -BABEL-2877 sys-sp_pkeys sys-sp_statistics BABEL-APPLOCK @@ -356,7 +355,6 @@ BABEL_OBJECT_ID test_windows_login_before_15_2 datediff_internal_date-before-14_7-or-15_2 BABEL_OBJECT_NAME -Test-sp_babelfish_volatility BABEL_SCHEMATA BABEL-3657 BABEL-3938 diff --git a/test/JDBC/upgrade/14_7/preparation/BABEL-2877-vu-prepare.sql b/test/JDBC/upgrade/14_7/preparation/BABEL-2877-vu-prepare.sql new file mode 100644 index 0000000000..b740c68c1e --- /dev/null +++ b/test/JDBC/upgrade/14_7/preparation/BABEL-2877-vu-prepare.sql @@ -0,0 +1,100 @@ +-- Function +-- Defaults at different positions +CREATE FUNCTION babel_2877_vu_prepare_func1 (@a int, @b varchar(10) = 'abc', @c money, @d float = 1.2) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- All parameters with defaults +CREATE FUNCTION babel_2877_vu_prepare_func2 (@a int = 10, @b varchar(10) = 'abc', @c money = $5, @d float = 1.2) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- No defaults +CREATE FUNCTION babel_2877_vu_prepare_func3 (@a int, @b varchar(10), @c money, @d float) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- Procedure +-- Defaults at different positions +CREATE PROCEDURE babel_2877_vu_prepare_proc1 (@a int, @b varchar(10) = 'abc', @c money = $5, @d float) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- All parameters with defaults +CREATE PROCEDURE babel_2877_vu_prepare_proc2 (@a int = 10, @b varchar(10) = 'abc', @c money = $5, @d float = 1.2) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- No defaults +CREATE PROCEDURE babel_2877_vu_prepare_proc3 (@a int, @b varchar(10), @c money, @d float) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- Views +CREATE VIEW babel_2877_vu_prepare_view1 AS SELECT babel_2877_vu_prepare_func1(20, 'def', $5); +GO + +CREATE VIEW babel_2877_vu_prepare_view2 AS SELECT babel_2877_vu_prepare_func2(); +GO + +CREATE VIEW babel_2877_vu_prepare_view3 AS SELECT babel_2877_vu_prepare_func1(20, 'def', $10, 1.8); +GO + +-- CASE: Check for session properties like ANSI_NULLS and QUOTED_IDENTIFIER +-- ANSI_NULLS - Last bit from left in flag_values +-- QUOTED_IDENTIFIER - Second last bit from left in flag_values +SET ANSI_NULLS ON; +GO + +SET QUOTED_IDENTIFIER ON; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDON] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET ANSI_NULLS OFF; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDON] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET QUOTED_IDENTIFIER OFF; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDOFF] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET ANSI_NULLS ON; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDOFF] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +-- reset session properties +SET ANSI_NULLS ON; +GO + +SET QUOTED_IDENTIFIER ON; +GO \ No newline at end of file diff --git a/test/JDBC/upgrade/14_7/preparation/Test-sp_babelfish_volatility-vu-prepare.sql b/test/JDBC/upgrade/14_7/preparation/Test-sp_babelfish_volatility-vu-prepare.sql new file mode 100644 index 0000000000..9be5872d7d --- /dev/null +++ b/test/JDBC/upgrade/14_7/preparation/Test-sp_babelfish_volatility-vu-prepare.sql @@ -0,0 +1,70 @@ +create function test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +go + +create schema test_sp_babelfish_volatility_schema1 +go + +create function test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +go + +create schema [test_sp_babelfish_volatility_schema1 with .dot and spaces] +go + +create function [test_sp_babelfish_volatility_schema1 with .dot and spaces].test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +go + +CREATE LOGIN test_sp_babelfish_volatility_login WITH PASSWORD = '12345678'; +GO + +CREATE DATABASE test_sp_babelfish_volatility_db1 +GO + +USE test_sp_babelfish_volatility_db1 +GO + +CREATE SCHEMA test_sp_babelfish_volatility_schema2 +GO + +create function test_sp_babelfish_volatility_f2() returns int begin declare @a int; set @a = 1; return @a; end +GO + +create function test_sp_babelfish_volatility_duplicate() returns int begin declare @a int; set @a = 1; return @a; end +go + +create function test_sp_babelfish_volatility_duplicate(@b int) returns int begin declare @a int; set @a = 1; return @a; end +go + +create function test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +GO + +create schema test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa; +go + +create function test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa() +returns int begin declare @a int; set @a = 1; return @a; end +go + +create function test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa() +returns int begin declare @a int; set @a = 1; return @a; end +go + +CREATE USER test_sp_babelfish_volatility_user FOR LOGIN test_sp_babelfish_volatility_login +GO + +use master +go + +create table test_bbf_vol_t1(a int) +go + +create function test_bbf_vol_f1() returns int begin declare @a int; set @a = 1; return @a; end +go + +create function [test_bbf_vol_f1;drop table test_bbf_vol_t1;]() returns int begin declare @a int; set @a = 1; return @a; end +go + +use test_sp_babelfish_volatility_db1 +go + +CREATE LOGIN test_sp_babelfish_volatility_login_2 WITH PASSWORD = '12345678' +GO diff --git a/test/JDBC/upgrade/14_7/schedule b/test/JDBC/upgrade/14_7/schedule index c0a68dfa9a..d424e13be3 100644 --- a/test/JDBC/upgrade/14_7/schedule +++ b/test/JDBC/upgrade/14_7/schedule @@ -241,7 +241,6 @@ sys-sql_modules-dep sys-system_sql_modules-dep sys-triggers-dep sys-proc_param_helper-dep -BABEL-2877 sys-sp_pkeys sys-sp_statistics BABEL-APPLOCK @@ -386,7 +385,6 @@ BABEL_OBJECT_NAME Test-sp_rename Test-sp_rename-dep BABEL-3657 -Test-sp_babelfish_volatility BABEL-733 BABEL-3938 babel_context_info diff --git a/test/JDBC/upgrade/14_8/preparation/BABEL-2877-vu-prepare.sql b/test/JDBC/upgrade/14_8/preparation/BABEL-2877-vu-prepare.sql new file mode 100644 index 0000000000..b740c68c1e --- /dev/null +++ b/test/JDBC/upgrade/14_8/preparation/BABEL-2877-vu-prepare.sql @@ -0,0 +1,100 @@ +-- Function +-- Defaults at different positions +CREATE FUNCTION babel_2877_vu_prepare_func1 (@a int, @b varchar(10) = 'abc', @c money, @d float = 1.2) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- All parameters with defaults +CREATE FUNCTION babel_2877_vu_prepare_func2 (@a int = 10, @b varchar(10) = 'abc', @c money = $5, @d float = 1.2) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- No defaults +CREATE FUNCTION babel_2877_vu_prepare_func3 (@a int, @b varchar(10), @c money, @d float) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- Procedure +-- Defaults at different positions +CREATE PROCEDURE babel_2877_vu_prepare_proc1 (@a int, @b varchar(10) = 'abc', @c money = $5, @d float) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- All parameters with defaults +CREATE PROCEDURE babel_2877_vu_prepare_proc2 (@a int = 10, @b varchar(10) = 'abc', @c money = $5, @d float = 1.2) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- No defaults +CREATE PROCEDURE babel_2877_vu_prepare_proc3 (@a int, @b varchar(10), @c money, @d float) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- Views +CREATE VIEW babel_2877_vu_prepare_view1 AS SELECT babel_2877_vu_prepare_func1(20, 'def', $5); +GO + +CREATE VIEW babel_2877_vu_prepare_view2 AS SELECT babel_2877_vu_prepare_func2(); +GO + +CREATE VIEW babel_2877_vu_prepare_view3 AS SELECT babel_2877_vu_prepare_func1(20, 'def', $10, 1.8); +GO + +-- CASE: Check for session properties like ANSI_NULLS and QUOTED_IDENTIFIER +-- ANSI_NULLS - Last bit from left in flag_values +-- QUOTED_IDENTIFIER - Second last bit from left in flag_values +SET ANSI_NULLS ON; +GO + +SET QUOTED_IDENTIFIER ON; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDON] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET ANSI_NULLS OFF; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDON] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET QUOTED_IDENTIFIER OFF; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDOFF] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET ANSI_NULLS ON; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDOFF] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +-- reset session properties +SET ANSI_NULLS ON; +GO + +SET QUOTED_IDENTIFIER ON; +GO \ No newline at end of file diff --git a/test/JDBC/upgrade/14_8/preparation/Test-sp_babelfish_volatility-vu-prepare.sql b/test/JDBC/upgrade/14_8/preparation/Test-sp_babelfish_volatility-vu-prepare.sql new file mode 100644 index 0000000000..9be5872d7d --- /dev/null +++ b/test/JDBC/upgrade/14_8/preparation/Test-sp_babelfish_volatility-vu-prepare.sql @@ -0,0 +1,70 @@ +create function test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +go + +create schema test_sp_babelfish_volatility_schema1 +go + +create function test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +go + +create schema [test_sp_babelfish_volatility_schema1 with .dot and spaces] +go + +create function [test_sp_babelfish_volatility_schema1 with .dot and spaces].test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +go + +CREATE LOGIN test_sp_babelfish_volatility_login WITH PASSWORD = '12345678'; +GO + +CREATE DATABASE test_sp_babelfish_volatility_db1 +GO + +USE test_sp_babelfish_volatility_db1 +GO + +CREATE SCHEMA test_sp_babelfish_volatility_schema2 +GO + +create function test_sp_babelfish_volatility_f2() returns int begin declare @a int; set @a = 1; return @a; end +GO + +create function test_sp_babelfish_volatility_duplicate() returns int begin declare @a int; set @a = 1; return @a; end +go + +create function test_sp_babelfish_volatility_duplicate(@b int) returns int begin declare @a int; set @a = 1; return @a; end +go + +create function test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +GO + +create schema test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa; +go + +create function test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa() +returns int begin declare @a int; set @a = 1; return @a; end +go + +create function test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa() +returns int begin declare @a int; set @a = 1; return @a; end +go + +CREATE USER test_sp_babelfish_volatility_user FOR LOGIN test_sp_babelfish_volatility_login +GO + +use master +go + +create table test_bbf_vol_t1(a int) +go + +create function test_bbf_vol_f1() returns int begin declare @a int; set @a = 1; return @a; end +go + +create function [test_bbf_vol_f1;drop table test_bbf_vol_t1;]() returns int begin declare @a int; set @a = 1; return @a; end +go + +use test_sp_babelfish_volatility_db1 +go + +CREATE LOGIN test_sp_babelfish_volatility_login_2 WITH PASSWORD = '12345678' +GO diff --git a/test/JDBC/upgrade/14_8/schedule b/test/JDBC/upgrade/14_8/schedule index 381beefef4..b85aa3ed36 100644 --- a/test/JDBC/upgrade/14_8/schedule +++ b/test/JDBC/upgrade/14_8/schedule @@ -241,7 +241,6 @@ sys-sql_modules-dep sys-system_sql_modules-dep sys-triggers-dep sys-proc_param_helper-dep -BABEL-2877 sys-sp_pkeys sys-sp_statistics BABEL-APPLOCK @@ -386,7 +385,6 @@ BABEL_OBJECT_NAME Test-sp_rename Test-sp_rename-dep BABEL-3657 -Test-sp_babelfish_volatility BABEL-733 BABEL-3938 binary-index diff --git a/test/JDBC/upgrade/15_1/preparation/BABEL-2877-vu-prepare.sql b/test/JDBC/upgrade/15_1/preparation/BABEL-2877-vu-prepare.sql new file mode 100644 index 0000000000..b740c68c1e --- /dev/null +++ b/test/JDBC/upgrade/15_1/preparation/BABEL-2877-vu-prepare.sql @@ -0,0 +1,100 @@ +-- Function +-- Defaults at different positions +CREATE FUNCTION babel_2877_vu_prepare_func1 (@a int, @b varchar(10) = 'abc', @c money, @d float = 1.2) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- All parameters with defaults +CREATE FUNCTION babel_2877_vu_prepare_func2 (@a int = 10, @b varchar(10) = 'abc', @c money = $5, @d float = 1.2) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- No defaults +CREATE FUNCTION babel_2877_vu_prepare_func3 (@a int, @b varchar(10), @c money, @d float) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- Procedure +-- Defaults at different positions +CREATE PROCEDURE babel_2877_vu_prepare_proc1 (@a int, @b varchar(10) = 'abc', @c money = $5, @d float) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- All parameters with defaults +CREATE PROCEDURE babel_2877_vu_prepare_proc2 (@a int = 10, @b varchar(10) = 'abc', @c money = $5, @d float = 1.2) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- No defaults +CREATE PROCEDURE babel_2877_vu_prepare_proc3 (@a int, @b varchar(10), @c money, @d float) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- Views +CREATE VIEW babel_2877_vu_prepare_view1 AS SELECT babel_2877_vu_prepare_func1(20, 'def', $5); +GO + +CREATE VIEW babel_2877_vu_prepare_view2 AS SELECT babel_2877_vu_prepare_func2(); +GO + +CREATE VIEW babel_2877_vu_prepare_view3 AS SELECT babel_2877_vu_prepare_func1(20, 'def', $10, 1.8); +GO + +-- CASE: Check for session properties like ANSI_NULLS and QUOTED_IDENTIFIER +-- ANSI_NULLS - Last bit from left in flag_values +-- QUOTED_IDENTIFIER - Second last bit from left in flag_values +SET ANSI_NULLS ON; +GO + +SET QUOTED_IDENTIFIER ON; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDON] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET ANSI_NULLS OFF; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDON] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET QUOTED_IDENTIFIER OFF; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDOFF] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET ANSI_NULLS ON; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDOFF] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +-- reset session properties +SET ANSI_NULLS ON; +GO + +SET QUOTED_IDENTIFIER ON; +GO \ No newline at end of file diff --git a/test/JDBC/upgrade/15_1/schedule b/test/JDBC/upgrade/15_1/schedule index 9a3e4c1aa3..55ec667ef5 100644 --- a/test/JDBC/upgrade/15_1/schedule +++ b/test/JDBC/upgrade/15_1/schedule @@ -233,7 +233,6 @@ sys-sql_modules-dep sys-system_sql_modules-dep sys-triggers-dep sys-proc_param_helper-dep -BABEL-2877 sys-sp_pkeys sys-sp_statistics BABEL-APPLOCK @@ -363,7 +362,6 @@ sys-sql_modules_before-14_7-or-15_2 BABEL_OBJECT_ID test_windows_login_before_15_2 openjson -Test-sp_babelfish_volatility BABEL_SCHEMATA datediff_internal_date-before-14_7-or-15_2 BABEL_OBJECT_NAME diff --git a/test/JDBC/upgrade/15_2/preparation/BABEL-2877-vu-prepare.sql b/test/JDBC/upgrade/15_2/preparation/BABEL-2877-vu-prepare.sql new file mode 100644 index 0000000000..b740c68c1e --- /dev/null +++ b/test/JDBC/upgrade/15_2/preparation/BABEL-2877-vu-prepare.sql @@ -0,0 +1,100 @@ +-- Function +-- Defaults at different positions +CREATE FUNCTION babel_2877_vu_prepare_func1 (@a int, @b varchar(10) = 'abc', @c money, @d float = 1.2) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- All parameters with defaults +CREATE FUNCTION babel_2877_vu_prepare_func2 (@a int = 10, @b varchar(10) = 'abc', @c money = $5, @d float = 1.2) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- No defaults +CREATE FUNCTION babel_2877_vu_prepare_func3 (@a int, @b varchar(10), @c money, @d float) +RETURNS varchar(100) AS +BEGIN + RETURN CAST(@a AS varchar(10)) + @b + CAST(@c AS varchar(10)) + CAST(@d AS varchar(10)); +END +GO + +-- Procedure +-- Defaults at different positions +CREATE PROCEDURE babel_2877_vu_prepare_proc1 (@a int, @b varchar(10) = 'abc', @c money = $5, @d float) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- All parameters with defaults +CREATE PROCEDURE babel_2877_vu_prepare_proc2 (@a int = 10, @b varchar(10) = 'abc', @c money = $5, @d float = 1.2) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- No defaults +CREATE PROCEDURE babel_2877_vu_prepare_proc3 (@a int, @b varchar(10), @c money, @d float) +AS +BEGIN + SELECT @a, @b, @c, @d; +END +GO + +-- Views +CREATE VIEW babel_2877_vu_prepare_view1 AS SELECT babel_2877_vu_prepare_func1(20, 'def', $5); +GO + +CREATE VIEW babel_2877_vu_prepare_view2 AS SELECT babel_2877_vu_prepare_func2(); +GO + +CREATE VIEW babel_2877_vu_prepare_view3 AS SELECT babel_2877_vu_prepare_func1(20, 'def', $10, 1.8); +GO + +-- CASE: Check for session properties like ANSI_NULLS and QUOTED_IDENTIFIER +-- ANSI_NULLS - Last bit from left in flag_values +-- QUOTED_IDENTIFIER - Second last bit from left in flag_values +SET ANSI_NULLS ON; +GO + +SET QUOTED_IDENTIFIER ON; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDON] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET ANSI_NULLS OFF; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDON] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET QUOTED_IDENTIFIER OFF; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDOFF] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +SET ANSI_NULLS ON; +GO + +CREATE FUNCTION [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDOFF] (@a int) +RETURNS INT AS BEGIN RETURN 1; END; +GO + +-- reset session properties +SET ANSI_NULLS ON; +GO + +SET QUOTED_IDENTIFIER ON; +GO \ No newline at end of file diff --git a/test/JDBC/upgrade/15_2/preparation/Test-sp_babelfish_volatility-vu-prepare.sql b/test/JDBC/upgrade/15_2/preparation/Test-sp_babelfish_volatility-vu-prepare.sql new file mode 100644 index 0000000000..9be5872d7d --- /dev/null +++ b/test/JDBC/upgrade/15_2/preparation/Test-sp_babelfish_volatility-vu-prepare.sql @@ -0,0 +1,70 @@ +create function test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +go + +create schema test_sp_babelfish_volatility_schema1 +go + +create function test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +go + +create schema [test_sp_babelfish_volatility_schema1 with .dot and spaces] +go + +create function [test_sp_babelfish_volatility_schema1 with .dot and spaces].test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +go + +CREATE LOGIN test_sp_babelfish_volatility_login WITH PASSWORD = '12345678'; +GO + +CREATE DATABASE test_sp_babelfish_volatility_db1 +GO + +USE test_sp_babelfish_volatility_db1 +GO + +CREATE SCHEMA test_sp_babelfish_volatility_schema2 +GO + +create function test_sp_babelfish_volatility_f2() returns int begin declare @a int; set @a = 1; return @a; end +GO + +create function test_sp_babelfish_volatility_duplicate() returns int begin declare @a int; set @a = 1; return @a; end +go + +create function test_sp_babelfish_volatility_duplicate(@b int) returns int begin declare @a int; set @a = 1; return @a; end +go + +create function test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +GO + +create schema test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa; +go + +create function test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa() +returns int begin declare @a int; set @a = 1; return @a; end +go + +create function test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa() +returns int begin declare @a int; set @a = 1; return @a; end +go + +CREATE USER test_sp_babelfish_volatility_user FOR LOGIN test_sp_babelfish_volatility_login +GO + +use master +go + +create table test_bbf_vol_t1(a int) +go + +create function test_bbf_vol_f1() returns int begin declare @a int; set @a = 1; return @a; end +go + +create function [test_bbf_vol_f1;drop table test_bbf_vol_t1;]() returns int begin declare @a int; set @a = 1; return @a; end +go + +use test_sp_babelfish_volatility_db1 +go + +CREATE LOGIN test_sp_babelfish_volatility_login_2 WITH PASSWORD = '12345678' +GO diff --git a/test/JDBC/upgrade/15_2/schedule b/test/JDBC/upgrade/15_2/schedule index 78859feb76..e8afcbcb4f 100644 --- a/test/JDBC/upgrade/15_2/schedule +++ b/test/JDBC/upgrade/15_2/schedule @@ -240,7 +240,6 @@ sys-sql_modules-dep sys-system_sql_modules-dep sys-triggers-dep sys-proc_param_helper-dep -BABEL-2877 sys-sp_pkeys sys-sp_statistics BABEL-APPLOCK @@ -396,7 +395,6 @@ BABEL-3748 sys-systypes openjson BABEL-3702 -Test-sp_babelfish_volatility BABEL_OBJECT_DEFINITION Test-sp_rename Test-sp_rename-dep diff --git a/test/JDBC/upgrade/latest/verification_cleanup/14_6/BABEL-2877-vu-cleanup.sql b/test/JDBC/upgrade/latest/verification_cleanup/14_6/BABEL-2877-vu-cleanup.sql new file mode 100644 index 0000000000..55bbbf383e --- /dev/null +++ b/test/JDBC/upgrade/latest/verification_cleanup/14_6/BABEL-2877-vu-cleanup.sql @@ -0,0 +1,42 @@ +DROP VIEW babel_2877_vu_prepare_view1; +GO + +DROP VIEW babel_2877_vu_prepare_view2; +GO + +DROP VIEW babel_2877_vu_prepare_view3; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func1; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func2; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func3; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc1; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc2; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc3; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDON]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDON]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDOFF]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDOFF]; +GO + +-- babelfish_function_ext entry should have been removed after dropping all these functions/procedure +SELECT * FROM sys.babelfish_function_ext WHERE funcname LIKE 'babel_2877_vu_prepare%'; +GO \ No newline at end of file diff --git a/test/JDBC/upgrade/latest/verification_cleanup/14_6/BABEL-2877-vu-verify.sql b/test/JDBC/upgrade/latest/verification_cleanup/14_6/BABEL-2877-vu-verify.sql new file mode 100644 index 0000000000..504d9692f0 --- /dev/null +++ b/test/JDBC/upgrade/latest/verification_cleanup/14_6/BABEL-2877-vu-verify.sql @@ -0,0 +1,102 @@ +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func1' as regproc)); +GO + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func2' as regproc)); +GO + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func3' as regproc)); +GO + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc1' as regproc)); +GO + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc2' as regproc)); +GO + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc3' as regproc)); +GO + +SELECT * FROM babel_2877_vu_prepare_func1(10); -- should fail, required argument @c not supplied +GO + +SELECT * FROM babel_2877_vu_prepare_func1(10, 'abc', $5); +GO + +SELECT * FROM babel_2877_vu_prepare_func2(); +GO + +SELECT * FROM babel_2877_vu_prepare_func3(); -- should fail, all parameters are required +GO + +SELECT * FROM babel_2877_vu_prepare_func3(10, 'abc', $5, 1.2); +GO + +SELECT * FROM babel_2877_vu_prepare_view1; +GO + +SELECT * FROM babel_2877_vu_prepare_view2; +GO + +SELECT * FROM babel_2877_vu_prepare_view3; +GO + +EXEC babel_2877_vu_prepare_proc1; -- should fail, required arguments @a and @d not supplied +GO + +EXEC babel_2877_vu_prepare_proc1 10; -- should fail, required argument @d not supplied +GO + +EXEC babel_2877_vu_prepare_proc1 @d=40; -- should fail, required argument @a not supplied +GO + +EXEC babel_2877_vu_prepare_proc1 @a = 10, @d = 1.8; +GO + +EXEC babel_2877_vu_prepare_proc1 @a = 10, @b = 20, @c = 30, @d = 40; +GO + +EXEC babel_2877_vu_prepare_proc2; +GO + +EXEC babel_2877_vu_prepare_proc2 @d = 1.5; +GO + +EXEC babel_2877_vu_prepare_proc3; -- should fail, all parameters are required +GO + +EXEC babel_2877_vu_prepare_proc3 10, 'def', $10, 1.8; -- should fail, all parameters are required +GO + +-- babelfish_function_ext table should have entry for all the above functions and procedures +SELECT nspname, + funcname, + funcsignature, + default_positions +FROM sys.babelfish_function_ext + WHERE funcname LIKE 'babel_2877_vu_prepare%' + AND funcname NOT LIKE '%ansi%' ORDER BY funcname; +GO + +SELECT orig_name, + CASE flag_validity & 1 + WHEN 0 + THEN NULL + ELSE + CASE flag_values & 1 + WHEN 0 + THEN 0 + ELSE 1 + END + END AS ansi_null, + CASE flag_validity & 2 + WHEN 0 + THEN NULL + ELSE + CASE flag_values & 2 + WHEN 0 + THEN 0 + ELSE 1 + END + END AS quoted_identifier +FROM sys.babelfish_function_ext WHERE funcname LIKE 'babel-2877-vu-prepare%' ORDER BY funcname; +GO diff --git a/test/JDBC/upgrade/latest/verification_cleanup/14_7/BABEL-2877-vu-cleanup.sql b/test/JDBC/upgrade/latest/verification_cleanup/14_7/BABEL-2877-vu-cleanup.sql new file mode 100644 index 0000000000..55bbbf383e --- /dev/null +++ b/test/JDBC/upgrade/latest/verification_cleanup/14_7/BABEL-2877-vu-cleanup.sql @@ -0,0 +1,42 @@ +DROP VIEW babel_2877_vu_prepare_view1; +GO + +DROP VIEW babel_2877_vu_prepare_view2; +GO + +DROP VIEW babel_2877_vu_prepare_view3; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func1; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func2; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func3; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc1; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc2; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc3; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDON]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDON]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDOFF]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDOFF]; +GO + +-- babelfish_function_ext entry should have been removed after dropping all these functions/procedure +SELECT * FROM sys.babelfish_function_ext WHERE funcname LIKE 'babel_2877_vu_prepare%'; +GO \ No newline at end of file diff --git a/test/JDBC/upgrade/latest/verification_cleanup/14_7/BABEL-2877-vu-verify.sql b/test/JDBC/upgrade/latest/verification_cleanup/14_7/BABEL-2877-vu-verify.sql new file mode 100644 index 0000000000..504d9692f0 --- /dev/null +++ b/test/JDBC/upgrade/latest/verification_cleanup/14_7/BABEL-2877-vu-verify.sql @@ -0,0 +1,102 @@ +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func1' as regproc)); +GO + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func2' as regproc)); +GO + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func3' as regproc)); +GO + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc1' as regproc)); +GO + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc2' as regproc)); +GO + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc3' as regproc)); +GO + +SELECT * FROM babel_2877_vu_prepare_func1(10); -- should fail, required argument @c not supplied +GO + +SELECT * FROM babel_2877_vu_prepare_func1(10, 'abc', $5); +GO + +SELECT * FROM babel_2877_vu_prepare_func2(); +GO + +SELECT * FROM babel_2877_vu_prepare_func3(); -- should fail, all parameters are required +GO + +SELECT * FROM babel_2877_vu_prepare_func3(10, 'abc', $5, 1.2); +GO + +SELECT * FROM babel_2877_vu_prepare_view1; +GO + +SELECT * FROM babel_2877_vu_prepare_view2; +GO + +SELECT * FROM babel_2877_vu_prepare_view3; +GO + +EXEC babel_2877_vu_prepare_proc1; -- should fail, required arguments @a and @d not supplied +GO + +EXEC babel_2877_vu_prepare_proc1 10; -- should fail, required argument @d not supplied +GO + +EXEC babel_2877_vu_prepare_proc1 @d=40; -- should fail, required argument @a not supplied +GO + +EXEC babel_2877_vu_prepare_proc1 @a = 10, @d = 1.8; +GO + +EXEC babel_2877_vu_prepare_proc1 @a = 10, @b = 20, @c = 30, @d = 40; +GO + +EXEC babel_2877_vu_prepare_proc2; +GO + +EXEC babel_2877_vu_prepare_proc2 @d = 1.5; +GO + +EXEC babel_2877_vu_prepare_proc3; -- should fail, all parameters are required +GO + +EXEC babel_2877_vu_prepare_proc3 10, 'def', $10, 1.8; -- should fail, all parameters are required +GO + +-- babelfish_function_ext table should have entry for all the above functions and procedures +SELECT nspname, + funcname, + funcsignature, + default_positions +FROM sys.babelfish_function_ext + WHERE funcname LIKE 'babel_2877_vu_prepare%' + AND funcname NOT LIKE '%ansi%' ORDER BY funcname; +GO + +SELECT orig_name, + CASE flag_validity & 1 + WHEN 0 + THEN NULL + ELSE + CASE flag_values & 1 + WHEN 0 + THEN 0 + ELSE 1 + END + END AS ansi_null, + CASE flag_validity & 2 + WHEN 0 + THEN NULL + ELSE + CASE flag_values & 2 + WHEN 0 + THEN 0 + ELSE 1 + END + END AS quoted_identifier +FROM sys.babelfish_function_ext WHERE funcname LIKE 'babel-2877-vu-prepare%' ORDER BY funcname; +GO diff --git a/test/JDBC/upgrade/latest/verification_cleanup/14_7/Test-sp_babelfish_volatility-vu-cleanup.sql b/test/JDBC/upgrade/latest/verification_cleanup/14_7/Test-sp_babelfish_volatility-vu-cleanup.sql new file mode 100644 index 0000000000..80a368ffa7 --- /dev/null +++ b/test/JDBC/upgrade/latest/verification_cleanup/14_7/Test-sp_babelfish_volatility-vu-cleanup.sql @@ -0,0 +1,65 @@ +drop function test_sp_babelfish_volatility_f1 +go + +drop function test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1 +go + +drop schema test_sp_babelfish_volatility_schema1 +go + +drop function [test_sp_babelfish_volatility_schema1 with .dot and spaces].test_sp_babelfish_volatility_f1 +go + +drop schema [test_sp_babelfish_volatility_schema1 with .dot and spaces] +go + +use test_sp_babelfish_volatility_db1 +go + +drop function test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1 +go + +drop function test_sp_babelfish_volatility_f2 +go + +drop function test_sp_babelfish_volatility_duplicate() +go + +drop function test_sp_babelfish_volatility_duplicate(@b int) +go + +drop schema test_sp_babelfish_volatility_schema2 +go + +drop function test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa; +go + +drop function test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa; +go + +drop schema test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa; +go + +drop user test_sp_babelfish_volatility_user +go + +drop login test_sp_babelfish_volatility_login_2 +go + +use master +go + +drop database test_sp_babelfish_volatility_db1 +go + +drop login test_sp_babelfish_volatility_login +go + +drop table test_bbf_vol_t1 +go + +drop function test_bbf_vol_f1 +go + +drop function [test_bbf_vol_f1;drop table test_bbf_vol_t1;] +go diff --git a/test/JDBC/upgrade/latest/verification_cleanup/14_7/Test-sp_babelfish_volatility-vu-verify.mix b/test/JDBC/upgrade/latest/verification_cleanup/14_7/Test-sp_babelfish_volatility-vu-verify.mix new file mode 100644 index 0000000000..3f453cf070 --- /dev/null +++ b/test/JDBC/upgrade/latest/verification_cleanup/14_7/Test-sp_babelfish_volatility-vu-verify.mix @@ -0,0 +1,314 @@ +-- tsql +/* test without schema name */ +use master +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'stable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'volatile' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'random' +go +exec sys.sp_babelfish_volatility '.test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'stable' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'volatile' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'random' +go +sp_babelfish_volatility '.test_sp_babelfish_volatility_f1' +go + +/* test with schema name */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility '"test_sp_babelfish_volatility_schema1".test_sp_babelfish_volatility_f1', 'stable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1].test_sp_babelfish_volatility_f1', 'volatile' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'random' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'immutable' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility '"test_sp_babelfish_volatility_schema1".test_sp_babelfish_volatility_f1', 'stable' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1].test_sp_babelfish_volatility_f1', 'volatile' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'random' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go + +/* testing for trailing spaces */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1 ', 'stable ' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go + +/* testing for leading space should give error */ +exec sys.sp_babelfish_volatility ' test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', ' immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go + +/* testing for some invalid cases */ +exec sys.sp_babelfish_volatility 'master.test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'random_function' +go +exec sys.sp_babelfish_volatility '','immutable' +go +exec sys.sp_babelfish_volatility '' +go +exec sys.sp_babelfish_volatility NULL, 'stable' +go +exec sys.sp_babelfish_volatility '. test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_name_for_a_very_long_function_name_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_name_for_a_very_long_function_name_more_longer_longer_than_4000_characters_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +go + +/* testing for injection */ +exec sys.sp_babelfish_volatility 'ran;dom' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable; some random text' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'rand;om' +go +/* testing injection in function name */ +exec sys.sp_babelfish_volatility 'test_bbf_vol_f1' +go +exec sys.sp_babelfish_volatility '[test_bbf_vol_f1;drop table test_bbf_vol_t1;]' +go +exec sys.sp_babelfish_volatility '[test_bbf_vol_f1;drop table test_bbf_vol_t1;]', 'immutable' +go +exec sys.sp_babelfish_volatility '[test_bbf_vol_f1;drop table test_bbf_vol_t1;]' +go +exec sys.sp_babelfish_volatility 'test_bbf_vol_f1' +go +select * from test_bbf_vol_t1 +go + +/* testing for case insensitive */ +exec sys.sp_babelfish_volatility 'TesT_SP_babelfish_Volatility_f1', 'VolatILe' +go +exec sys.sp_babelfish_volatility 'TesT_Sp_babelfish_Volatility_F1' +go + +/* testing with dot and spaces in schema name */ +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1 with .dot and spaces].test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1 with .dot and spaces]."test_sp_babelfish_volatility_f1"' +go + +/* test in a database */ +use test_sp_babelfish_volatility_db1 +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' +go +/* test with duplicate function name */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_duplicate' +go +/* test with long names */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa', 'immutable' +go +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa]' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa', 'immutable' +go +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa].[test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa]' +go +/* test with trucated names */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7', 'volatile' +go +exec sys.sp_babelfish_volatility '"test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7"' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_scc62ee1eb13f7c4857c426f2affcc9a16.test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_scc62ee1eb13f7c4857c426f2affcc9a16.test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7', 'volatile' +go +exec sys.sp_babelfish_volatility '"test_sp_babelfish_volatility_scc62ee1eb13f7c4857c426f2affcc9a16".[test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7]' +go +exec sys.sp_babelfish_volatility +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go + +/* function on which user has privilege is only visible */ +-- tsql user=test_sp_babelfish_volatility_login password=12345678 +use test_sp_babelfish_volatility_db1 +go +select current_user +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'dbo.test_sp_babelfish_volatility_f2' +go +exec sys.sp_babelfish_volatility +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'dbo.test_sp_babelfish_volatility_f2' +go +sp_babelfish_volatility +go + +/* grant access to current user */ +-- tsql +use test_sp_babelfish_volatility_db1 +go +grant execute on test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1 to test_sp_babelfish_volatility_user +go +grant execute on test_sp_babelfish_volatility_f2 to test_sp_babelfish_volatility_user +go + +-- tsql user=test_sp_babelfish_volatility_login password=12345678 +use test_sp_babelfish_volatility_db1 +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +exec sys.sp_babelfish_volatility +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +sp_babelfish_volatility +go + +/* test for default schema */ +-- tsql +use test_sp_babelfish_volatility_db1 +go +ALTER USER test_sp_babelfish_volatility_user WITH DEFAULT_SCHEMA=test_sp_babelfish_volatility_schema2 +GO + +-- tsql user=test_sp_babelfish_volatility_login password=12345678 +use test_sp_babelfish_volatility_db1 +go +select current_user +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1 ' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +exec sys.sp_babelfish_volatility 'dbo.test_sp_babelfish_volatility_f2' +go +exec sys.sp_babelfish_volatility +go + +/* revoke the priviledges to the user */ +-- tsql +use test_sp_babelfish_volatility_db1 +go +revoke execute on test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1 from test_sp_babelfish_volatility_user +go +revoke execute on test_sp_babelfish_volatility_f2 from test_sp_babelfish_volatility_user +go + +/* test default schema in guest user */ +-- tsql +use test_sp_babelfish_volatility_db1 +go +grant connect to guest +go + +-- tsql user=test_sp_babelfish_volatility_login_2 password=12345678 +use test_sp_babelfish_volatility_db1 +go +SELECT current_user +go +create function test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable'; +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'dbo.test_sp_babelfish_volatility_f2' +go +sp_babelfish_volatility +go +drop function test_sp_babelfish_volatility_f1 +go + +-- tsql +use test_sp_babelfish_volatility_db1 +go +revoke connect from guest +go + +-- psql +-- Need to terminate active session before cleaning up the login +SELECT pg_terminate_backend(pid) FROM pg_stat_get_activity(NULL) +WHERE sys.suser_name(usesysid) = 'test_sp_babelfish_volatility_user' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +GO +-- Wait to sync with another session +SELECT pg_sleep(1); +GO diff --git a/test/JDBC/upgrade/latest/verification_cleanup/14_8/BABEL-2877-vu-cleanup.sql b/test/JDBC/upgrade/latest/verification_cleanup/14_8/BABEL-2877-vu-cleanup.sql new file mode 100644 index 0000000000..55bbbf383e --- /dev/null +++ b/test/JDBC/upgrade/latest/verification_cleanup/14_8/BABEL-2877-vu-cleanup.sql @@ -0,0 +1,42 @@ +DROP VIEW babel_2877_vu_prepare_view1; +GO + +DROP VIEW babel_2877_vu_prepare_view2; +GO + +DROP VIEW babel_2877_vu_prepare_view3; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func1; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func2; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func3; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc1; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc2; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc3; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDON]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDON]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDOFF]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDOFF]; +GO + +-- babelfish_function_ext entry should have been removed after dropping all these functions/procedure +SELECT * FROM sys.babelfish_function_ext WHERE funcname LIKE 'babel_2877_vu_prepare%'; +GO \ No newline at end of file diff --git a/test/JDBC/upgrade/latest/verification_cleanup/14_8/BABEL-2877-vu-verify.sql b/test/JDBC/upgrade/latest/verification_cleanup/14_8/BABEL-2877-vu-verify.sql new file mode 100644 index 0000000000..504d9692f0 --- /dev/null +++ b/test/JDBC/upgrade/latest/verification_cleanup/14_8/BABEL-2877-vu-verify.sql @@ -0,0 +1,102 @@ +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func1' as regproc)); +GO + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func2' as regproc)); +GO + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func3' as regproc)); +GO + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc1' as regproc)); +GO + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc2' as regproc)); +GO + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc3' as regproc)); +GO + +SELECT * FROM babel_2877_vu_prepare_func1(10); -- should fail, required argument @c not supplied +GO + +SELECT * FROM babel_2877_vu_prepare_func1(10, 'abc', $5); +GO + +SELECT * FROM babel_2877_vu_prepare_func2(); +GO + +SELECT * FROM babel_2877_vu_prepare_func3(); -- should fail, all parameters are required +GO + +SELECT * FROM babel_2877_vu_prepare_func3(10, 'abc', $5, 1.2); +GO + +SELECT * FROM babel_2877_vu_prepare_view1; +GO + +SELECT * FROM babel_2877_vu_prepare_view2; +GO + +SELECT * FROM babel_2877_vu_prepare_view3; +GO + +EXEC babel_2877_vu_prepare_proc1; -- should fail, required arguments @a and @d not supplied +GO + +EXEC babel_2877_vu_prepare_proc1 10; -- should fail, required argument @d not supplied +GO + +EXEC babel_2877_vu_prepare_proc1 @d=40; -- should fail, required argument @a not supplied +GO + +EXEC babel_2877_vu_prepare_proc1 @a = 10, @d = 1.8; +GO + +EXEC babel_2877_vu_prepare_proc1 @a = 10, @b = 20, @c = 30, @d = 40; +GO + +EXEC babel_2877_vu_prepare_proc2; +GO + +EXEC babel_2877_vu_prepare_proc2 @d = 1.5; +GO + +EXEC babel_2877_vu_prepare_proc3; -- should fail, all parameters are required +GO + +EXEC babel_2877_vu_prepare_proc3 10, 'def', $10, 1.8; -- should fail, all parameters are required +GO + +-- babelfish_function_ext table should have entry for all the above functions and procedures +SELECT nspname, + funcname, + funcsignature, + default_positions +FROM sys.babelfish_function_ext + WHERE funcname LIKE 'babel_2877_vu_prepare%' + AND funcname NOT LIKE '%ansi%' ORDER BY funcname; +GO + +SELECT orig_name, + CASE flag_validity & 1 + WHEN 0 + THEN NULL + ELSE + CASE flag_values & 1 + WHEN 0 + THEN 0 + ELSE 1 + END + END AS ansi_null, + CASE flag_validity & 2 + WHEN 0 + THEN NULL + ELSE + CASE flag_values & 2 + WHEN 0 + THEN 0 + ELSE 1 + END + END AS quoted_identifier +FROM sys.babelfish_function_ext WHERE funcname LIKE 'babel-2877-vu-prepare%' ORDER BY funcname; +GO diff --git a/test/JDBC/upgrade/latest/verification_cleanup/14_8/Test-sp_babelfish_volatility-vu-cleanup.sql b/test/JDBC/upgrade/latest/verification_cleanup/14_8/Test-sp_babelfish_volatility-vu-cleanup.sql new file mode 100644 index 0000000000..80a368ffa7 --- /dev/null +++ b/test/JDBC/upgrade/latest/verification_cleanup/14_8/Test-sp_babelfish_volatility-vu-cleanup.sql @@ -0,0 +1,65 @@ +drop function test_sp_babelfish_volatility_f1 +go + +drop function test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1 +go + +drop schema test_sp_babelfish_volatility_schema1 +go + +drop function [test_sp_babelfish_volatility_schema1 with .dot and spaces].test_sp_babelfish_volatility_f1 +go + +drop schema [test_sp_babelfish_volatility_schema1 with .dot and spaces] +go + +use test_sp_babelfish_volatility_db1 +go + +drop function test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1 +go + +drop function test_sp_babelfish_volatility_f2 +go + +drop function test_sp_babelfish_volatility_duplicate() +go + +drop function test_sp_babelfish_volatility_duplicate(@b int) +go + +drop schema test_sp_babelfish_volatility_schema2 +go + +drop function test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa; +go + +drop function test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa; +go + +drop schema test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa; +go + +drop user test_sp_babelfish_volatility_user +go + +drop login test_sp_babelfish_volatility_login_2 +go + +use master +go + +drop database test_sp_babelfish_volatility_db1 +go + +drop login test_sp_babelfish_volatility_login +go + +drop table test_bbf_vol_t1 +go + +drop function test_bbf_vol_f1 +go + +drop function [test_bbf_vol_f1;drop table test_bbf_vol_t1;] +go diff --git a/test/JDBC/upgrade/latest/verification_cleanup/14_8/Test-sp_babelfish_volatility-vu-verify.mix b/test/JDBC/upgrade/latest/verification_cleanup/14_8/Test-sp_babelfish_volatility-vu-verify.mix new file mode 100644 index 0000000000..3f453cf070 --- /dev/null +++ b/test/JDBC/upgrade/latest/verification_cleanup/14_8/Test-sp_babelfish_volatility-vu-verify.mix @@ -0,0 +1,314 @@ +-- tsql +/* test without schema name */ +use master +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'stable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'volatile' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'random' +go +exec sys.sp_babelfish_volatility '.test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'stable' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'volatile' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'random' +go +sp_babelfish_volatility '.test_sp_babelfish_volatility_f1' +go + +/* test with schema name */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility '"test_sp_babelfish_volatility_schema1".test_sp_babelfish_volatility_f1', 'stable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1].test_sp_babelfish_volatility_f1', 'volatile' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'random' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'immutable' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility '"test_sp_babelfish_volatility_schema1".test_sp_babelfish_volatility_f1', 'stable' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1].test_sp_babelfish_volatility_f1', 'volatile' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'random' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go + +/* testing for trailing spaces */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1 ', 'stable ' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go + +/* testing for leading space should give error */ +exec sys.sp_babelfish_volatility ' test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', ' immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go + +/* testing for some invalid cases */ +exec sys.sp_babelfish_volatility 'master.test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'random_function' +go +exec sys.sp_babelfish_volatility '','immutable' +go +exec sys.sp_babelfish_volatility '' +go +exec sys.sp_babelfish_volatility NULL, 'stable' +go +exec sys.sp_babelfish_volatility '. test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_name_for_a_very_long_function_name_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_name_for_a_very_long_function_name_more_longer_longer_than_4000_characters_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +go + +/* testing for injection */ +exec sys.sp_babelfish_volatility 'ran;dom' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable; some random text' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'rand;om' +go +/* testing injection in function name */ +exec sys.sp_babelfish_volatility 'test_bbf_vol_f1' +go +exec sys.sp_babelfish_volatility '[test_bbf_vol_f1;drop table test_bbf_vol_t1;]' +go +exec sys.sp_babelfish_volatility '[test_bbf_vol_f1;drop table test_bbf_vol_t1;]', 'immutable' +go +exec sys.sp_babelfish_volatility '[test_bbf_vol_f1;drop table test_bbf_vol_t1;]' +go +exec sys.sp_babelfish_volatility 'test_bbf_vol_f1' +go +select * from test_bbf_vol_t1 +go + +/* testing for case insensitive */ +exec sys.sp_babelfish_volatility 'TesT_SP_babelfish_Volatility_f1', 'VolatILe' +go +exec sys.sp_babelfish_volatility 'TesT_Sp_babelfish_Volatility_F1' +go + +/* testing with dot and spaces in schema name */ +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1 with .dot and spaces].test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1 with .dot and spaces]."test_sp_babelfish_volatility_f1"' +go + +/* test in a database */ +use test_sp_babelfish_volatility_db1 +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' +go +/* test with duplicate function name */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_duplicate' +go +/* test with long names */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa', 'immutable' +go +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa]' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa', 'immutable' +go +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa].[test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa]' +go +/* test with trucated names */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7', 'volatile' +go +exec sys.sp_babelfish_volatility '"test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7"' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_scc62ee1eb13f7c4857c426f2affcc9a16.test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_scc62ee1eb13f7c4857c426f2affcc9a16.test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7', 'volatile' +go +exec sys.sp_babelfish_volatility '"test_sp_babelfish_volatility_scc62ee1eb13f7c4857c426f2affcc9a16".[test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7]' +go +exec sys.sp_babelfish_volatility +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go + +/* function on which user has privilege is only visible */ +-- tsql user=test_sp_babelfish_volatility_login password=12345678 +use test_sp_babelfish_volatility_db1 +go +select current_user +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'dbo.test_sp_babelfish_volatility_f2' +go +exec sys.sp_babelfish_volatility +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'dbo.test_sp_babelfish_volatility_f2' +go +sp_babelfish_volatility +go + +/* grant access to current user */ +-- tsql +use test_sp_babelfish_volatility_db1 +go +grant execute on test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1 to test_sp_babelfish_volatility_user +go +grant execute on test_sp_babelfish_volatility_f2 to test_sp_babelfish_volatility_user +go + +-- tsql user=test_sp_babelfish_volatility_login password=12345678 +use test_sp_babelfish_volatility_db1 +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +exec sys.sp_babelfish_volatility +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +sp_babelfish_volatility +go + +/* test for default schema */ +-- tsql +use test_sp_babelfish_volatility_db1 +go +ALTER USER test_sp_babelfish_volatility_user WITH DEFAULT_SCHEMA=test_sp_babelfish_volatility_schema2 +GO + +-- tsql user=test_sp_babelfish_volatility_login password=12345678 +use test_sp_babelfish_volatility_db1 +go +select current_user +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1 ' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +exec sys.sp_babelfish_volatility 'dbo.test_sp_babelfish_volatility_f2' +go +exec sys.sp_babelfish_volatility +go + +/* revoke the priviledges to the user */ +-- tsql +use test_sp_babelfish_volatility_db1 +go +revoke execute on test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1 from test_sp_babelfish_volatility_user +go +revoke execute on test_sp_babelfish_volatility_f2 from test_sp_babelfish_volatility_user +go + +/* test default schema in guest user */ +-- tsql +use test_sp_babelfish_volatility_db1 +go +grant connect to guest +go + +-- tsql user=test_sp_babelfish_volatility_login_2 password=12345678 +use test_sp_babelfish_volatility_db1 +go +SELECT current_user +go +create function test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable'; +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'dbo.test_sp_babelfish_volatility_f2' +go +sp_babelfish_volatility +go +drop function test_sp_babelfish_volatility_f1 +go + +-- tsql +use test_sp_babelfish_volatility_db1 +go +revoke connect from guest +go + +-- psql +-- Need to terminate active session before cleaning up the login +SELECT pg_terminate_backend(pid) FROM pg_stat_get_activity(NULL) +WHERE sys.suser_name(usesysid) = 'test_sp_babelfish_volatility_user' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +GO +-- Wait to sync with another session +SELECT pg_sleep(1); +GO diff --git a/test/JDBC/upgrade/latest/verification_cleanup/15_1/BABEL-2877-vu-cleanup.sql b/test/JDBC/upgrade/latest/verification_cleanup/15_1/BABEL-2877-vu-cleanup.sql new file mode 100644 index 0000000000..55bbbf383e --- /dev/null +++ b/test/JDBC/upgrade/latest/verification_cleanup/15_1/BABEL-2877-vu-cleanup.sql @@ -0,0 +1,42 @@ +DROP VIEW babel_2877_vu_prepare_view1; +GO + +DROP VIEW babel_2877_vu_prepare_view2; +GO + +DROP VIEW babel_2877_vu_prepare_view3; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func1; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func2; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func3; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc1; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc2; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc3; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDON]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDON]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDOFF]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDOFF]; +GO + +-- babelfish_function_ext entry should have been removed after dropping all these functions/procedure +SELECT * FROM sys.babelfish_function_ext WHERE funcname LIKE 'babel_2877_vu_prepare%'; +GO \ No newline at end of file diff --git a/test/JDBC/upgrade/latest/verification_cleanup/15_1/BABEL-2877-vu-verify.sql b/test/JDBC/upgrade/latest/verification_cleanup/15_1/BABEL-2877-vu-verify.sql new file mode 100644 index 0000000000..504d9692f0 --- /dev/null +++ b/test/JDBC/upgrade/latest/verification_cleanup/15_1/BABEL-2877-vu-verify.sql @@ -0,0 +1,102 @@ +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func1' as regproc)); +GO + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func2' as regproc)); +GO + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func3' as regproc)); +GO + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc1' as regproc)); +GO + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc2' as regproc)); +GO + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc3' as regproc)); +GO + +SELECT * FROM babel_2877_vu_prepare_func1(10); -- should fail, required argument @c not supplied +GO + +SELECT * FROM babel_2877_vu_prepare_func1(10, 'abc', $5); +GO + +SELECT * FROM babel_2877_vu_prepare_func2(); +GO + +SELECT * FROM babel_2877_vu_prepare_func3(); -- should fail, all parameters are required +GO + +SELECT * FROM babel_2877_vu_prepare_func3(10, 'abc', $5, 1.2); +GO + +SELECT * FROM babel_2877_vu_prepare_view1; +GO + +SELECT * FROM babel_2877_vu_prepare_view2; +GO + +SELECT * FROM babel_2877_vu_prepare_view3; +GO + +EXEC babel_2877_vu_prepare_proc1; -- should fail, required arguments @a and @d not supplied +GO + +EXEC babel_2877_vu_prepare_proc1 10; -- should fail, required argument @d not supplied +GO + +EXEC babel_2877_vu_prepare_proc1 @d=40; -- should fail, required argument @a not supplied +GO + +EXEC babel_2877_vu_prepare_proc1 @a = 10, @d = 1.8; +GO + +EXEC babel_2877_vu_prepare_proc1 @a = 10, @b = 20, @c = 30, @d = 40; +GO + +EXEC babel_2877_vu_prepare_proc2; +GO + +EXEC babel_2877_vu_prepare_proc2 @d = 1.5; +GO + +EXEC babel_2877_vu_prepare_proc3; -- should fail, all parameters are required +GO + +EXEC babel_2877_vu_prepare_proc3 10, 'def', $10, 1.8; -- should fail, all parameters are required +GO + +-- babelfish_function_ext table should have entry for all the above functions and procedures +SELECT nspname, + funcname, + funcsignature, + default_positions +FROM sys.babelfish_function_ext + WHERE funcname LIKE 'babel_2877_vu_prepare%' + AND funcname NOT LIKE '%ansi%' ORDER BY funcname; +GO + +SELECT orig_name, + CASE flag_validity & 1 + WHEN 0 + THEN NULL + ELSE + CASE flag_values & 1 + WHEN 0 + THEN 0 + ELSE 1 + END + END AS ansi_null, + CASE flag_validity & 2 + WHEN 0 + THEN NULL + ELSE + CASE flag_values & 2 + WHEN 0 + THEN 0 + ELSE 1 + END + END AS quoted_identifier +FROM sys.babelfish_function_ext WHERE funcname LIKE 'babel-2877-vu-prepare%' ORDER BY funcname; +GO diff --git a/test/JDBC/upgrade/latest/verification_cleanup/15_2/BABEL-2877-vu-cleanup.sql b/test/JDBC/upgrade/latest/verification_cleanup/15_2/BABEL-2877-vu-cleanup.sql new file mode 100644 index 0000000000..55bbbf383e --- /dev/null +++ b/test/JDBC/upgrade/latest/verification_cleanup/15_2/BABEL-2877-vu-cleanup.sql @@ -0,0 +1,42 @@ +DROP VIEW babel_2877_vu_prepare_view1; +GO + +DROP VIEW babel_2877_vu_prepare_view2; +GO + +DROP VIEW babel_2877_vu_prepare_view3; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func1; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func2; +GO + +DROP FUNCTION IF EXISTS babel_2877_vu_prepare_func3; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc1; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc2; +GO + +DROP PROCEDURE IF EXISTS babel_2877_vu_prepare_proc3; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDON]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDON]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLOFF_QIDOFF]; +GO + +DROP FUNCTION IF EXISTS [BABEL-2877-vu-prepare_FUNC_ANSI_NULLON_QIDOFF]; +GO + +-- babelfish_function_ext entry should have been removed after dropping all these functions/procedure +SELECT * FROM sys.babelfish_function_ext WHERE funcname LIKE 'babel_2877_vu_prepare%'; +GO \ No newline at end of file diff --git a/test/JDBC/upgrade/latest/verification_cleanup/15_2/BABEL-2877-vu-verify.sql b/test/JDBC/upgrade/latest/verification_cleanup/15_2/BABEL-2877-vu-verify.sql new file mode 100644 index 0000000000..504d9692f0 --- /dev/null +++ b/test/JDBC/upgrade/latest/verification_cleanup/15_2/BABEL-2877-vu-verify.sql @@ -0,0 +1,102 @@ +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func1' as regproc)); +GO + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func2' as regproc)); +GO + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_func3' as regproc)); +GO + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc1' as regproc)); +GO + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc2' as regproc)); +GO + +SELECT pg_get_functiondef(cast('babel_2877_vu_prepare_proc3' as regproc)); +GO + +SELECT * FROM babel_2877_vu_prepare_func1(10); -- should fail, required argument @c not supplied +GO + +SELECT * FROM babel_2877_vu_prepare_func1(10, 'abc', $5); +GO + +SELECT * FROM babel_2877_vu_prepare_func2(); +GO + +SELECT * FROM babel_2877_vu_prepare_func3(); -- should fail, all parameters are required +GO + +SELECT * FROM babel_2877_vu_prepare_func3(10, 'abc', $5, 1.2); +GO + +SELECT * FROM babel_2877_vu_prepare_view1; +GO + +SELECT * FROM babel_2877_vu_prepare_view2; +GO + +SELECT * FROM babel_2877_vu_prepare_view3; +GO + +EXEC babel_2877_vu_prepare_proc1; -- should fail, required arguments @a and @d not supplied +GO + +EXEC babel_2877_vu_prepare_proc1 10; -- should fail, required argument @d not supplied +GO + +EXEC babel_2877_vu_prepare_proc1 @d=40; -- should fail, required argument @a not supplied +GO + +EXEC babel_2877_vu_prepare_proc1 @a = 10, @d = 1.8; +GO + +EXEC babel_2877_vu_prepare_proc1 @a = 10, @b = 20, @c = 30, @d = 40; +GO + +EXEC babel_2877_vu_prepare_proc2; +GO + +EXEC babel_2877_vu_prepare_proc2 @d = 1.5; +GO + +EXEC babel_2877_vu_prepare_proc3; -- should fail, all parameters are required +GO + +EXEC babel_2877_vu_prepare_proc3 10, 'def', $10, 1.8; -- should fail, all parameters are required +GO + +-- babelfish_function_ext table should have entry for all the above functions and procedures +SELECT nspname, + funcname, + funcsignature, + default_positions +FROM sys.babelfish_function_ext + WHERE funcname LIKE 'babel_2877_vu_prepare%' + AND funcname NOT LIKE '%ansi%' ORDER BY funcname; +GO + +SELECT orig_name, + CASE flag_validity & 1 + WHEN 0 + THEN NULL + ELSE + CASE flag_values & 1 + WHEN 0 + THEN 0 + ELSE 1 + END + END AS ansi_null, + CASE flag_validity & 2 + WHEN 0 + THEN NULL + ELSE + CASE flag_values & 2 + WHEN 0 + THEN 0 + ELSE 1 + END + END AS quoted_identifier +FROM sys.babelfish_function_ext WHERE funcname LIKE 'babel-2877-vu-prepare%' ORDER BY funcname; +GO diff --git a/test/JDBC/upgrade/latest/verification_cleanup/15_2/Test-sp_babelfish_volatility-vu-cleanup.sql b/test/JDBC/upgrade/latest/verification_cleanup/15_2/Test-sp_babelfish_volatility-vu-cleanup.sql new file mode 100644 index 0000000000..80a368ffa7 --- /dev/null +++ b/test/JDBC/upgrade/latest/verification_cleanup/15_2/Test-sp_babelfish_volatility-vu-cleanup.sql @@ -0,0 +1,65 @@ +drop function test_sp_babelfish_volatility_f1 +go + +drop function test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1 +go + +drop schema test_sp_babelfish_volatility_schema1 +go + +drop function [test_sp_babelfish_volatility_schema1 with .dot and spaces].test_sp_babelfish_volatility_f1 +go + +drop schema [test_sp_babelfish_volatility_schema1 with .dot and spaces] +go + +use test_sp_babelfish_volatility_db1 +go + +drop function test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1 +go + +drop function test_sp_babelfish_volatility_f2 +go + +drop function test_sp_babelfish_volatility_duplicate() +go + +drop function test_sp_babelfish_volatility_duplicate(@b int) +go + +drop schema test_sp_babelfish_volatility_schema2 +go + +drop function test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa; +go + +drop function test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa; +go + +drop schema test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa; +go + +drop user test_sp_babelfish_volatility_user +go + +drop login test_sp_babelfish_volatility_login_2 +go + +use master +go + +drop database test_sp_babelfish_volatility_db1 +go + +drop login test_sp_babelfish_volatility_login +go + +drop table test_bbf_vol_t1 +go + +drop function test_bbf_vol_f1 +go + +drop function [test_bbf_vol_f1;drop table test_bbf_vol_t1;] +go diff --git a/test/JDBC/upgrade/latest/verification_cleanup/15_2/Test-sp_babelfish_volatility-vu-verify.mix b/test/JDBC/upgrade/latest/verification_cleanup/15_2/Test-sp_babelfish_volatility-vu-verify.mix new file mode 100644 index 0000000000..3f453cf070 --- /dev/null +++ b/test/JDBC/upgrade/latest/verification_cleanup/15_2/Test-sp_babelfish_volatility-vu-verify.mix @@ -0,0 +1,314 @@ +-- tsql +/* test without schema name */ +use master +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'stable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'volatile' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'random' +go +exec sys.sp_babelfish_volatility '.test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'stable' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'volatile' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'random' +go +sp_babelfish_volatility '.test_sp_babelfish_volatility_f1' +go + +/* test with schema name */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility '"test_sp_babelfish_volatility_schema1".test_sp_babelfish_volatility_f1', 'stable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1].test_sp_babelfish_volatility_f1', 'volatile' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'random' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'immutable' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility '"test_sp_babelfish_volatility_schema1".test_sp_babelfish_volatility_f1', 'stable' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1].test_sp_babelfish_volatility_f1', 'volatile' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1', 'random' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go + +/* testing for trailing spaces */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1 ', 'stable ' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go + +/* testing for leading space should give error */ +exec sys.sp_babelfish_volatility ' test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', ' immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go + +/* testing for some invalid cases */ +exec sys.sp_babelfish_volatility 'master.test_sp_babelfish_volatility_schema1.test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'random_function' +go +exec sys.sp_babelfish_volatility '','immutable' +go +exec sys.sp_babelfish_volatility '' +go +exec sys.sp_babelfish_volatility NULL, 'stable' +go +exec sys.sp_babelfish_volatility '. test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema1.' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_name_for_a_very_long_function_name_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_name_for_a_very_long_function_name_more_longer_longer_than_4000_characters_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' +go + +/* testing for injection */ +exec sys.sp_babelfish_volatility 'ran;dom' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable; some random text' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'rand;om' +go +/* testing injection in function name */ +exec sys.sp_babelfish_volatility 'test_bbf_vol_f1' +go +exec sys.sp_babelfish_volatility '[test_bbf_vol_f1;drop table test_bbf_vol_t1;]' +go +exec sys.sp_babelfish_volatility '[test_bbf_vol_f1;drop table test_bbf_vol_t1;]', 'immutable' +go +exec sys.sp_babelfish_volatility '[test_bbf_vol_f1;drop table test_bbf_vol_t1;]' +go +exec sys.sp_babelfish_volatility 'test_bbf_vol_f1' +go +select * from test_bbf_vol_t1 +go + +/* testing for case insensitive */ +exec sys.sp_babelfish_volatility 'TesT_SP_babelfish_Volatility_f1', 'VolatILe' +go +exec sys.sp_babelfish_volatility 'TesT_Sp_babelfish_Volatility_F1' +go + +/* testing with dot and spaces in schema name */ +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1 with .dot and spaces].test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema1 with .dot and spaces]."test_sp_babelfish_volatility_f1"' +go + +/* test in a database */ +use test_sp_babelfish_volatility_db1 +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' +go +/* test with duplicate function name */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_duplicate' +go +/* test with long names */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa', 'immutable' +go +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa]' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa.test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa', 'immutable' +go +exec sys.sp_babelfish_volatility '[test_sp_babelfish_volatility_schema_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaaaa].[test_sp_babelfish_volatility_function_very_long_with_length_greater_than_63_but_less_equal_than_128_random_text_aaaaaaaaaaaaaaaa]' +go +/* test with trucated names */ +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7', 'volatile' +go +exec sys.sp_babelfish_volatility '"test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7"' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_scc62ee1eb13f7c4857c426f2affcc9a16.test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_scc62ee1eb13f7c4857c426f2affcc9a16.test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7', 'volatile' +go +exec sys.sp_babelfish_volatility '"test_sp_babelfish_volatility_scc62ee1eb13f7c4857c426f2affcc9a16".[test_sp_babelfish_volatility_fu563bc8b23212e981e53906bdf6df41d7]' +go +exec sys.sp_babelfish_volatility +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2', 'immutable' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go + +/* function on which user has privilege is only visible */ +-- tsql user=test_sp_babelfish_volatility_login password=12345678 +use test_sp_babelfish_volatility_db1 +go +select current_user +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'dbo.test_sp_babelfish_volatility_f2' +go +exec sys.sp_babelfish_volatility +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'dbo.test_sp_babelfish_volatility_f2' +go +sp_babelfish_volatility +go + +/* grant access to current user */ +-- tsql +use test_sp_babelfish_volatility_db1 +go +grant execute on test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1 to test_sp_babelfish_volatility_user +go +grant execute on test_sp_babelfish_volatility_f2 to test_sp_babelfish_volatility_user +go + +-- tsql user=test_sp_babelfish_volatility_login password=12345678 +use test_sp_babelfish_volatility_db1 +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +exec sys.sp_babelfish_volatility +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +sp_babelfish_volatility +go + +/* test for default schema */ +-- tsql +use test_sp_babelfish_volatility_db1 +go +ALTER USER test_sp_babelfish_volatility_user WITH DEFAULT_SCHEMA=test_sp_babelfish_volatility_schema2 +GO + +-- tsql user=test_sp_babelfish_volatility_login password=12345678 +use test_sp_babelfish_volatility_db1 +go +select current_user +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f1 ' +go +exec sys.sp_babelfish_volatility 'test_sp_babelfish_volatility_f2' +go +exec sys.sp_babelfish_volatility 'dbo.test_sp_babelfish_volatility_f2' +go +exec sys.sp_babelfish_volatility +go + +/* revoke the priviledges to the user */ +-- tsql +use test_sp_babelfish_volatility_db1 +go +revoke execute on test_sp_babelfish_volatility_schema2.test_sp_babelfish_volatility_f1 from test_sp_babelfish_volatility_user +go +revoke execute on test_sp_babelfish_volatility_f2 from test_sp_babelfish_volatility_user +go + +/* test default schema in guest user */ +-- tsql +use test_sp_babelfish_volatility_db1 +go +grant connect to guest +go + +-- tsql user=test_sp_babelfish_volatility_login_2 password=12345678 +use test_sp_babelfish_volatility_db1 +go +SELECT current_user +go +create function test_sp_babelfish_volatility_f1() returns int begin declare @a int; set @a = 1; return @a; end +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1', 'immutable'; +go +sp_babelfish_volatility 'test_sp_babelfish_volatility_f1' +go +sp_babelfish_volatility 'dbo.test_sp_babelfish_volatility_f2' +go +sp_babelfish_volatility +go +drop function test_sp_babelfish_volatility_f1 +go + +-- tsql +use test_sp_babelfish_volatility_db1 +go +revoke connect from guest +go + +-- psql +-- Need to terminate active session before cleaning up the login +SELECT pg_terminate_backend(pid) FROM pg_stat_get_activity(NULL) +WHERE sys.suser_name(usesysid) = 'test_sp_babelfish_volatility_user' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +GO +-- Wait to sync with another session +SELECT pg_sleep(1); +GO From de5292edbe8a34858ff7d4655e3cdc170c2bc758 Mon Sep 17 00:00:00 2001 From: Satarupa Biswas Date: Fri, 24 Mar 2023 22:58:25 +0530 Subject: [PATCH 029/363] Fixing existing expected file due to changes added as part of BABEL-1625 (#1364) Postgres outputs datetimeoffset data by removing/subtracting input timezone value from it. Datetimeoffset change in PR #1340 works on the engine output to include timezone and thereby retain the input timestamp as is. In this PR, we have fixed errors in existing expected file generated due to changes added to BABEL-1625. Task: BABEL-1625 Signed-off-by: Satarupa Biswas satarupb@amazon.com --- contrib/babelfishpg_tsql/expected/test/babel_function.out | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/babelfishpg_tsql/expected/test/babel_function.out b/contrib/babelfishpg_tsql/expected/test/babel_function.out index ab040f76fe..06c14c9fd3 100644 --- a/contrib/babelfishpg_tsql/expected/test/babel_function.out +++ b/contrib/babelfishpg_tsql/expected/test/babel_function.out @@ -1590,7 +1590,7 @@ select dateadd(quarter, 3, '2037-03-01'::date); select dateadd(minute, 70, '2016-12-26 23:30:05.523456+8'::datetimeoffset); dateadd ---------------------------------------- - Mon Dec 26 16:40:05.523456 2016 +08:00 + Tue Dec 27 00:40:05.523456 2016 +08:00 (1 row) select dateadd(month, 2, '2016-12-26 23:30:05.523456'::datetime2); @@ -1627,7 +1627,7 @@ select dateadd(hour, -2, '01:12:34.876543'::time); select dateadd(minute, -70, '2016-12-26 00:30:05.523456+8'::datetimeoffset); dateadd ---------------------------------------- - Sun Dec 25 15:20:05.523456 2016 +08:00 + Sun Dec 25 23:20:05.523456 2016 +08:00 (1 row) select dateadd(second, -56, '2016-12-26 00:00:55'::smalldatetime); From 289af2a475a6e61048540c52ff1c3fc52038e7ea Mon Sep 17 00:00:00 2001 From: Ashish Prasad <56514722+hash-16@users.noreply.github.com> Date: Mon, 27 Mar 2023 13:57:22 +0530 Subject: [PATCH 030/363] Changes to support DDL Export Test Framework (#1326) Adding support for DDL test framework into python framework. We in the framework are comparing the generated exported DDL export from the BBF and to the expected exported DDL from the sql server instance. Issues Resolved [BABEL-3969] Signed-off-by: Ashish Prasad pashisht@amazon.com --- .github/workflows/python-tests.yml | 4 + test/python/SMO_script.ps1 | 36 +++ test/python/batch_run.py | 44 +++- test/python/config.txt | 2 + test/python/execute_query.py | 15 ++ test/python/expected/pyodbc/ddl_func_proc.out | 207 ++++++++++++++++ .../expected/pyodbc/ddl_tables_index.out | 194 +++++++++++++++ test/python/expected/pyodbc/ddl_triggers.out | 75 ++++++ test/python/expected/pyodbc/ddl_views.out | 31 +++ test/python/input/ddl_func_proc.sql | 232 ++++++++++++++++++ test/python/input/ddl_tables_index.sql | 94 +++++++ test/python/input/ddl_triggers.sql | 58 +++++ test/python/input/ddl_views.sql | 32 +++ test/python/test_main.py | 2 + 14 files changed, 1023 insertions(+), 3 deletions(-) create mode 100644 test/python/SMO_script.ps1 create mode 100644 test/python/expected/pyodbc/ddl_func_proc.out create mode 100644 test/python/expected/pyodbc/ddl_tables_index.out create mode 100644 test/python/expected/pyodbc/ddl_triggers.out create mode 100644 test/python/expected/pyodbc/ddl_views.out create mode 100644 test/python/input/ddl_func_proc.sql create mode 100644 test/python/input/ddl_tables_index.sql create mode 100644 test/python/input/ddl_triggers.sql create mode 100644 test/python/input/ddl_views.sql diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml index 48ece5ef09..2cbb0f8680 100644 --- a/.github/workflows/python-tests.yml +++ b/.github/workflows/python-tests.yml @@ -47,6 +47,10 @@ jobs: cd ~ curl https://packages.microsoft.com/config/ubuntu/20.04/prod.list | sudo tee /etc/apt/sources.list.d/mssql-release.list cd ~/work/babelfish_extensions/babelfish_extensions/test/python + mkdir sqltoolsservice + cd sqltoolsservice + wget https://github.com/microsoft/sqltoolsservice/releases/download/4.4.0.12/Microsoft.SqlTools.ServiceLayer-rhel-x64-net6.0.tar.gz && tar -xzvf Microsoft.SqlTools.ServiceLayer-rhel-x64-net6.0.tar.gz + cd ../ sudo ACCEPT_EULA=Y apt-get install -y msodbcsql17 python3-dev pip3 install pyodbc==4.0.35 pymssql pytest pytest-xdist diff --git a/test/python/SMO_script.ps1 b/test/python/SMO_script.ps1 new file mode 100644 index 0000000000..46f66a30d5 --- /dev/null +++ b/test/python/SMO_script.ps1 @@ -0,0 +1,36 @@ +$argss = $args[0] +$paramsArray =$argss.Split("?") + +$Assem = (“Microsoft.SqlServer.Management.Sdk.Sfcâ€, +“Microsoft.SqlServer.Smoâ€, +“Microsoft.SqlServer.ConnectionInfoâ€, +“Microsoft.SqlServer.SqlEnumâ€); + +Add-Type -AssemblyName $Assem + +$SmoServer = New-Object ('Microsoft.SqlServer.Management.Smo.Server') -argumentlist $paramsArray[0] +$SmoServer.ConnectionContext.LoginSecure = $false +$SmoServer.ConnectionContext.set_Login($paramsArray[3]) +$SmoServer.ConnectionContext.set_Password($paramsArray[4]) +$db = $SmoServer.Databases[$paramsArray[2]] + +$Objects = $db.Tables +$Objects += $db.Views +$Objects += $db.StoredProcedures +$Objects += $db.UserDefinedFunctions +$Objects += $db.Tables.Indexes +$Objects += $db.Tables.Triggers + +foreach ($CurrentObject in $Objects) +{ + if (-not $CurrentObject.IsSystemObject ) + { + $Scripter = New-Object ('Microsoft.SqlServer.Management.Smo.Scripter') ($SmoServer) + $Scripter.Options.DriAll = $True; + $Scripter.Options.ScriptSchema = $True; + $Scripter.Options.ScriptData = $False; + $Scripter.Options.NoCollation = $True; + $Scripter.Script($CurrentObject); + Write-Output "GO`n" + } +} \ No newline at end of file diff --git a/test/python/batch_run.py b/test/python/batch_run.py index 98f36173db..e42e825b31 100644 --- a/test/python/batch_run.py +++ b/test/python/batch_run.py @@ -1,10 +1,12 @@ from utils.config import config_dict as cfg -from execute_query import parse_prepared_statement, parse_stored_procedures, process_transaction_statement,process_statement_in_file_mode +from execute_query import parse_prepared_statement, parse_stored_procedures, process_transaction_statement,process_statement_in_file_mode,process_statement_in_file_mode_ddl from python_authentication import py_authentication if cfg['runIsolationTests'] == 'true': from isolationtest.isolationTestHandler import isolationTestHandler import os - +from compare_results import handle_exception_in_file +from pathlib import Path +import subprocess #categorise statements based on prefixes and accordingly process them def batch_run(bbl_cnxn, file_handler, file, logger): @@ -14,8 +16,44 @@ def batch_run(bbl_cnxn, file_handler, file, logger): filename = file.name f_type = filename.split(".")[1] + if filename.split(".")[0][:4] == 'ddl_' and cfg['ddlExport'] == 'true': + with open(file, "r") as f: + sqlbatch = "" + + line = f.readline() + while line: + line = line.replace("\n", "") + #ignore empty lines + if len(line) < 1: + line = f.readline() + continue + else: + if line == "--DROP": + dest = Path.cwd().joinpath("output",cfg["driver"], filename.split(".")[0] + ".out") + f_obj = open(dest, 'a') + work_dir = Path.cwd().joinpath("sqltoolsservice") + script_path = Path.cwd().joinpath("SMO_script.ps1") + params="?".join([cfg["fileGenerator_URL"],cfg["fileGenerator_port"],cfg["fileGenerator_databaseName"],cfg["fileGenerator_user"],cfg["fileGenerator_password"]]) + args = [] + args.append("pwsh -WorkingDirectory {} -File {} {}".format(work_dir,script_path,params)) + p=subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,shell=True,text=True) + p_out, p_err = p.communicate() + f_obj.write(p_out) + + elif line.lower() == "go" or line.lower() == "go;": + flag = True + flag = process_statement_in_file_mode_ddl(bbl_cnxn, file_handler, sqlbatch) + if flag: + passed += 1 + else: + failed += 1 + + sqlbatch = "" + else: + sqlbatch += line + os.linesep + line = f.readline() - if f_type == "sql": + elif f_type == "sql": with open(file, "r") as f: sqlbatch = "" diff --git a/test/python/config.txt b/test/python/config.txt index d1f1815513..7017ce74e4 100644 --- a/test/python/config.txt +++ b/test/python/config.txt @@ -38,6 +38,8 @@ outputErrorCode = true ############################ ALLOW TO RUN ISOLATION TESTS (IF TRUE THEN RUNS ALL THE .SPEC FILES FROM INPUT DIRECTORY OTHERWISE SKIP THEM) ################################################## runIsolationTests = false +############################ ALLOW TO RUN DDL EXPORT TESTS (IF TRUE THEN RUNS ALL THE .SQL FILES WITH PREFIX ddl_ FROM INPUT DIRECTORY OTHERWISE SKIP THEM) ################################################## +ddlExport = true ############################ MAX TIME LIMIT FOR SINGLE STEP QUERY EXECUTION IN SECONDS(FOR ISOLATION TESTS ONLY) ############################ stepTimeLimit = 30 diff --git a/test/python/execute_query.py b/test/python/execute_query.py index 76c0d8eba4..3f4bf57b37 100644 --- a/test/python/execute_query.py +++ b/test/python/execute_query.py @@ -308,6 +308,21 @@ def process_statement_in_file_mode(bbl_cnxn, file_writer, query, is_sql_batch): return True +def process_statement_in_file_mode_ddl(bbl_cnxn, file_writer, query): + try: + bbl_cursor = bbl_cnxn.get_cursor() + bbl_cursor.execute(query) + result_set_exist = bbl_cursor.description + except Exception as e: + handle_exception_in_file(e, file_writer) + + try: + bbl_cursor.close() + except Exception as e: + print(str(e)) + + return True + #function to generate output files for prepared statements def process_prepared_statement_in_file_mode(bbl_cnxn, file_writer, query, prep_statement, result, logger): try: diff --git a/test/python/expected/pyodbc/ddl_func_proc.out b/test/python/expected/pyodbc/ddl_func_proc.out new file mode 100644 index 0000000000..f6a352794a --- /dev/null +++ b/test/python/expected/pyodbc/ddl_func_proc.out @@ -0,0 +1,207 @@ +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE TABLE [dbo].[routines_customers]( + [customer_id] [int] NOT NULL, + [customer_name] [char](50) NOT NULL, + [address] [char](50) NULL, + [city] [char](50) NULL, + [state] [char](25) NULL, + [zip_code] [char](10) NULL, + CONSTRAINT [customers_pkroutines_customers248e85dd01b015e3396e8567c240879b] PRIMARY KEY NONCLUSTERED +( + [customer_id] +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +) ON [PRIMARY] + +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +create procedure routines_test_b1 +AS +BEGIN + select * from customers; + select * from customers where customer_id = 25; + select count(state) from customers; +END; +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +create procedure routines_test_b2(@test_b2_name char(255), @test_b2_city char(255), @test_b2_id int, @test_b2_address char(255), @test_b2_state char(255), @test_b2_cust_id int) +AS +BEGIN + INSERT INTO customers (customer_name,address,city,state,customer_id) VALUES (@test_b2_name,@test_b2_address,@test_b2_city,@test_b2_state,@test_b2_cust_id); + DELETE from customers where customer_id = @test_b2_id; + ALTER TABLE customers ADD email varchar(255); +END; +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +create procedure routines_test_b3 @test_b3_paramout varchar(20) out +AS +BEGIN +SELECT @test_b3_paramout ='helloworld'; +END; +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +create procedure routines_test_b4(@test_b4_a int, @test_b4_b char(255), @test_b4_c char(255), @test_b4_d char(255)) +AS +SET @test_b4_a=10; SET Nocount ON; +DECLARE @test_b4_temp int =12; +BEGIN + INSERT INTO customers (customer_name,address,city,customer_id) VALUES (@test_b4_b,@test_b4_c,@test_b4_d,@test_b4_a); +END; +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE PROCEDURE routines_test_def(@test_def_a int = 2, @test_def_b char(255) OUTPUT, @test_def_c varchar(20) = 'abc', @test_def_d varbinary(8)) +AS +BEGIN + SET @test_def_b = 'a'; + SELECT @test_def_a, @test_def_b, @test_def_c, @test_def_d; +END; +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +create procedure routines_test_nvar(@test_nvar_a nvarchar , @test_nvar_b int = 8) +AS +BEGIN + SELECT @test_nvar_b=8; +END +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +create procedure routines_test_t (@test_t_a int) +AS +BEGIN + begin try + begin transaction + update Empl set Name ="Arman" where id =99; + update Empl set Name ="Anand" where id =100; + commit transaction + print 'transaction committed' + END try + BEGIN catch + rollback transaction + print 'rollback' + end catch +END; +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +create procedure routines_test_uid(@test_uid_a uniqueidentifier output) +AS +BEGIN + set @test_uid_a ='ce8af10a-2709-43b0-9e4e-a02753929d17'; + SELECT @test_uid_a as test_uid_a; +END; +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +create function routines_fc1(@fc1_a nvarchar) RETURNS nvarchar AS BEGIN return @fc1_a END; +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +create function routines_fc2(@fc2_a varchar) RETURNS varchar AS BEGIN return @fc2_a END; +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +create function routines_fc3(@fc3_a nchar) RETURNS nchar AS BEGIN return @fc3_a END; +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +create function routines_fc4(@fc4_a binary, @fc4_b tinyint, @fc4_c BIGINT, @fc4_d float) RETURNS binary AS BEGIN return @fc4_a END; +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +create function routines_fc5(@fc5_a varbinary) RETURNS varbinary AS BEGIN return @fc5_a END; +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +create function routines_fc6(@fc6_a char) RETURNS char AS BEGIN return @fc6_a END; +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE FUNCTION routines_fc7() +RETURNS @myRetTable table (a int PRIMARY KEY) +AS +BEGIN +INSERT INTO @myRetTable VALUES (1) +RETURN +END; +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +create function routines_func_nvar (@func_nvar_a nvarchar(23)) returns nvarchar(23) AS BEGIN return @func_nvar_a END; +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +create function routines_test_b6( + @test_b6_a INT, + @test_b6_b DEC(10,2), + @test_b6_c DEC(4,2) +) +RETURNS DEC(10,2) +AS +BEGIN + RETURN @test_b6_a * @test_b6_b * (1 - @test_b6_c); +END; +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +create function routines_test_con(@test_con_a int) +RETURNS INT + WITH CALLED ON NULL INPUT +AS +BEGIN +RETURN @test_con_a; +END; +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE FUNCTION routines_test_func_opt (@test_func_opt_name varchar(10)) +RETURNS INT + WITH RETURNS NULL ON NULL INPUT +AS +BEGIN + RETURN 2; +END; +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +create function routines_test_s (@test_s_a char(45)) RETURNS char(45) +WITH SCHEMABINDING +AS +BEGIN + RETURN @test_s_a; +END; +GO + +ALTER TABLE [dbo].[routines_customers] ADD CONSTRAINT [customers_pkroutines_customers248e85dd01b015e3396e8567c240879b] PRIMARY KEY NONCLUSTERED +( + [customer_id] +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +GO + +GO + diff --git a/test/python/expected/pyodbc/ddl_tables_index.out b/test/python/expected/pyodbc/ddl_tables_index.out new file mode 100644 index 0000000000..e3756f7087 --- /dev/null +++ b/test/python/expected/pyodbc/ddl_tables_index.out @@ -0,0 +1,194 @@ +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE TABLE [dbo].[isc_check_constraints_t1]( + [a] [varchar](1) NULL +) ON [PRIMARY] + +ALTER TABLE [dbo].[isc_check_constraints_t1] WITH CHECK ADD CONSTRAINT [isc_check_constraints_t1_a_check] CHECK (((a = 'provvwstdjtlyzygsx'))) +ALTER TABLE [dbo].[isc_check_constraints_t1] CHECK CONSTRAINT [isc_check_constraints_t1_a_check] +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE TABLE [dbo].[table_check]( + [id] [int] NOT NULL, + [name] [varchar](10) NOT NULL, + [age] [int] NOT NULL +) ON [PRIMARY] + +ALTER TABLE [dbo].[table_check] WITH CHECK ADD CONSTRAINT [table_check_age_check] CHECK (((age >= 18))) +ALTER TABLE [dbo].[table_check] CHECK CONSTRAINT [table_check_age_check] +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE TABLE [dbo].[table_foreign]( + [aa] [int] NOT NULL, + [bb] [int] NOT NULL, + [a] [int] NULL, + CONSTRAINT [table_foreign_pkey] PRIMARY KEY NONCLUSTERED +( + [aa] +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +) ON [PRIMARY] + +ALTER TABLE [dbo].[table_foreign] WITH CHECK ADD FOREIGN KEY([a]) +REFERENCES [dbo].[table_primary] ([a]) +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE TABLE [dbo].[table_primary]( + [a] [int] NOT NULL, + [b] [int] NOT NULL, + [c] [int] NULL, + CONSTRAINT [table_primary_pkey] PRIMARY KEY NONCLUSTERED +( + [a] +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +) ON [PRIMARY] + +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE TABLE [dbo].[table_unique]( + [a] [int] NOT NULL, + [b] [int] NOT NULL, + [c] [int] NULL, + CONSTRAINT [table_unique_a_key] UNIQUE NONCLUSTERED +( + [a] +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +) ON [PRIMARY] + +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE TABLE [dbo].[test_datetime]( + [c_time] [time](6) NULL, + [c_date] [date] NULL, + [c_datetime] [datetime] NULL, + [c_datetime2] [datetime2](6) NULL, + [c_datetimeoffset] [datetimeoffset](6) NULL, + [c_smalldatetime] [smalldatetime] NULL +) ON [PRIMARY] + +ALTER TABLE [dbo].[test_datetime] WITH CHECK ADD CONSTRAINT [test_datetime_c_date_check] CHECK (((c_date < '2001-01-01'))) +ALTER TABLE [dbo].[test_datetime] CHECK CONSTRAINT [test_datetime_c_date_check] +ALTER TABLE [dbo].[test_datetime] WITH CHECK ADD CONSTRAINT [test_datetime_c_datetime_check] CHECK (((c_datetime < '2020-10-20 09:00:00'))) +ALTER TABLE [dbo].[test_datetime] CHECK CONSTRAINT [test_datetime_c_datetime_check] +ALTER TABLE [dbo].[test_datetime] WITH CHECK ADD CONSTRAINT [test_datetime_c_datetime2_check] CHECK ((((c_datetime2 < '2020-10-20 09:00:00') AND (c_datetime2 < CAST('2020-10-20 09:00:00' AS datetime2(6)))))) +ALTER TABLE [dbo].[test_datetime] CHECK CONSTRAINT [test_datetime_c_datetime2_check] +ALTER TABLE [dbo].[test_datetime] WITH CHECK ADD CONSTRAINT [test_datetime_c_datetimeoffset_check] CHECK ((((c_datetimeoffset < '2025-12-10 12:32:10 +01:00') AND (c_datetimeoffset < CAST('2025-12-10 12:32:10 +01:00' AS datetimeoffset(4)))))) +ALTER TABLE [dbo].[test_datetime] CHECK CONSTRAINT [test_datetime_c_datetimeoffset_check] +ALTER TABLE [dbo].[test_datetime] WITH CHECK ADD CONSTRAINT [test_datetime_c_smalldatetime_check] CHECK (((c_smalldatetime < '2007-05-08 12:35:00'))) +ALTER TABLE [dbo].[test_datetime] CHECK CONSTRAINT [test_datetime_c_smalldatetime_check] +ALTER TABLE [dbo].[test_datetime] WITH CHECK ADD CONSTRAINT [test_datetime_c_time_check] CHECK ((((c_time < '09:00:00') AND (c_time < CAST('09:00:00' AS time(6)))))) +ALTER TABLE [dbo].[test_datetime] CHECK CONSTRAINT [test_datetime_c_time_check] +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE TABLE [dbo].[test_null]( + [a] [int] NULL, + [b] [int] NULL +) ON [PRIMARY] + +ALTER TABLE [dbo].[test_null] WITH CHECK ADD CONSTRAINT [constraint1test_null987b8e55c77de33d095778885ecd84f4] CHECK (((a > 10))) +ALTER TABLE [dbo].[test_null] CHECK CONSTRAINT [constraint1test_null987b8e55c77de33d095778885ecd84f4] +ALTER TABLE [dbo].[test_null] WITH CHECK ADD CONSTRAINT [test_null_a_check] CHECK (((a IS NOT NULL))) +ALTER TABLE [dbo].[test_null] CHECK CONSTRAINT [test_null_a_check] +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE TABLE [dbo].[test_tsql_collate]( + [c_varchar] [varchar](1) NULL, + [c_char] [char](1) NULL, + [c_nchar] [nchar](1) NULL +) ON [PRIMARY] + +ALTER TABLE [dbo].[test_tsql_collate] WITH CHECK ADD CONSTRAINT [test_tsql_collate_c_char_check] CHECK (((c_char <> (CAST('sflkjasdlkfjf' AS char(7)) COLLATE japanese_ci_as)))) +ALTER TABLE [dbo].[test_tsql_collate] CHECK CONSTRAINT [test_tsql_collate_c_char_check] +ALTER TABLE [dbo].[test_tsql_collate] WITH CHECK ADD CONSTRAINT [test_tsql_collate_c_nchar_check] CHECK (((CAST((c_nchar) AS nchar(7)) <> (CAST(('sflkjasdlkfjf') AS nchar(7)) COLLATE latin1_general_ci_as)))) +ALTER TABLE [dbo].[test_tsql_collate] CHECK CONSTRAINT [test_tsql_collate_c_nchar_check] +ALTER TABLE [dbo].[test_tsql_collate] WITH CHECK ADD CONSTRAINT [test_tsql_collate_c_varchar_check] CHECK (((c_varchar <> (CAST('sflkjasdlkfjf' AS varchar(12)) COLLATE latin1_general_ci_as)))) +ALTER TABLE [dbo].[test_tsql_collate] CHECK CONSTRAINT [test_tsql_collate_c_varchar_check] +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE TABLE [dbo].[test_tsql_const]( + [c_int] [int] NOT NULL, + [c_bit] [bit] NULL, + [c_smallint] [smallint] NULL, + [c_binary] [binary](8) NULL, + [c_varbinary] [varbinary](8) NULL, + CONSTRAINT [test_tsql_const_pkey] PRIMARY KEY NONCLUSTERED +( + [c_int] +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +) ON [PRIMARY] + +ALTER TABLE [dbo].[test_tsql_const] WITH CHECK ADD CONSTRAINT [test_tsql_const_c_binary_check] CHECK (((c_binary > CAST(('0xfe') AS binary(8))))) +ALTER TABLE [dbo].[test_tsql_const] CHECK CONSTRAINT [test_tsql_const_c_binary_check] +ALTER TABLE [dbo].[test_tsql_const] WITH CHECK ADD CONSTRAINT [test_tsql_const_c_bit_check] CHECK (((c_bit <> CAST((1) AS bit)))) +ALTER TABLE [dbo].[test_tsql_const] CHECK CONSTRAINT [test_tsql_const_c_bit_check] +ALTER TABLE [dbo].[test_tsql_const] WITH CHECK ADD CONSTRAINT [test_tsql_const_c_int_check] CHECK (((c_int < 10))) +ALTER TABLE [dbo].[test_tsql_const] CHECK CONSTRAINT [test_tsql_const_c_int_check] +ALTER TABLE [dbo].[test_tsql_const] WITH CHECK ADD CONSTRAINT [test_tsql_const_c_smallint_check] CHECK (((c_smallint < CAST((CAST(('20') AS sql_variant)) AS smallint)))) +ALTER TABLE [dbo].[test_tsql_const] CHECK CONSTRAINT [test_tsql_const_c_smallint_check] +ALTER TABLE [dbo].[test_tsql_const] WITH CHECK ADD CONSTRAINT [test_tsql_const_c_varbinary_check] CHECK (((c_varbinary > CAST('0xfe' AS varbinary(8))))) +ALTER TABLE [dbo].[test_tsql_const] CHECK CONSTRAINT [test_tsql_const_c_varbinary_check] +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE TABLE [dbo].[test_upper]( + [a] [char](1) NULL +) ON [PRIMARY] + +ALTER TABLE [dbo].[test_upper] WITH CHECK ADD CONSTRAINT [test_upper_a_check] CHECK (((upper(a) IN ('A', 'B')))) +ALTER TABLE [dbo].[test_upper] CHECK CONSTRAINT [test_upper_a_check] +GO + +ALTER TABLE [dbo].[table_foreign] ADD CONSTRAINT [table_foreign_pkey] PRIMARY KEY NONCLUSTERED +( + [aa] +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +GO + +ALTER TABLE [dbo].[table_primary] ADD CONSTRAINT [table_primary_pkey] PRIMARY KEY NONCLUSTERED +( + [a] +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +GO + +ALTER TABLE [dbo].[table_unique] ADD CONSTRAINT [table_unique_a_key] UNIQUE NONCLUSTERED +( + [a] +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +GO + +CREATE NONCLUSTERED INDEX [test_comp_indextable_unique54256857b8bed086a06f91b550a3a65b] ON [dbo].[table_unique] +( + [a] +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +GO + +ALTER TABLE [dbo].[test_tsql_const] ADD CONSTRAINT [test_tsql_const_pkey] PRIMARY KEY NONCLUSTERED +( + [c_int] +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +GO + +CREATE NONCLUSTERED INDEX [test_indextest_upper8e0335bba8a0f780c0c12b75ae201ead] ON [dbo].[test_upper] +( + [a] +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +GO + +GO + diff --git a/test/python/expected/pyodbc/ddl_triggers.out b/test/python/expected/pyodbc/ddl_triggers.out new file mode 100644 index 0000000000..034cae9ca5 --- /dev/null +++ b/test/python/expected/pyodbc/ddl_triggers.out @@ -0,0 +1,75 @@ +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE TABLE [dbo].[babel_1654_vu_prepare_employeedata]( + [id] [int] IDENTITY(1,1) NOT NULL, + [id] [int] IDENTITY(1,1) NOT NULL, + [emp_first_name] [varchar](50) NULL, + [emp_last_name] [varchar](50) NULL, + [emp_salary] [int] NULL, + [a] [varchar](50) NULL, + [b] [varchar](50) NULL, + [c] [varchar](50) NULL, + [d] [varchar](50) NULL, + [e] [varchar](50) NULL, + [f] [varchar](50) NULL, + CONSTRAINT [babel_1654_vu_prepare_employeedata_pkey] PRIMARY KEY NONCLUSTERED +( + [id] +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +) ON [PRIMARY] + +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE TABLE [dbo].[babel_1654_vu_prepare_t]( + [id] [int] IDENTITY(1,1) NOT NULL, + [id] [int] IDENTITY(1,1) NOT NULL, + [a] [varchar](50) NULL, + [b] [varchar](50) NULL, + CONSTRAINT [babel_1654_vu_prepare_t_pkey] PRIMARY KEY NONCLUSTERED +( + [id] +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +) ON [PRIMARY] + +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE TABLE [dbo].[sys_computed_columns_vu_prepare_t1]( + [scc_first_number] [smallint] NULL, + [scc_second_number] [money] NULL, + [scc_multiplied] AS (scc_first_number * scc_second_number) +) ON [PRIMARY] + +GO + +ALTER TABLE [dbo].[babel_1654_vu_prepare_employeedata] ADD CONSTRAINT [babel_1654_vu_prepare_employeedata_pkey] PRIMARY KEY NONCLUSTERED +( + [id] +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +GO + +ALTER TABLE [dbo].[babel_1654_vu_prepare_t] ADD CONSTRAINT [babel_1654_vu_prepare_t_pkey] PRIMARY KEY NONCLUSTERED +( + [id] +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE TRIGGER [dbo].[babel_1654_vu_prepare_updemployeedatas] ON [dbo].[babel_1654_vu_prepare_employeedata] AFTER UPDATE,INSERT AS + select COLUMNS_UPDATED(); + update babel_1654_vu_prepare_t set a = 'sss' , b = 'sss' where id = 1; + select COLUMNS_UPDATED(); +ALTER TABLE [dbo].[babel_1654_vu_prepare_employeedata] ENABLE TRIGGER [babel_1654_vu_prepare_updemployeedatas] +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE TRIGGER babel_1654_vu_prepare_trig_t on babel_1654_vu_prepare_t after update as + select COLUMNS_UPDATED(); +ALTER TABLE [dbo].[babel_1654_vu_prepare_t] ENABLE TRIGGER [babel_1654_vu_prepare_trig_t] +GO + diff --git a/test/python/expected/pyodbc/ddl_views.out b/test/python/expected/pyodbc/ddl_views.out new file mode 100644 index 0000000000..4d72388ac8 --- /dev/null +++ b/test/python/expected/pyodbc/ddl_views.out @@ -0,0 +1,31 @@ +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE TABLE [dbo].[sys_all_views_table_vu_prepare]( + [a] [int] NULL +) ON [PRIMARY] + +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE VIEW sys_all_views_dep_view_vu_prepare AS +SELECT name, type, with_check_option FROM sys.all_views where object_id = object_id('sys_all_views_select_vu_prepare') +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE VIEW sys_all_views_select_chk_option_vu_prepare AS +SELECT * FROM sys_all_views_table_vu_prepare +WITH CHECK OPTION +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE VIEW sys_all_views_select_vu_prepare AS +SELECT * FROM sys_all_views_table_vu_prepare +GO + +GO + +GO + diff --git a/test/python/input/ddl_func_proc.sql b/test/python/input/ddl_func_proc.sql new file mode 100644 index 0000000000..5cdeb939f2 --- /dev/null +++ b/test/python/input/ddl_func_proc.sql @@ -0,0 +1,232 @@ +/* This test files will check for scripting of table with stored procedures and user defined functions including diffferent inbuilt functions */ + +drop procedure IF EXISTS routines_test_nvar; +go +drop procedure IF EXISTS routines_test_num; +go +drop procedure IF EXISTS routines_test_uid; +go +drop procedure IF EXISTS routines_test_b1; +go +drop procedure IF EXISTS routines_test_b2; +go +drop procedure IF EXISTS routines_test_b3; +go +drop procedure IF EXISTS routines_test_b4; +go +drop function IF EXISTS routines_test_b6; +go +DROP function IF EXISTS routines_func_nvar; +go +drop function IF EXISTS routines_test_func_opt; +go +drop function IF EXISTS routines_test_s; +go +drop function IF EXISTS routines_test_con; +go +drop procedure IF EXISTS routines_test_t; +go +drop procedure IF EXISTS routines_cur_var; +go +drop procedure IF EXISTS routines_test_def; +go +drop function IF EXISTS routines_fc1; +go +drop function IF EXISTS routines_fc2; +go +drop function IF EXISTS routines_fc3; +go +drop function IF EXISTS routines_fc4; +go +drop function IF EXISTS routines_fc5; +go +drop function IF EXISTS routines_fc6; +go +drop function IF EXISTS routines_fc7; +go +DROP TABLE IF EXISTS routines_customers; +go + +create procedure routines_test_nvar(@test_nvar_a nvarchar , @test_nvar_b int = 8) +AS +BEGIN + SELECT @test_nvar_b=8; +END +go +create function routines_fc1(@fc1_a nvarchar) RETURNS nvarchar AS BEGIN return @fc1_a END; +go +create function routines_fc2(@fc2_a varchar) RETURNS varchar AS BEGIN return @fc2_a END; +go +create function routines_fc3(@fc3_a nchar) RETURNS nchar AS BEGIN return @fc3_a END; +go +create function routines_fc4(@fc4_a binary, @fc4_b tinyint, @fc4_c BIGINT, @fc4_d float) RETURNS binary AS BEGIN return @fc4_a END; +go +create function routines_fc5(@fc5_a varbinary) RETURNS varbinary AS BEGIN return @fc5_a END; +go +create function routines_fc6(@fc6_a char) RETURNS char AS BEGIN return @fc6_a END; +go + +create procedure routines_test_uid(@test_uid_a uniqueidentifier output) +AS +BEGIN + set @test_uid_a ='ce8af10a-2709-43b0-9e4e-a02753929d17'; + SELECT @test_uid_a as test_uid_a; +END; +go +CREATE TABLE routines_customers +( customer_id int NOT NULL, + customer_name char(50) NOT NULL, + address char(50), + city char(50), + state char(25), + zip_code char(10), + CONSTRAINT customers_pk PRIMARY KEY (customer_id) +); +go +create procedure routines_test_b1 +AS +BEGIN + select * from customers; + select * from customers where customer_id = 25; + select count(state) from customers; +END; +go +create procedure routines_test_b2(@test_b2_name char(255), @test_b2_city char(255), @test_b2_id int, @test_b2_address char(255), @test_b2_state char(255), @test_b2_cust_id int) +AS +BEGIN + INSERT INTO customers (customer_name,address,city,state,customer_id) VALUES (@test_b2_name,@test_b2_address,@test_b2_city,@test_b2_state,@test_b2_cust_id); + DELETE from customers where customer_id = @test_b2_id; + ALTER TABLE customers ADD email varchar(255); +END; +go +create procedure routines_test_b3 @test_b3_paramout varchar(20) out +AS +BEGIN +SELECT @test_b3_paramout ='helloworld'; +END; +go +create procedure routines_test_b4(@test_b4_a int, @test_b4_b char(255), @test_b4_c char(255), @test_b4_d char(255)) +AS +SET @test_b4_a=10; SET Nocount ON; +DECLARE @test_b4_temp int =12; +BEGIN + INSERT INTO customers (customer_name,address,city,customer_id) VALUES (@test_b4_b,@test_b4_c,@test_b4_d,@test_b4_a); +END; +go + +create function routines_test_b6( + @test_b6_a INT, + @test_b6_b DEC(10,2), + @test_b6_c DEC(4,2) +) +RETURNS DEC(10,2) +AS +BEGIN + RETURN @test_b6_a * @test_b6_b * (1 - @test_b6_c); +END; +go +create function routines_func_nvar (@func_nvar_a nvarchar(23)) returns nvarchar(23) AS BEGIN return @func_nvar_a END; +go +CREATE FUNCTION routines_test_func_opt (@test_func_opt_name varchar(10)) +RETURNS INT + WITH RETURNS NULL ON NULL INPUT +AS +BEGIN + RETURN 2; +END; +go +create function routines_test_s (@test_s_a char(45)) RETURNS char(45) +WITH SCHEMABINDING +AS +BEGIN + RETURN @test_s_a; +END; +go +create function routines_test_con(@test_con_a int) +RETURNS INT + WITH CALLED ON NULL INPUT +AS +BEGIN +RETURN @test_con_a; +END; +go +create procedure routines_test_t (@test_t_a int) +AS +BEGIN + begin try + begin transaction + update Empl set Name ="Arman" where id =99; + update Empl set Name ="Anand" where id =100; + commit transaction + print 'transaction committed' + END try + BEGIN catch + rollback transaction + print 'rollback' + end catch +END; +go +CREATE PROCEDURE routines_test_def(@test_def_a int = 2, @test_def_b char(255) OUTPUT, @test_def_c varchar(20) = 'abc', @test_def_d varbinary(8)) +AS +BEGIN + SET @test_def_b = 'a'; + SELECT @test_def_a, @test_def_b, @test_def_c, @test_def_d; +END; +go +CREATE FUNCTION routines_fc7() +RETURNS @myRetTable table (a int PRIMARY KEY) +AS +BEGIN +INSERT INTO @myRetTable VALUES (1) +RETURN +END; +GO + +--DROP + +drop procedure IF EXISTS routines_test_nvar; +go +drop procedure IF EXISTS routines_test_num; +go +drop procedure IF EXISTS routines_test_uid; +go +drop procedure IF EXISTS routines_test_b1; +go +drop procedure IF EXISTS routines_test_b2; +go +drop procedure IF EXISTS routines_test_b3; +go +drop procedure IF EXISTS routines_test_b4; +go +drop function IF EXISTS routines_test_b6; +go +DROP function IF EXISTS routines_func_nvar; +go +drop function IF EXISTS routines_test_func_opt; +go +drop function IF EXISTS routines_test_s; +go +drop function IF EXISTS routines_test_con; +go +drop procedure IF EXISTS routines_test_t; +go +drop procedure IF EXISTS routines_cur_var; +go +drop procedure IF EXISTS routines_test_def; +go +drop function IF EXISTS routines_fc1; +go +drop function IF EXISTS routines_fc2; +go +drop function IF EXISTS routines_fc3; +go +drop function IF EXISTS routines_fc4; +go +drop function IF EXISTS routines_fc5; +go +drop function IF EXISTS routines_fc6; +go +drop function IF EXISTS routines_fc7; +go +DROP TABLE IF EXISTS routines_customers; +go diff --git a/test/python/input/ddl_tables_index.sql b/test/python/input/ddl_tables_index.sql new file mode 100644 index 0000000000..4e67727d39 --- /dev/null +++ b/test/python/input/ddl_tables_index.sql @@ -0,0 +1,94 @@ +/* This test files will check for scripting of tables with constraints including check , primary keys, foreign keys , NULL , unique and single , composite indexes */ + +DROP TABLE IF EXISTS table_check +GO +DROP TABLE IF EXISTS table_foreign +GO +DROP TABLE IF EXISTS table_primary +GO +DROP TABLE IF EXISTS table_unique +GO +DROP TABLE IF EXISTS isc_check_constraints_t1 +GO +DROP TABLE IF EXISTS test_tsql_const +GO +DROP TABLE IF EXISTS test_tsql_cast +GO +DROP TABLE IF EXISTS test_datetime +GO +DROP TABLE IF EXISTS test_functioncall +GO +DROP TABLE IF EXISTS test_tsql_collate +GO +DROP TABLE IF EXISTS test_null +GO +DROP TABLE IF EXISTS test_upper +GO +Create table table_unique (a int NOT NULL UNIQUE , b int NOT NULL,c int ) +GO +Create table table_primary (a int NOT NULL , b int NOT NULL,c int, PRIMARY KEY(a) ) +GO +Create table table_foreign (aa int NOT NULL , bb int NOT NULL,a int, PRIMARY KEY(aa) ,FOREIGN KEY (a) REFERENCES table_primary(a)) +GO +Create table table_check (ID int NOT NULL,NAME varchar(10) NOT NULL,AGE int NOT NULL CHECK (AGE >= 18)) +GO +Create table isc_check_constraints_t1( a varchar, check(a = 'provvwstdjtlyzygsx')); +GO +Create table test_tsql_const( + c_int int primary key, + c_bit sys.bit check(c_bit <> cast(1 as sys.bit)), + check(c_int < 10), + c_smallint smallint check(c_smallint < cast(cast(CAST('20' AS smallint) as sql_variant) as smallint)), + c_binary binary(8) check(c_binary > cast(0xfe as binary(8))), + c_varbinary varbinary(8) check(c_varbinary > cast(0xfe as varbinary(8))) +) +GO +Create table test_datetime( + c_time time check(cast(c_time as pg_catalog.time) < cast('09:00:00' as time) and c_time < cast('09:00:00' as time(6))), + c_date date check(c_date < cast('2001-01-01' as date)), + c_datetime datetime check(c_datetime < cast('2020-10-20 09:00:00' as datetime)), + c_datetime2 datetime2 check(c_datetime2 < cast('2020-10-20 09:00:00' as datetime2) and c_datetime2 < cast('2020-10-20 09:00:00' as datetime2(6)) ), + c_datetimeoffset datetimeoffset check(c_datetimeoffset < cast('12-10-25 12:32:10 +01:00' as sys.datetimeoffset) and c_datetimeoffset < cast('12-10-25 12:32:10 +01:00' as datetimeoffset(4))), + c_smalldatetime smalldatetime check(c_smalldatetime < cast('2007-05-08 12:35:29.123' AS smalldatetime)), +) +GO +create table test_tsql_collate( + c_varchar varchar check(c_varchar <> cast('sflkjasdlkfjf' as varchar(12)) COLLATE latin1_general_ci_as), + c_char char check(c_char <> cast('sflkjasdlkfjf' as char(7)) COLLATE japanese_ci_as), + c_nchar nchar check(cast(c_nchar as nchar(7)) <> cast('sflkjasdlkfjf' as nchar(7)) COLLATE bbf_unicode_cp1_ci_as), +) +GO +Create table test_null(a int, b int, check(a IS NOT NULL), CONSTRAINT constraint1 check (a>10)); +GO +Create table test_upper(a char, check (upper(a) in ('A','B'))); +GO +Create index test_index on test_upper(a) +GO +Create index test_comp_index on table_unique(a,b) +GO +--DROP + +DROP TABLE IF EXISTS table_check +GO +DROP TABLE IF EXISTS table_foreign +GO +DROP TABLE IF EXISTS table_primary +GO +DROP TABLE IF EXISTS table_unique +GO +DROP TABLE IF EXISTS isc_check_constraints_t1 +GO +DROP TABLE IF EXISTS test_tsql_const +GO +DROP TABLE IF EXISTS test_tsql_cast +GO +DROP TABLE IF EXISTS test_tsql_collate +GO +DROP TABLE IF EXISTS test_datetime +GO +DROP TABLE IF EXISTS test_functioncall +GO +DROP TABLE IF EXISTS test_null +GO +DROP TABLE IF EXISTS test_upper +GO \ No newline at end of file diff --git a/test/python/input/ddl_triggers.sql b/test/python/input/ddl_triggers.sql new file mode 100644 index 0000000000..24608f0293 --- /dev/null +++ b/test/python/input/ddl_triggers.sql @@ -0,0 +1,58 @@ +/* This test files will check for scripting of triggers and identity and computed columns */ + +DROP TRIGGER IF EXISTS babel_1654_vu_prepare_trig_t +GO + +DROP TRIGGER IF EXISTS babel_1654_vu_prepare_updEmployeeDatas +GO + +DROP TABLE IF EXISTS babel_1654_vu_prepare_employeeData +GO + +DROP TABLE IF EXISTS babel_1654_vu_prepare_t +GO + +DROP TABLE IF EXISTS sys_computed_columns_vu_prepare_t1 +GO + + +CREATE TABLE babel_1654_vu_prepare_employeeData( ID INT IDENTITY (1,1) PRIMARY KEY,Emp_First_name VARCHAR (50),Emp_Last_name VARCHAR (50),Emp_Salary INT, +a varchar (50), b varchar(50), c varchar(50), d varchar(50), e varchar(50), f varchar(50)) +GO + +create table babel_1654_vu_prepare_t ( ID INT IDENTITY (1,1) PRIMARY KEY , a varchar(50), b varchar(50)) +GO + +CREATE TRIGGER babel_1654_vu_prepare_trig_t on babel_1654_vu_prepare_t after update as + select COLUMNS_UPDATED(); +GO + +CREATE TRIGGER babel_1654_vu_prepare_updEmployeeDatas ON babel_1654_vu_prepare_employeeData AFTER UPDATE,INSERT AS + select COLUMNS_UPDATED(); + update babel_1654_vu_prepare_t set a = 'sss' , b = 'sss' where id = 1; + select COLUMNS_UPDATED(); +GO + +CREATE TABLE sys_computed_columns_vu_prepare_t1 ( + scc_first_number smallint, + scc_second_number money, + scc_multiplied AS scc_first_number * scc_second_number +) +GO + +--DROP + +DROP TRIGGER IF EXISTS babel_1654_vu_prepare_trig_t +GO + +DROP TRIGGER IF EXISTS babel_1654_vu_prepare_updEmployeeDatas +GO + +DROP TABLE IF EXISTS babel_1654_vu_prepare_employeeData +GO + +DROP TABLE IF EXISTS babel_1654_vu_prepare_t +GO + +DROP TABLE IF EXISTS sys_computed_columns_vu_prepare_t1 +GO \ No newline at end of file diff --git a/test/python/input/ddl_views.sql b/test/python/input/ddl_views.sql new file mode 100644 index 0000000000..155cce6b46 --- /dev/null +++ b/test/python/input/ddl_views.sql @@ -0,0 +1,32 @@ +/* This test files will check for scripting views only */ + +DROP VIEW IF EXISTS sys_all_views_select_vu_prepare +GO +DROP VIEW IF EXISTS sys_all_views_select_chk_option_vu_prepare +GO +DROP VIEW IF EXISTS sys_all_views_dep_view_vu_prepare +GO +DROP TABLE IF EXISTS sys_all_views_table_vu_prepare +GO +CREATE TABLE sys_all_views_table_vu_prepare(a int) +GO +CREATE VIEW sys_all_views_select_vu_prepare AS +SELECT * FROM sys_all_views_table_vu_prepare +GO +CREATE VIEW sys_all_views_select_chk_option_vu_prepare AS +SELECT * FROM sys_all_views_table_vu_prepare +WITH CHECK OPTION +GO +CREATE VIEW sys_all_views_dep_view_vu_prepare AS +SELECT name, type, with_check_option FROM sys.all_views where object_id = object_id('sys_all_views_select_vu_prepare') +GO + +--DROP +DROP VIEW IF EXISTS sys_all_views_select_vu_prepare +GO +DROP VIEW IF EXISTS sys_all_views_select_chk_option_vu_prepare +GO +DROP VIEW IF EXISTS sys_all_views_dep_view_vu_prepare +GO +DROP TABLE IF EXISTS sys_all_views_table_vu_prepare +GO \ No newline at end of file diff --git a/test/python/test_main.py b/test/python/test_main.py index b9fcd66b84..a3c0becbf1 100644 --- a/test/python/test_main.py +++ b/test/python/test_main.py @@ -37,6 +37,8 @@ def test_main(fx1, my_setup): pytest.skip("Isolation Tests are not allowed - runIsolationTests config param is false") if fx1.name in ignored_files: pytest.skip("Ignored test file - Modify ignoredTestName to run this step") + if fx1.name.split(".")[0][:4] == 'ddl_' and cfg['ddlExport'] == 'false': + pytest.skip("DDL Export test not allowed") logfname = my_setup From 11cdc15224875cd3602bb989892a4744c5dc0ca6 Mon Sep 17 00:00:00 2001 From: Sharu Goel <30777678+thephantomthief@users.noreply.github.com> Date: Tue, 28 Mar 2023 13:33:42 +0530 Subject: [PATCH 031/363] Add build instructions for linked servers and disable them by default (#1369) This commit disables the linked servers feature by default and only keeps it enabled in the github actions. The instructions to enable the feature is added to the build instructions of the Babelfish extensions. Task: BABEL-OSS Signed-off-by: Sharu Goel --- .../build-extensions/action.yml | 3 ++- contrib/README.md | 16 ++++++++++++++++ contrib/babelfishpg_tsql/Makefile | 8 ++------ 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/.github/composite-actions/build-extensions/action.yml b/.github/composite-actions/build-extensions/action.yml index ca439b097d..2ff796b2c4 100644 --- a/.github/composite-actions/build-extensions/action.yml +++ b/.github/composite-actions/build-extensions/action.yml @@ -36,5 +36,6 @@ runs: cd ../babelfishpg_tds make -j 4 && make install cd ../babelfishpg_tsql - make && make install + PG_CPPFLAGS='-I/usr/include -DENABLE_TDS_LIB' SHLIB_LINK='-lsybdb -L/usr/lib64' make + PG_CPPFLAGS='-I/usr/include -DENABLE_TDS_LIB' SHLIB_LINK='-lsybdb -L/usr/lib64' make install shell: bash diff --git a/contrib/README.md b/contrib/README.md index caf83253e6..80e317d673 100644 --- a/contrib/README.md +++ b/contrib/README.md @@ -219,3 +219,19 @@ The following build instructions comply with Ubuntu 20.04 and Amazon Linux 2 env mvn test ``` For detailed instructions on how to write, add, and run tests in JDBC test framework, refer [to the online instructions](../test/JDBC/README.md). + + +# How to build the babelfishpg_tsql extension with linked servers enabled + +1. To work with linked servers, you must install the `tds_fdw` extension. More information about building and installing the extension can be found [at this link](https://github.com/tds-fdw/tds_fdw/blob/master/README.md). +2. Build the babelfishpg_tsql extension as follows: + ``` + PG_CPPFLAGS='-I/usr/include -DENABLE_TDS_LIB' SHLIB_LINK='-lsybdb -L/usr/lib64' make + PG_CPPFLAGS='-I/usr/include -DENABLE_TDS_LIB' SHLIB_LINK='-lsybdb -L/usr/lib64' make install + ``` +3. Create rest of the Babelfish extensions as usual, and initialize Babelfish. +4. Create the `tds_fdw` extension in the Babelfish database: + ``` + babelfish_db=> CREATE EXTENSION tds_fdw; + CREATE EXTENSION + ``` diff --git a/contrib/babelfishpg_tsql/Makefile b/contrib/babelfishpg_tsql/Makefile index ffb564162f..fe5429e73e 100644 --- a/contrib/babelfishpg_tsql/Makefile +++ b/contrib/babelfishpg_tsql/Makefile @@ -78,10 +78,6 @@ export ANTLR4_RUNTIME_LIB=-lantlr4-runtime export ANTLR4_RUNTIME_INCLUDE_DIR=/usr/local/include/antlr4-runtime export ANTLR4_RUNTIME_LIB_DIR=/usr/local/lib -export FREE_TDS_INCLUDE_DIR=/usr/include -export FREE_TDS_LIB_DIR=/usr/lib64 -export FREE_TDS_LIB="-lsybdb" - OBJS += src/pltsql_bulkcopy.o PG_CXXFLAGS += -g -Werror @@ -91,9 +87,9 @@ PG_CXXFLAGS += -Wno-register # otherwise C++17 gags on PostgreSQL headers PG_CXXFLAGS += -I$(ANTLR4_RUNTIME_INCLUDE_DIR) PG_CFLAGS += -g -Werror PG_CFLAGS += -fstack-protector-strong -PG_CPPFLAGS += -I$(TSQLSRC) -I$(PG_SRC) -I$(FREE_TDS_INCLUDE_DIR) -DFAULT_INJECTOR -DENABLE_TDS_LIB +PG_CPPFLAGS += -I$(TSQLSRC) -I$(PG_SRC) -DFAULT_INJECTOR -SHLIB_LINK += -L$(ANTLR4_RUNTIME_LIB_DIR) $(ANTLR4_RUNTIME_LIB) -lcrypto $(FREE_TDS_LIB) -L$(FREE_TDS_LIB_DIR) +SHLIB_LINK += -L$(ANTLR4_RUNTIME_LIB_DIR) $(ANTLR4_RUNTIME_LIB) -lcrypto UPGRADES = $(patsubst sql/upgrades/%.sql,sql/%.sql,$(wildcard sql/upgrades/*.sql)) From c67feb8f623c597345185fba2c62bfcbdc69c2eb Mon Sep 17 00:00:00 2001 From: Ashish Prasad <56514722+hash-16@users.noreply.github.com> Date: Wed, 29 Mar 2023 16:34:15 +0530 Subject: [PATCH 032/363] Disable DDl testcase (#1374) Disable DDL test cases from python framework , taking lot of time to execute Signed-off-by: Ashish Prasad pashisht@amazon.com --- test/python/config.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/python/config.txt b/test/python/config.txt index 7017ce74e4..792f6283a7 100644 --- a/test/python/config.txt +++ b/test/python/config.txt @@ -39,7 +39,7 @@ outputErrorCode = true runIsolationTests = false ############################ ALLOW TO RUN DDL EXPORT TESTS (IF TRUE THEN RUNS ALL THE .SQL FILES WITH PREFIX ddl_ FROM INPUT DIRECTORY OTHERWISE SKIP THEM) ################################################## -ddlExport = true +ddlExport = false ############################ MAX TIME LIMIT FOR SINGLE STEP QUERY EXECUTION IN SECONDS(FOR ISOLATION TESTS ONLY) ############################ stepTimeLimit = 30 From f1599536ce099f305ed987755cfa36dbda8c7163 Mon Sep 17 00:00:00 2001 From: Jake Owen Date: Wed, 29 Mar 2023 08:05:19 -0400 Subject: [PATCH 033/363] Created macro for PGC_SUSET (#1362) This commit creates a macro for (superuser() ? PGC_SUSET : PGC_USERSET) named GUC_CONTEXT_CONFIG to avoid future merge conflicts. Task: BABEL-OSS Signed-off-by: Jake Owen --- contrib/babelfishpg_common/src/coerce.c | 12 +++--- contrib/babelfishpg_common/src/sqlvariant.c | 4 +- .../src/backend/tds/tdstypeio.c | 14 +++---- contrib/babelfishpg_tsql/src/dbcmds.c | 24 +++++------ contrib/babelfishpg_tsql/src/multidb.c | 6 +-- contrib/babelfishpg_tsql/src/pl_handler.c | 6 +-- contrib/babelfishpg_tsql/src/pltsql_coerce.c | 12 +++--- contrib/babelfishpg_tsql/src/pltsql_utils.c | 4 +- contrib/babelfishpg_tsql/src/procedures.c | 42 +++++++++---------- .../src/tsql_for/forjson_old.c | 2 +- .../src/tsql_for/forxml_old.c | 2 +- 11 files changed, 64 insertions(+), 64 deletions(-) diff --git a/contrib/babelfishpg_common/src/coerce.c b/contrib/babelfishpg_common/src/coerce.c index 1b7db188d9..dfca1d3911 100644 --- a/contrib/babelfishpg_common/src/coerce.c +++ b/contrib/babelfishpg_common/src/coerce.c @@ -242,20 +242,20 @@ pltsql_text_name(PG_FUNCTION_ARGS) { /* T-SQL casting. follow T-SQL truncation rule */ set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); n = (*cstr_to_name_hook) (VARDATA_ANY(s), len); } PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RE_THROW(); } PG_END_TRY(); set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_NAME(n); @@ -303,20 +303,20 @@ pltsql_bpchar_name(PG_FUNCTION_ARGS) { /* T-SQL casting. follow T-SQL truncation rule */ set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); n = (*cstr_to_name_hook) (VARDATA_ANY(s), len); } PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RE_THROW(); } PG_END_TRY(); set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_NAME(n); diff --git a/contrib/babelfishpg_common/src/sqlvariant.c b/contrib/babelfishpg_common/src/sqlvariant.c index fc7f376d24..2554a6354a 100644 --- a/contrib/babelfishpg_common/src/sqlvariant.c +++ b/contrib/babelfishpg_common/src/sqlvariant.c @@ -365,7 +365,7 @@ gen_type_datum_from_sqlvariant_bytea(bytea *sv, uint8_t target_typcode, int32_t } set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); if (typcode == target_typcode) @@ -425,7 +425,7 @@ do_compare(char *oprname, bytea *arg1, bytea *arg2, Oid fncollation) memcpy(&d2, SV_DATUM_PTR(arg2, svhdr_size2), data_len2); set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); /* Check Type Code */ diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdstypeio.c b/contrib/babelfishpg_tds/src/backend/tds/tdstypeio.c index fade2ed106..8a29e42e27 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tdstypeio.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tdstypeio.c @@ -2118,7 +2118,7 @@ FetchTvpTypeOid(const ParameterToken token, char *tvpName) { /* Reset dialect. */ set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); elog(ERROR, "SPI_connect() failed in TDS Listener " "with return code %d", rc); @@ -2131,7 +2131,7 @@ FetchTvpTypeOid(const ParameterToken token, char *tvpName) { /* Reset dialect. */ set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); elog(ERROR, "Failed to insert in the underlying table for table-valued parameter: %d", rc); } @@ -2209,7 +2209,7 @@ TdsRecvTypeTable(const char *message, const ParameterToken token) * prep/exec insert query via SPI. */ set_config_option("babelfishpg_tsql.sql_dialect", "postgres", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); if (!xactStarted) @@ -2235,7 +2235,7 @@ TdsRecvTypeTable(const char *message, const ParameterToken token) { /* Reset dialect. */ set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); elog(ERROR, "Failed to create the underlying table for table-valued parameter: %d", rc); } @@ -2362,7 +2362,7 @@ TdsRecvTypeTable(const char *message, const ParameterToken token) { /* Reset dialect. */ set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); elog(ERROR, "SPI_connect() failed in TDS Listener " "with return code %d", rc); @@ -2377,7 +2377,7 @@ TdsRecvTypeTable(const char *message, const ParameterToken token) { /* Reset dialect. */ set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); elog(ERROR, "Failed to insert in the underlying table for table-valued parameter: %d", rc); } @@ -2389,7 +2389,7 @@ TdsRecvTypeTable(const char *message, const ParameterToken token) } set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); } diff --git a/contrib/babelfishpg_tsql/src/dbcmds.c b/contrib/babelfishpg_tsql/src/dbcmds.c index 45e86ca511..1efe2932b6 100644 --- a/contrib/babelfishpg_tsql/src/dbcmds.c +++ b/contrib/babelfishpg_tsql/src/dbcmds.c @@ -747,19 +747,19 @@ create_builtin_dbs(PG_FUNCTION_ARGS) PG_TRY(); { set_config_option("babelfishpg_tsql.sql_dialect", tsql_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); do_create_bbf_db("master", NULL, sa_name); do_create_bbf_db("tempdb", NULL, sa_name); do_create_bbf_db("msdb", NULL, sa_name); set_config_option("babelfishpg_tsql.sql_dialect", sql_dialect_value_old, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); } PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", sql_dialect_value_old, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); } @@ -785,17 +785,17 @@ create_msdb_if_not_exists(PG_FUNCTION_ARGS) PG_TRY(); { set_config_option("babelfishpg_tsql.sql_dialect", tsql_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); create_bbf_db_internal("msdb", NULL, sa_name, 4); set_config_option("babelfishpg_tsql.sql_dialect", sql_dialect_value_old, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); } PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", sql_dialect_value_old, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); } @@ -822,7 +822,7 @@ drop_all_dbs(PG_FUNCTION_ARGS) PG_TRY(); { set_config_option("babelfishpg_tsql.sql_dialect", tsql_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); /* drop built-in DBs */ drop_bbf_db("master", false, true); @@ -859,13 +859,13 @@ drop_all_dbs(PG_FUNCTION_ARGS) all_db_dropped = true; } set_config_option("babelfishpg_tsql.sql_dialect", sql_dialect_value_old, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); } PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", sql_dialect_value_old, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RE_THROW(); @@ -1100,7 +1100,7 @@ create_guest_schema_for_all_dbs(PG_FUNCTION_ARGS) PG_TRY(); { set_config_option("babelfishpg_tsql.sql_dialect", tsql_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); /* @@ -1129,14 +1129,14 @@ create_guest_schema_for_all_dbs(PG_FUNCTION_ARGS) creating_extension = creating_extension_backup; set_config_option("babelfishpg_tsql.sql_dialect", sql_dialect_value_old, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); } PG_FINALLY(); { creating_extension = creating_extension_backup; set_config_option("babelfishpg_tsql.sql_dialect", sql_dialect_value_old, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); } PG_END_TRY(); diff --git a/contrib/babelfishpg_tsql/src/multidb.c b/contrib/babelfishpg_tsql/src/multidb.c index bd509f82e2..25e5075e4a 100644 --- a/contrib/babelfishpg_tsql/src/multidb.c +++ b/contrib/babelfishpg_tsql/src/multidb.c @@ -1468,20 +1468,20 @@ truncate_tsql_identifier(char *ident) { /* this is BBF help function. use BBF truncation logic */ set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); truncate_identifier(ident, strlen(ident), false); } PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RE_THROW(); } PG_END_TRY(); set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); } diff --git a/contrib/babelfishpg_tsql/src/pl_handler.c b/contrib/babelfishpg_tsql/src/pl_handler.c index 3c9221bc16..7fd9ec26a4 100644 --- a/contrib/babelfishpg_tsql/src/pl_handler.c +++ b/contrib/babelfishpg_tsql/src/pl_handler.c @@ -3711,20 +3711,20 @@ pltsql_truncate_identifier_func(PG_FUNCTION_ARGS) { /* this is BBF help function. use BBF truncation logic */ set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); truncate_identifier(name, len, false); } PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RE_THROW(); } PG_END_TRY(); set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_TEXT_P(cstring_to_text(name)); diff --git a/contrib/babelfishpg_tsql/src/pltsql_coerce.c b/contrib/babelfishpg_tsql/src/pltsql_coerce.c index e907d23b1f..2de3703659 100644 --- a/contrib/babelfishpg_tsql/src/pltsql_coerce.c +++ b/contrib/babelfishpg_tsql/src/pltsql_coerce.c @@ -1367,20 +1367,20 @@ pltsql_text_name(PG_FUNCTION_ARGS) { /* T-SQL casting. follow T-SQL truncation rule */ set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); n = (*cstr_to_name_hook) (VARDATA_ANY(s), len); } PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RE_THROW(); } PG_END_TRY(); set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_NAME(n); @@ -1429,20 +1429,20 @@ pltsql_bpchar_name(PG_FUNCTION_ARGS) { /* T-SQL casting. follow T-SQL truncation rule */ set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); n = (*cstr_to_name_hook) (VARDATA_ANY(s), len); } PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RE_THROW(); } PG_END_TRY(); set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_NAME(n); diff --git a/contrib/babelfishpg_tsql/src/pltsql_utils.c b/contrib/babelfishpg_tsql/src/pltsql_utils.c index e39b417766..7b19ace186 100644 --- a/contrib/babelfishpg_tsql/src/pltsql_utils.c +++ b/contrib/babelfishpg_tsql/src/pltsql_utils.c @@ -897,7 +897,7 @@ get_pltsql_function_signature_internal(const char *funcname, * string */ set_config_option("quote_all_identifiers", "true", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); appendStringInfo(&argbuf, "%s(", funcname); @@ -912,7 +912,7 @@ get_pltsql_function_signature_internal(const char *funcname, PG_FINALLY(); { set_config_option("quote_all_identifiers", prev_quote_ident, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); } PG_END_TRY(); diff --git a/contrib/babelfishpg_tsql/src/procedures.c b/contrib/babelfishpg_tsql/src/procedures.c index 86851f42b4..be666e9eb8 100644 --- a/contrib/babelfishpg_tsql/src/procedures.c +++ b/contrib/babelfishpg_tsql/src/procedures.c @@ -127,7 +127,7 @@ sp_prepare(PG_FUNCTION_ARGS) old_dialect = GetConfigOption("babelfishpg_tsql.sql_dialect", true, true); set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, @@ -152,7 +152,7 @@ sp_prepare(PG_FUNCTION_ARGS) PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", old_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, @@ -163,7 +163,7 @@ sp_prepare(PG_FUNCTION_ARGS) PG_END_TRY(); set_config_option("babelfishpg_tsql.sql_dialect", old_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, @@ -444,13 +444,13 @@ sp_describe_first_result_set_internal(PG_FUNCTION_ARGS) * TSQL Syntax. */ set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); if ((rc = SPI_execute(query, false, 1)) < 0) { sp_describe_first_result_set_inprogress = false; set_config_option("babelfishpg_tsql.sql_dialect", "postgres", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); elog(ERROR, "SPI_execute failed: %s", SPI_result_code_string(rc)); } @@ -458,7 +458,7 @@ sp_describe_first_result_set_internal(PG_FUNCTION_ARGS) sp_describe_first_result_set_inprogress = false; set_config_option("babelfishpg_tsql.sql_dialect", "postgres", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); pfree(query); @@ -1595,7 +1595,7 @@ sp_addrole(PG_FUNCTION_ARGS) PG_TRY(); { set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); rolname = PG_ARGISNULL(0) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(0)); @@ -1686,13 +1686,13 @@ sp_addrole(PG_FUNCTION_ARGS) PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RE_THROW(); } PG_END_TRY(); set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_VOID(); } @@ -1752,7 +1752,7 @@ sp_droprole(PG_FUNCTION_ARGS) PG_TRY(); { set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); rolname = PG_ARGISNULL(0) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(0)); @@ -1824,13 +1824,13 @@ sp_droprole(PG_FUNCTION_ARGS) PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RE_THROW(); } PG_END_TRY(); set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_VOID(); } @@ -1888,7 +1888,7 @@ sp_addrolemember(PG_FUNCTION_ARGS) PG_TRY(); { set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); rolname = PG_ARGISNULL(0) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(0)); @@ -1993,13 +1993,13 @@ sp_addrolemember(PG_FUNCTION_ARGS) PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RE_THROW(); } PG_END_TRY(); set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_VOID(); } @@ -2059,7 +2059,7 @@ sp_droprolemember(PG_FUNCTION_ARGS) PG_TRY(); { set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); rolname = PG_ARGISNULL(0) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(0)); @@ -2152,13 +2152,13 @@ sp_droprolemember(PG_FUNCTION_ARGS) PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RE_THROW(); } PG_END_TRY(); set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_VOID(); } @@ -2879,7 +2879,7 @@ sp_rename_internal(PG_FUNCTION_ARGS) { /* 1. set dialect to TSQL */ set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); /* 2. read the input arguments */ @@ -3018,13 +3018,13 @@ sp_rename_internal(PG_FUNCTION_ARGS) PG_CATCH(); { set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RE_THROW(); } PG_END_TRY(); set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_VOID(); } diff --git a/contrib/babelfishpg_tsql/src/tsql_for/forjson_old.c b/contrib/babelfishpg_tsql/src/tsql_for/forjson_old.c index fbdc04a6e0..80c71e3c20 100644 --- a/contrib/babelfishpg_tsql/src/tsql_for/forjson_old.c +++ b/contrib/babelfishpg_tsql/src/tsql_for/forjson_old.c @@ -193,7 +193,7 @@ tsql_query_to_json_internal(const char *query, int mode, bool include_null_value uint64 i; set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); result = makeStringInfo(); diff --git a/contrib/babelfishpg_tsql/src/tsql_for/forxml_old.c b/contrib/babelfishpg_tsql/src/tsql_for/forxml_old.c index 88d3dd08e4..550617e441 100644 --- a/contrib/babelfishpg_tsql/src/tsql_for/forxml_old.c +++ b/contrib/babelfishpg_tsql/src/tsql_for/forxml_old.c @@ -219,7 +219,7 @@ tsql_query_to_xml_internal(const char *query, int mode, uint64 i; set_config_option("babelfishpg_tsql.sql_dialect", "tsql", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); result = makeStringInfo(); From ad95b43ca44e48b305de01cb4865294b68043f3a Mon Sep 17 00:00:00 2001 From: Rui Zhao Date: Thu, 30 Mar 2023 05:30:42 +0800 Subject: [PATCH 034/363] Fix the issue that context_info() cannot display complete varbinary in sqlcmd. (#1355) Description =========== context_info() cannot display complete varbinary in sqlcmd. Analysis ======== Based on the TDS document, it is expected that sqlcmd would have the capability to support both variable-length and partially length-prefixed data types. However, in this particular scenario, sqlcmd does not support the partially length-prefixed data type for varbinary. The main distinguishing factor between these two data types is that the variable-length data type has an associated length value, while the partially length-prefixed data type does not require the full data length to be specified before the actual data is streamed out. Note: Neither freetds nor JDBC encounter any issues with regard to this matter. Fix === Fill atttypmod in PrepareRowDescription with the typmod value stored in pg_proc.probin. --- .../src/backend/tds/tdsresponse.c | 72 ++++++++++++++----- contrib/babelfishpg_tsql/runtime/functions.c | 7 ++ .../babelfishpg_tsql/sql/babelfishpg_tsql.sql | 9 +++ .../sql/sys_function_helpers.sql | 3 + .../babelfishpg_tsql/sql/sys_functions.sql | 3 - .../babelfishpg_tsql--3.1.0--3.2.0.sql | 12 +++- .../babel_context_info-vu-cleanup.out | 3 + .../babel_context_info-vu-prepare.out | 7 ++ .../expected/babel_context_info-vu-verify.out | 16 +++++ .../input/babel_context_info-vu-cleanup.sql | 3 + .../input/babel_context_info-vu-prepare.sql | 7 ++ .../input/babel_context_info-vu-verify.sql | 6 ++ .../expected_dependency.out | 1 + 13 files changed, 129 insertions(+), 20 deletions(-) diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdsresponse.c b/contrib/babelfishpg_tds/src/backend/tds/tdsresponse.c index d9e278bfa2..2e63fd539b 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tdsresponse.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tdsresponse.c @@ -815,6 +815,60 @@ resolve_numeric_typmod_from_exp(Node *expr) } } +/* look for a typmod to return from a varbinary expression */ +static int32 +resolve_varbinary_typmod_from_exp(Node *expr) +{ + if (expr == NULL) + return -1; + + switch (nodeTag(expr)) + { + case T_Const: + { + /* + * Generate the typmod from hex const input because typmod won't be + * specified. + */ + Const *con = (Const *) expr; + if (!con->constisnull) + { + bytea *source = (bytea *) con->constvalue; + + return VARSIZE_ANY(source); + } + else + return -1; + } + case T_FuncExpr: + { + FuncExpr *func = (FuncExpr *) expr; + Oid func_oid = InvalidOid; + int rettypmod = -1; + + /* Be smart about length-coercion functions... */ + if (exprIsLengthCoercion(expr, &rettypmod)) + return rettypmod; + + /* + * Look up the return type typmod from a persistent store + * using the function oid. + */ + func_oid = func->funcid; + Assert(func_oid != InvalidOid); + + if (func->funcresulttype != VOIDOID) + rettypmod = pltsql_plugin_handler_ptr->pltsql_read_numeric_typmod(func_oid, + func->args == NIL ? 0 : func->args->length, + func->funcresulttype); + return rettypmod; + } + /* TODO handle more Expr types if needed */ + default: + return -1; + } +} + void InitTDSResponse(void) { @@ -1727,22 +1781,8 @@ PrepareRowDescription(TupleDesc typeinfo, List *targetlist, int16 *formats, 1 : atttypmod - VARHDRSZ); break; case TDS_SEND_VARBINARY: - - /* - * Generate the typmod from hex const input because typmod - * won't be specified - */ - if (atttypmod == -1 && tle != NULL && IsA(tle->expr, Const)) - { - Const *con = (Const *) tle->expr; - - if (!con->constisnull) - { - bytea *source = (bytea *) con->constvalue; - - atttypmod = VARSIZE_ANY(source); - } - } + if (atttypmod == -1 && tle != NULL) + atttypmod = resolve_varbinary_typmod_from_exp((Node *) tle->expr); SetColMetadataForBinaryType(col, TDS_TYPE_VARBINARY, (atttypmod == -1) ? atttypmod : atttypmod - VARHDRSZ); break; diff --git a/contrib/babelfishpg_tsql/runtime/functions.c b/contrib/babelfishpg_tsql/runtime/functions.c index ca28e8229c..dcf0b8f52a 100644 --- a/contrib/babelfishpg_tsql/runtime/functions.c +++ b/contrib/babelfishpg_tsql/runtime/functions.c @@ -86,6 +86,7 @@ PG_FUNCTION_INFO_V1(sp_datatype_info_helper); PG_FUNCTION_INFO_V1(language); PG_FUNCTION_INFO_V1(host_name); PG_FUNCTION_INFO_V1(context_info); +PG_FUNCTION_INFO_V1(bbf_get_context_info); PG_FUNCTION_INFO_V1(bbf_set_context_info); PG_FUNCTION_INFO_V1(procid); PG_FUNCTION_INFO_V1(babelfish_integrity_checker); @@ -1848,6 +1849,12 @@ host_name(PG_FUNCTION_ARGS) Datum context_info(PG_FUNCTION_ARGS) +{ + return bbf_get_context_info(fcinfo); +} + +Datum +bbf_get_context_info(PG_FUNCTION_ARGS) { Datum context_info = (Datum) 0; diff --git a/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql index c81f72a941..4f80559e67 100644 --- a/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql +++ b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql @@ -3059,3 +3059,12 @@ END; $$ LANGUAGE 'pltsql'; GRANT EXECUTE ON PROCEDURE sys.sp_linkedservers TO PUBLIC; +CREATE OR REPLACE FUNCTION sys.context_info() +RETURNS sys.VARBINARY(128) +AS '{"version_num": "1", "typmod_array": ["128"], "original_probin": ""}', +$$ +BEGIN + return sys.bbf_get_context_info() +END; +$$ +LANGUAGE pltsql STABLE; diff --git a/contrib/babelfishpg_tsql/sql/sys_function_helpers.sql b/contrib/babelfishpg_tsql/sql/sys_function_helpers.sql index 51d92c2059..80e7aca6fa 100644 --- a/contrib/babelfishpg_tsql/sql/sys_function_helpers.sql +++ b/contrib/babelfishpg_tsql/sql/sys_function_helpers.sql @@ -10352,3 +10352,6 @@ CREATE OR REPLACE FUNCTION sys.bbf_is_shared_schema(IN schemaname TEXT) RETURNS BOOL AS 'babelfishpg_tsql', 'is_shared_schema_wrapper' LANGUAGE C IMMUTABLE STRICT; + +CREATE OR REPLACE FUNCTION sys.bbf_get_context_info() +RETURNS sys.VARBINARY(128) AS 'babelfishpg_tsql', 'bbf_get_context_info' LANGUAGE C STABLE; diff --git a/contrib/babelfishpg_tsql/sql/sys_functions.sql b/contrib/babelfishpg_tsql/sql/sys_functions.sql index 1fcbb9c92d..a4a974ab37 100644 --- a/contrib/babelfishpg_tsql/sql/sys_functions.sql +++ b/contrib/babelfishpg_tsql/sql/sys_functions.sql @@ -3329,9 +3329,6 @@ RETURNS sys.NVARCHAR(128) AS 'babelfishpg_tsql' LANGUAGE C STABLE; CREATE OR REPLACE FUNCTION sys.host_name() RETURNS sys.NVARCHAR(128) AS 'babelfishpg_tsql' LANGUAGE C IMMUTABLE PARALLEL SAFE; -CREATE OR REPLACE FUNCTION sys.context_info() -RETURNS sys.VARBINARY(128) AS 'babelfishpg_tsql' LANGUAGE C STABLE; - CREATE OR REPLACE FUNCTION sys.degrees(IN arg1 BIGINT) RETURNS bigint AS 'babelfishpg_tsql','bigint_degrees' LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE; GRANT EXECUTE ON FUNCTION sys.degrees(BIGINT) TO PUBLIC; diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql index 2deb778a1a..08c21bbe94 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql @@ -421,8 +421,18 @@ CALL sys.babelfish_drop_deprecated_object('view', 'sys', 'sysprocesses_deprecate CALL sys.babelfish_drop_deprecated_object('view', 'sys', 'dm_exec_sessions_deprecated_in_3_2_0'); CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'tsql_stat_get_activity_deprecated_in_3_2_0'); +CREATE OR REPLACE FUNCTION sys.bbf_get_context_info() +RETURNS sys.VARBINARY(128) AS 'babelfishpg_tsql', 'bbf_get_context_info' LANGUAGE C STABLE; + CREATE OR REPLACE FUNCTION sys.context_info() -RETURNS sys.VARBINARY(128) AS 'babelfishpg_tsql' LANGUAGE C STABLE; +RETURNS sys.VARBINARY(128) +AS '{"version_num": "1", "typmod_array": ["128"], "original_probin": ""}', +$$ +BEGIN + return sys.bbf_get_context_info() +END; +$$ +LANGUAGE pltsql STABLE; CREATE OR REPLACE PROCEDURE sys.bbf_set_context_info(IN context_info sys.VARBINARY(128)) AS 'babelfishpg_tsql' LANGUAGE C; diff --git a/test/JDBC/expected/babel_context_info-vu-cleanup.out b/test/JDBC/expected/babel_context_info-vu-cleanup.out index 872ec2b27f..6588449608 100644 --- a/test/JDBC/expected/babel_context_info-vu-cleanup.out +++ b/test/JDBC/expected/babel_context_info-vu-cleanup.out @@ -1,6 +1,9 @@ DROP PROCEDURE BABEL_SET_CONTEXT_INFO GO +DROP PROCEDURE BABEL_GET_CONTEXT_INFO_WITH_PLP +GO + DROP PROCEDURE BABEL_GET_CONTEXT_INFO GO diff --git a/test/JDBC/expected/babel_context_info-vu-prepare.out b/test/JDBC/expected/babel_context_info-vu-prepare.out index 62db0ea452..43c3f26ae6 100644 --- a/test/JDBC/expected/babel_context_info-vu-prepare.out +++ b/test/JDBC/expected/babel_context_info-vu-prepare.out @@ -6,6 +6,13 @@ BEGIN END; GO +CREATE PROCEDURE BABEL_GET_CONTEXT_INFO_WITH_PLP +AS +BEGIN + SELECT sys.bbf_get_context_info() +END; +GO + CREATE PROCEDURE BABEL_GET_CONTEXT_INFO AS BEGIN diff --git a/test/JDBC/expected/babel_context_info-vu-verify.out b/test/JDBC/expected/babel_context_info-vu-verify.out index d7fdbfd7b1..5f2bbdb34d 100644 --- a/test/JDBC/expected/babel_context_info-vu-verify.out +++ b/test/JDBC/expected/babel_context_info-vu-verify.out @@ -7,6 +7,14 @@ varbinary ~~END~~ +EXEC BABEL_GET_CONTEXT_INFO_WITH_PLP +GO +~~START~~ +varbinary + +~~END~~ + + EXEC BABEL_GET_CONTEXT_INFO GO ~~START~~ @@ -42,6 +50,14 @@ varbinary EXEC BABEL_SET_CONTEXT_INFO 0x1234567812345678 GO +EXEC BABEL_GET_CONTEXT_INFO_WITH_PLP +GO +~~START~~ +varbinary +1234567812345678000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + EXEC BABEL_GET_CONTEXT_INFO GO ~~START~~ diff --git a/test/JDBC/input/babel_context_info-vu-cleanup.sql b/test/JDBC/input/babel_context_info-vu-cleanup.sql index 872ec2b27f..6588449608 100644 --- a/test/JDBC/input/babel_context_info-vu-cleanup.sql +++ b/test/JDBC/input/babel_context_info-vu-cleanup.sql @@ -1,6 +1,9 @@ DROP PROCEDURE BABEL_SET_CONTEXT_INFO GO +DROP PROCEDURE BABEL_GET_CONTEXT_INFO_WITH_PLP +GO + DROP PROCEDURE BABEL_GET_CONTEXT_INFO GO diff --git a/test/JDBC/input/babel_context_info-vu-prepare.sql b/test/JDBC/input/babel_context_info-vu-prepare.sql index 62db0ea452..43c3f26ae6 100644 --- a/test/JDBC/input/babel_context_info-vu-prepare.sql +++ b/test/JDBC/input/babel_context_info-vu-prepare.sql @@ -6,6 +6,13 @@ BEGIN END; GO +CREATE PROCEDURE BABEL_GET_CONTEXT_INFO_WITH_PLP +AS +BEGIN + SELECT sys.bbf_get_context_info() +END; +GO + CREATE PROCEDURE BABEL_GET_CONTEXT_INFO AS BEGIN diff --git a/test/JDBC/input/babel_context_info-vu-verify.sql b/test/JDBC/input/babel_context_info-vu-verify.sql index cd5ebb11b0..97f15d6fad 100644 --- a/test/JDBC/input/babel_context_info-vu-verify.sql +++ b/test/JDBC/input/babel_context_info-vu-verify.sql @@ -2,6 +2,9 @@ SELECT CONTEXT_INFO() GO +EXEC BABEL_GET_CONTEXT_INFO_WITH_PLP +GO + EXEC BABEL_GET_CONTEXT_INFO GO @@ -17,6 +20,9 @@ GO EXEC BABEL_SET_CONTEXT_INFO 0x1234567812345678 GO +EXEC BABEL_GET_CONTEXT_INFO_WITH_PLP +GO + EXEC BABEL_GET_CONTEXT_INFO GO diff --git a/test/python/expected/upgrade_validation/expected_dependency.out b/test/python/expected/upgrade_validation/expected_dependency.out index c936707ea6..701f74948f 100644 --- a/test/python/expected/upgrade_validation/expected_dependency.out +++ b/test/python/expected/upgrade_validation/expected_dependency.out @@ -219,6 +219,7 @@ Function sys.babelfish_waitfor_delay(text) Function sys.babelfish_waitfor_delay(timestamp without time zone) Function sys.bbf_binary_cmp(sys.bbf_binary,sys.bbf_binary) Function sys.bbf_binary_varbinary_cmp(sys.bbf_binary,sys.bbf_varbinary) +Function sys.bbf_get_context_info() Function sys.bbf_get_current_physical_schema_name(text) Function sys.bbf_is_shared_schema(text) Function sys.bbf_varbinary_binary_cmp(sys.bbf_varbinary,sys.bbf_binary) From 184ccd6a652b501c5a1427bdff5b7b40c6042728 Mon Sep 17 00:00:00 2001 From: Sai Rohan Basa <108261379+basasairohan@users.noreply.github.com> Date: Thu, 30 Mar 2023 11:04:06 +0530 Subject: [PATCH 035/363] Add manual and scheduled workflow for generating Code Coverage (#1370) This change adds a code-coverage workflow which is scheduled to run at 00:00:00 UTC every day and it can also be triggered manually by specifying the branch name as an input. Scheduled workflow generates code coverage for BABEL_3_X_DEV and BABEL_2_X_DEV branches. We can also trigger the manual workflow for BABEL_3_X_DEV Task: TES2-12 Signed-off-by: Sai Rohan Basa bsrohan@amazon.com --- .github/workflows/code-coverage.yml | 312 ++++++++++++++++++++++++++++ 1 file changed, 312 insertions(+) create mode 100644 .github/workflows/code-coverage.yml diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml new file mode 100644 index 0000000000..84703f3e92 --- /dev/null +++ b/.github/workflows/code-coverage.yml @@ -0,0 +1,312 @@ +name: Code Coverage +on: + schedule: + - cron: '0 0 * * *' # runs every midnight + workflow_dispatch: + +jobs: + + generate-branch-names: + runs-on: ubuntu-20.04 + outputs: + matrix: ${{ steps.matrix.outputs.branches }} + steps: + - id: matrix + run: | + if [[ ${{ github.event_name }} == 'workflow_dispatch' ]]; then + echo "::set-output name=branches::['BABEL_3_X_DEV']" + else + echo "::set-output name=branches::['BABEL_3_X_DEV', 'BABEL_2_X_DEV']" + fi + + run-all-tests: + needs: [ generate-branch-names ] + runs-on: ubuntu-20.04 + + strategy: + fail-fast: false + matrix: + branch: ${{fromJson(needs.generate-branch-names.outputs.matrix)}} + + steps: + - uses: actions/checkout@v2 + id: checkout + with: + ref: ${{ matrix.branch }} + + - name: Install Dependencies + id: install-dependencies + if: always() + uses: ./.github/composite-actions/install-dependencies + + - name: Install Code Coverage Dependencies + id: install-code-coverage-dependencies + if: always() + run: | + sudo apt-get install lcov + + - name: Build Modified Postgres + id: build-modified-postgres + if: always() && steps.install-dependencies.outcome == 'success' + run: | + cd .. + rm -rf postgresql_modified_for_babelfish + $GITHUB_WORKSPACE/.github/scripts/clone_engine_repo "$GITHUB_REPOSITORY_OWNER" "${{matrix.branch}}" + cd postgresql_modified_for_babelfish + ./configure --prefix=$HOME/psql/ --with-python PYTHON=/usr/bin/python3.8 --enable-coverage --enable-cassert CFLAGS="-ggdb" --with-libxml --with-uuid=ossp --with-icu + make -j 4 2>error.txt + make install + cd contrib && make && sudo make install + cd ../.. + rm -rf pg_hint_plan + if [[ ${{matrix.branch}} == "BABEL_2_"* ]]; then + git clone --depth 1 --branch REL14_1_4_0 https://github.com/ossc-db/pg_hint_plan.git + else + git clone --depth 1 --branch PG15 https://github.com/ossc-db/pg_hint_plan.git + fi + cd pg_hint_plan + export PATH=$HOME/psql/bin:$PATH + make + make install + + - name: Compile ANTLR + id: compile-antlr + if: always() && steps.build-modified-postgres.outcome == 'success' + uses: ./.github/composite-actions/compile-antlr + with: + install_dir: 'psql' + + - name: Build Extensions + id: build-extensions + if: always() && steps.compile-antlr.outcome == 'success' + uses: ./.github/composite-actions/build-extensions + with: + install_dir: 'psql' + + - name: Install Extensions + id: install-extensions + if: always() && steps.build-extensions.outcome == 'success' + uses: ./.github/composite-actions/install-extensions + with: + install_dir: 'psql' + + - name: Build tds_fdw Extension + id: build-tds_fdw-extension + if: ${{ startsWith(matrix.branch, 'BABEL_3_') && (steps.build-extensions.outcome == 'success') }} + uses: ./.github/composite-actions/build-tds_fdw-extension + + - name: Run JDBC Tests + id: jdbc + if: always() && steps.install-extensions.outcome == 'success' + timeout-minutes: 60 + run: | + cd test/JDBC/ + mvn test + + - name: Install MSSQL Tools + id: install-mssql-tools + if: always() && steps.install-mssql-tools.outcome == 'success' + run: | + curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add - + curl https://packages.microsoft.com/config/ubuntu/20.04/prod.list | sudo tee /etc/apt/sources.list.d/msprod.list + sudo apt-get update + sudo apt-get install mssql-tools unixodbc-dev + echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc + source ~/.bashrc + + - name: Install Dotnet + id: install-dotnet + if: always() && steps.install-extensions.outcome == 'success' + run: | + cd ~ + wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb + sudo dpkg -i packages-microsoft-prod.deb + rm packages-microsoft-prod.deb + sudo apt-get install -y apt-transport-https + sudo apt-get install -y dotnet-sdk-5.0 + sudo apt-get install -y apt-transport-https + sudo apt-get install -y aspnetcore-runtime-5.0 + + - name: Run Dotnet Tests + if: always() && steps.install-dotnet.outcome == 'success' + run: | + cd test/dotnet + dotnet build + babel_URL=localhost \ + babel_port=1433 \ + babel_databaseName=master \ + babel_user=jdbc_user \ + babel_password=12345678 \ + testName="all---TestUDD.txt;TestChar.txt;TestSqlVariant.txt;TestVarChar.txt;TestAuthentication.txt;TestText.txt" \ + dotnet test + + - name: Install SQL Server ODBC Driver + id: install-sql-server-odbc-driver + if: always() && steps.install-extensions.outcome == 'success' + run: | + cd ~ + sudo apt-get install msodbcsql17 + + - name: Install unixODBC Driver + id: install-unix-odbc-driver + if: always() && steps.install-extensions.outcome == 'success' + run: | + cd ~ + wget http://www.unixodbc.org/unixODBC-2.3.11.tar.gz + gunzip unixODBC*.tar.gz + tar xvf unixODBC*.tar + cd unixODBC-2.3.11 + ./configure + make + sudo make install + + - name: Install psqlODBC Driver + id: install-psql-odbc-driver + if: always() && steps.install-extensions.outcome == 'success' && steps.install-unix-odbc-driver.outcome=='success' + run: | + cd ~ + wget https://ftp.postgresql.org/pub/odbc/versions/src/psqlodbc-12.01.0000.tar.gz + tar -zxvf psqlodbc-12.01.0000.tar.gz + cd psqlodbc-12.01.0000 + ./configure + sudo make + sudo make install + echo '[ODBC_Driver_12_for_PostgreSQL]' | sudo tee -a /etc/odbcinst.ini > /dev/null + echo 'Description=ODBC Driver 12 for PostgreSQL Server' | sudo tee -a /etc/odbcinst.ini > /dev/null + echo 'Driver=/usr/local/lib/psqlodbcw.so' | sudo tee -a /etc/odbcinst.ini > /dev/null + echo 'UsageCount=1' | sudo tee -a /etc/odbcinst.ini > /dev/null + + - name: Run ODBC Tests + if: always() && steps.install-sql-server-odbc-driver.outcome == 'success' && steps.install-psql-odbc-driver.outcome == 'success' + run: | + cd test/odbc + cmake -S . -B build + cmake --build build + MSSQL_ODBC_DRIVER_NAME="ODBC Driver 17 for SQL Server" \ + MSSQL_BABEL_DB_SERVER=localhost \ + MSSQL_BABEL_DB_PORT=1433 \ + MSSQL_BABEL_DB_USER=jdbc_user \ + MSSQL_BABEL_DB_PASSWORD=12345678 \ + MSSQL_BABEL_DB_NAME=master \ + PSQL_ODBC_DRIVER_NAME=ODBC_Driver_12_for_PostgreSQL \ + PSQL_BABEL_DB_SERVER=localhost \ + PSQL_BABEL_DB_PORT=5432 \ + PSQL_BABEL_DB_USER=jdbc_user \ + PSQL_BABEL_DB_PASSWORD=12345678 \ + PSQL_BABEL_DB_NAME=jdbc_testdb \ + ./build/main + + - name: Install Python + id: install-python + if: always() && steps.install-extensions.outcome == 'success' + uses: actions/setup-python@v2 + with: + python-version: 3.7 + + - name: Configure Python Environment + id: configure-python-environment + if: always() && steps.install-python.outcome == 'success' + run: | + cd ~ + curl https://packages.microsoft.com/config/ubuntu/20.04/prod.list | sudo tee /etc/apt/sources.list.d/mssql-release.list + cd ~/work/babelfish_extensions/babelfish_extensions/test/python + mkdir sqltoolsservice + cd sqltoolsservice + wget https://github.com/microsoft/sqltoolsservice/releases/download/4.4.0.12/Microsoft.SqlTools.ServiceLayer-rhel-x64-net6.0.tar.gz && tar -xzvf Microsoft.SqlTools.ServiceLayer-rhel-x64-net6.0.tar.gz + cd ../ + sudo ACCEPT_EULA=Y apt-get install -y msodbcsql17 python3-dev + pip3 install pyodbc==4.0.35 pymssql pytest pytest-xdist + + - name: Run Python Tests + if: always() && steps.configure-python-environment.outcome == 'success' + run: | + cd test/python + compareWithFile=true \ + driver=pyodbc \ + runInParallel=false \ + testName=all \ + provider="ODBC Driver 17 for SQL Server" \ + fileGenerator_URL=localhost \ + fileGenerator_port=1433 \ + fileGenerator_databaseName=master \ + fileGenerator_user=jdbc_user \ + fileGenerator_password=12345678 \ + pytest -s --tb=long -q . + + - name: Generate code coverage HTML report + id: code-coverage + if: always() + run: | + export PG_CONFIG=~/psql/bin/pg_config + export PG_SRC=~/work/postgresql_modified_for_babelfish + export cmake=$(which cmake) + cd contrib + for ext in babelfishpg_common babelfishpg_money babelfishpg_tds babelfishpg_tsql + do + cd $ext + /usr/bin/lcov --gcov-tool /usr/bin/gcov -q --no-external -c -i -d . -d ./ -o lcov_base.info + /usr/bin/lcov --gcov-tool /usr/bin/gcov -q --no-external -c -d . -d ./ -o lcov_test.info + rm -rf coverage + /usr/bin/genhtml -q --legend -o coverage --title='$ext' --ignore-errors source --num-spaces=4 lcov_base.info lcov_test.info + touch coverage-html-stamp + cd .. + done + shell: bash + + - name: Summarize code coverage + id: code-coverage-summary + if: always() + run: | + cd contrib/ + lcov -a babelfishpg_tsql/lcov_test.info -a babelfishpg_tds/lcov_test.info -a babelfishpg_common/lcov_test.info -a babelfishpg_money/lcov_test.info -o lcov.info + lcov --list lcov.info + - name: Upload Coverage Report for babelfishpg_tsql extension + if: always() + uses: actions/upload-artifact@v3 + with: + name: coverage_tsql_${{ matrix.branch }} + path: contrib/babelfishpg_tsql/coverage/ + + - name: Upload Coverage Report for babelfishpg_tds extension + if: always() + uses: actions/upload-artifact@v3 + with: + name: coverage_tds_${{ matrix.branch }} + path: contrib/babelfishpg_tds/coverage/ + + - name: Upload Coverage Report for babelfishpg_common extension + if: always() + uses: actions/upload-artifact@v3 + with: + name: coverage_common_${{ matrix.branch }} + path: contrib/babelfishpg_common/coverage/ + + - name: Upload Coverage Report for babelfishpg_money extension + if: always() + uses: actions/upload-artifact@v3 + with: + name: coverage_money_${{ matrix.branch }} + path: contrib/babelfishpg_money/coverage/ + + - name: Download CSV report from previous run + if: (github.event_name == 'schedule') + uses: dawidd6/action-download-artifact@v2 + with: + name: csv_${{ matrix.branch }} + path: contrib/ + search_artifacts: true + if_no_artifact_found: warn + + - name: Add latest coverage numbers to CSV file + if: (github.event_name == 'schedule') + run: | + cd contrib/ + paste -s -d, <(date +"%m/%d/%Y %H:%M:%S";lcov --summary lcov.info | grep -Po "[0-9]+\.[0-9]*") >> ${{ matrix.branch }}.csv + shell: bash + + - name: Upload CSV report with latest coverage numbers + if: (github.event_name == 'schedule') + uses: actions/upload-artifact@v3 + with: + name: csv_${{ matrix.branch }} + path: contrib/${{ matrix.branch }}.csv From 6d3550a77c4fa5d319652aff3d87f32e609d2ba2 Mon Sep 17 00:00:00 2001 From: pratikzode <73869399+pratikzode@users.noreply.github.com> Date: Thu, 30 Mar 2023 08:27:24 -0700 Subject: [PATCH 036/363] TES2_14 Moving Test to JDBC (#1367) * TES2_14 Moving Test to JDBC Moved babel_219, babel_collection, babel_datatype, babel_ddl, babel_delete1, babel_function, babel_like, babel_typecode, babel_uniqueidentifier babel_set_command babel_table_type babel_transaction babel_emoji to JDBC And removed it from babelfish_extensions/contrib/babelfishpg_tsql/sql/test directory Signed-off-by: pratikzode --- .../expected/test/babel_219.out | 84 - .../expected/test/babel_collation.out | 840 ----- .../expected/test/babel_datatype.out | 1477 -------- .../expected/test/babel_ddl.out | 323 -- .../expected/test/babel_delete.out | 294 -- .../expected/test/babel_like.out | 98 - .../expected/test/babel_set_command.out | 91 - .../expected/test/babel_transaction.out | 509 --- .../expected/test/babel_typecode.out | 40 - .../expected/test/babel_uniqueidentifier.out | 175 - .../babelfishpg_tsql/sql/test/babel_emoji.sql | 76 - .../babelfishpg_tsql/sql/test/babel_like.sql | 29 - .../sql/test/babel_set_command.sql | 57 - test/JDBC/expected/babel_219.out | 81 + test/JDBC/expected/babel_collection.out | 858 +++++ test/JDBC/expected/babel_datatype.out | 3083 +++++++++++++++++ test/JDBC/expected/babel_ddl.out | 399 +++ test/JDBC/expected/babel_delete1.out | 352 ++ test/JDBC/expected/babel_emoji.out | 184 + test/JDBC/expected/babel_function.out | 2861 +++++++++++++++ test/JDBC/expected/babel_like.out | 52 + .../expected/babel_select_distinct_top.out | 59 + test/JDBC/expected/babel_set_command.out | 68 + .../JDBC/expected/babel_table_type.out | 364 +- test/JDBC/expected/babel_transaction.out | 430 +++ test/JDBC/expected/babel_typecode.out | 40 + test/JDBC/expected/babel_uniqueidentifier.out | 323 ++ .../test => test/JDBC/input}/babel_219.sql | 35 +- .../JDBC/input/babel_collection.sql | 180 +- .../JDBC/input}/babel_datatype.sql | 849 +++-- .../test => test/JDBC/input}/babel_ddl.sql | 141 +- .../JDBC/input/babel_delete1.sql | 62 +- test/JDBC/input/babel_emoji.sql | 77 + .../JDBC/input}/babel_function.sql | 882 +++-- test/JDBC/input/babel_like.sql | 20 + test/JDBC/input/babel_select_distinct_top.sql | 19 + test/JDBC/input/babel_set_command.sql | 38 + .../JDBC/input/babel_table_type.sql | 358 +- .../JDBC/input}/babel_transaction.sql | 70 +- .../JDBC/input}/babel_typecode.sql | 5 +- .../JDBC/input}/babel_uniqueidentifier.sql | 90 +- .../expected_create.out | 2 - 42 files changed, 10567 insertions(+), 5508 deletions(-) delete mode 100644 contrib/babelfishpg_tsql/expected/test/babel_219.out delete mode 100644 contrib/babelfishpg_tsql/expected/test/babel_collation.out delete mode 100644 contrib/babelfishpg_tsql/expected/test/babel_datatype.out delete mode 100644 contrib/babelfishpg_tsql/expected/test/babel_ddl.out delete mode 100644 contrib/babelfishpg_tsql/expected/test/babel_delete.out delete mode 100644 contrib/babelfishpg_tsql/expected/test/babel_like.out delete mode 100644 contrib/babelfishpg_tsql/expected/test/babel_set_command.out delete mode 100644 contrib/babelfishpg_tsql/expected/test/babel_transaction.out delete mode 100644 contrib/babelfishpg_tsql/expected/test/babel_typecode.out delete mode 100644 contrib/babelfishpg_tsql/expected/test/babel_uniqueidentifier.out delete mode 100644 contrib/babelfishpg_tsql/sql/test/babel_emoji.sql delete mode 100644 contrib/babelfishpg_tsql/sql/test/babel_like.sql delete mode 100644 contrib/babelfishpg_tsql/sql/test/babel_set_command.sql create mode 100644 test/JDBC/expected/babel_219.out create mode 100644 test/JDBC/expected/babel_collection.out create mode 100644 test/JDBC/expected/babel_datatype.out create mode 100644 test/JDBC/expected/babel_ddl.out create mode 100644 test/JDBC/expected/babel_delete1.out create mode 100644 test/JDBC/expected/babel_emoji.out create mode 100644 test/JDBC/expected/babel_function.out create mode 100644 test/JDBC/expected/babel_like.out create mode 100644 test/JDBC/expected/babel_select_distinct_top.out create mode 100644 test/JDBC/expected/babel_set_command.out rename contrib/babelfishpg_tsql/sql/test/babel_table_type.sql => test/JDBC/expected/babel_table_type.out (72%) create mode 100644 test/JDBC/expected/babel_transaction.out create mode 100644 test/JDBC/expected/babel_typecode.out create mode 100644 test/JDBC/expected/babel_uniqueidentifier.out rename {contrib/babelfishpg_tsql/sql/test => test/JDBC/input}/babel_219.sql (59%) rename contrib/babelfishpg_tsql/sql/test/babel_collation.sql => test/JDBC/input/babel_collection.sql (58%) rename {contrib/babelfishpg_tsql/sql/test => test/JDBC/input}/babel_datatype.sql (70%) rename {contrib/babelfishpg_tsql/sql/test => test/JDBC/input}/babel_ddl.sql (74%) rename contrib/babelfishpg_tsql/sql/test/babel_delete.sql => test/JDBC/input/babel_delete1.sql (86%) create mode 100644 test/JDBC/input/babel_emoji.sql rename {contrib/babelfishpg_tsql/sql/test => test/JDBC/input}/babel_function.sql (50%) create mode 100644 test/JDBC/input/babel_like.sql create mode 100644 test/JDBC/input/babel_select_distinct_top.sql create mode 100644 test/JDBC/input/babel_set_command.sql rename contrib/babelfishpg_tsql/expected/test/babel_table_type.out => test/JDBC/input/babel_table_type.sql (57%) rename {contrib/babelfishpg_tsql/sql/test => test/JDBC/input}/babel_transaction.sql (81%) rename {contrib/babelfishpg_tsql/sql/test => test/JDBC/input}/babel_typecode.sql (75%) rename {contrib/babelfishpg_tsql/sql/test => test/JDBC/input}/babel_uniqueidentifier.sql (81%) diff --git a/contrib/babelfishpg_tsql/expected/test/babel_219.out b/contrib/babelfishpg_tsql/expected/test/babel_219.out deleted file mode 100644 index cdf9b9b5a1..0000000000 --- a/contrib/babelfishpg_tsql/expected/test/babel_219.out +++ /dev/null @@ -1,84 +0,0 @@ --- This test should be run without installing the babelfishpg_tsql extension --- BABEL-219 test a domain named varchar in schema other than sys --- is not affected by the fix of BABEL-219 -create domain public.varchar as pg_catalog.varchar(2) check (char_length(value) < 1); -select cast('a' as public.varchar); -- throw error -ERROR: value for domain public."varchar" violates check constraint "varchar_check" -select cast('' as public.varchar); - varchar ---------- - -(1 row) - -select cast('a' as varchar); -- pg_catalog.varchar should work - varchar ---------- - a -(1 row) - -show search_path; - search_path ------------------ - "$user", public -(1 row) - --- Explicitly add pg_catalog to tail of search_path, --- to force varchar default to public.varchar -select set_config('search_path', current_setting('search_path') || ', pg_catalog', false); - set_config ------------------------------ - "$user", public, pg_catalog -(1 row) - --- Set tsql dialet so the fix for BABEL-219 can kick in -SET babelfishpg_tsql.sql_dialect = 'tsql'; -select cast('a' as varchar); -- varchar default to public.varchar. should fail exactly the same way as explicitly specifying public.varchar -ERROR: value for domain "varchar" violates check constraint "varchar_check" -select cast('' as varchar); -- varchar default to public.varchar. should pass - varchar ---------- - -(1 row) - -create table t1(col varchar); -insert into t1 (col) select 'a'; -- fail -ERROR: value for domain "varchar" violates check constraint "varchar_check" -insert into t1 (col) select ''; -- pass -select * from t1; - col ------ - -(1 row) - --- verify behavior of public.varchar is unchanged in tsql dialect -select cast('a' as public.varchar); -- fail -ERROR: value for domain "varchar" violates check constraint "varchar_check" -select cast('' as public.varchar); -- pass - varchar ---------- - -(1 row) - -create table t2(col public.varchar); -insert into t1 (col) select 'a'; -- fail -ERROR: value for domain "varchar" violates check constraint "varchar_check" -insert into t1 (col) select ''; -- pass -select * from t1; - col ------ - - -(2 rows) - --- Clean up -drop table t1; -drop table t2; -set babelfishpg_tsql.sql_dialect = 'postgres'; --- Reset search_path -set search_path to "$user", public; -show search_path; - search_path ------------------ - "$user", public -(1 row) - diff --git a/contrib/babelfishpg_tsql/expected/test/babel_collation.out b/contrib/babelfishpg_tsql/expected/test/babel_collation.out deleted file mode 100644 index ff13367fc3..0000000000 --- a/contrib/babelfishpg_tsql/expected/test/babel_collation.out +++ /dev/null @@ -1,840 +0,0 @@ --- nvarchar is not supported in PG -create table testing1(col nvarchar(60)); -- expect this to fail in the Postgres dialect -ERROR: type "nvarchar" does not exist -LINE 1: create table testing1(col nvarchar(60)); - ^ -CREATE EXTENSION IF NOT EXISTS "babelfishpg_tsql" CASCADE; -NOTICE: extension "babelfishpg_tsql" already exists, skipping -set babelfishpg_tsql.sql_dialect = "tsql"; --- check the babelfish version -select cast( - case - when cast(sys.SERVERPROPERTY('BabelfishVersion') as varchar(20)) LIKE '_._._' - THEN 'valid' - else 'invalid' - end as sys.varchar(20)); - varchar ---------- - valid -(1 row) - --- nvarchar is supported in tsql dialect -create table testing1(col nvarchar(60)); -insert into testing1 (col) select N'Muffler'; -insert into testing1 (col) select N'Mülle'; -insert into testing1 (col) select N'MX Systems'; -insert into testing1 (col) select N'Magic'; -select * from testing1 order by col; - col ------------- - Magic - Muffler - Mülle - MX Systems -(4 rows) - --- test case insensitive collation -create table testing2 (col varchar(20) collate SQL_Latin1_General_CP1_CI_AS); -insert into testing2 values ('JONES'); -insert into testing2 values ('jones'); -insert into testing2 values ('Jones'); -insert into testing2 values ('JoNes'); -insert into testing2 values ('JoNés'); -select * from testing2 where col collate BBF_Unicode_General_CS_AS = 'JoNes'; - col -------- - JoNes -(1 row) - -select * from testing2 where col collate BBF_Unicode_General_CI_AS = 'JoNes'; - col -------- - JONES - jones - Jones - JoNes -(4 rows) - -select * from testing2 where col collate BBF_Unicode_General_CI_AI = 'JoNes'; - col -------- - JONES - jones - Jones - JoNes - JoNés -(5 rows) - -select * from testing2 where col collate BBF_Unicode_General_CS_AI = 'JoNes'; - col -------- - JoNes - JoNés -(2 rows) - --- test case insensitivity for default collation -create table testing3 (c1 varchar(20), c2 char(20), c3 nvarchar(20)); -reset babelfishpg_tsql.sql_dialect; -\d testing3 - Table "public.testing3" - Column | Type | Collation | Nullable | Default ---------+-------------------+-----------+----------+--------- - c1 | sys."varchar"(20) | | | - c2 | sys.bpchar(20) | | | - c3 | sys.nvarchar(20) | | | - -set babelfishpg_tsql.sql_dialect = "tsql"; -insert into testing3 values ('JONES','JONES','JONES'); -insert into testing3 values ('JoneS','JoneS','JoneS'); -insert into testing3 values ('jOnes','jOnes','jOnes'); -select c1 from testing3 where c1='jones'; - c1 -------- - JONES - JoneS - jOnes -(3 rows) - -select c2 from testing3 where c2='jones'; - c2 ----------------------- - JONES - JoneS - jOnes -(3 rows) - -select c3 from testing3 where c3='jones'; - c3 -------- - JONES - JoneS - jOnes -(3 rows) - --- test LIKE to ILIKE transformation -create table testing4 (c1 varchar(20), c2 char(20), c3 nvarchar(20)); -create index c1_idx on testing4 (c1); -insert into testing4 values ('JONES','JONES','JONES'); -insert into testing4 values ('JoneS','JoneS','JoneS'); -insert into testing4 values ('jOnes','jOnes','jOnes'); -insert into testing4 values ('abcD','AbcD','ABCd'); -insert into testing4 values ('äbĆD','äḃcD','äƀCd'); --- set enable_seqscan doesn't work from the TSQL dialect, so switch --- dialects, disable sequential scan so we see some index-based plans, --- then switch back to the TSQL dialect --- -reset babelfishpg_tsql.sql_dialect; -set enable_seqscan = false; -set babelfishpg_tsql.sql_dialect = "tsql"; --- test that like is case-insenstive -select c1 from testing4 where c1 LIKE 'jones'; -- this gets converted to '=' - c1 -------- - JONES - JoneS - jOnes -(3 rows) - -explain (costs false) select c1 from testing4 where c1 LIKE 'jones'; - QUERY PLAN ---------------------------------------------------------------------------- - Bitmap Heap Scan on testing4 - Filter: ((c1)::text = 'jones'::text) - -> Bitmap Index Scan on c1_idxtesting49a168d73f3ba5aacdfd495b931b8d187 -(3 rows) - -select c1 from testing4 where c1 LIKE 'Jon%'; - c1 -------- - JONES - JoneS - jOnes -(3 rows) - -explain (costs false) select c1 from testing4 where c1 LIKE 'Jon%'; - QUERY PLAN ------------------------------------------------------------------------------------------------------------ - Bitmap Heap Scan on testing4 - Filter: (((c1)::text ~~* 'Jon%'::text) AND ((c1)::text >= 'Jon'::text) AND ((c1)::text < 'Jonï¿¿'::text)) - -> Bitmap Index Scan on c1_idxtesting49a168d73f3ba5aacdfd495b931b8d187 -(3 rows) - -select c1 from testing4 where c1 LIKE 'jone_'; - c1 -------- - JONES - JoneS - jOnes -(3 rows) - -explain (costs false) select c1 from testing4 where c1 LIKE 'jone_'; - QUERY PLAN --------------------------------------------------------------------------------------------------------------- - Bitmap Heap Scan on testing4 - Filter: (((c1)::text ~~* 'jone_'::text) AND ((c1)::text >= 'jone'::text) AND ((c1)::text < 'joneï¿¿'::text)) - -> Bitmap Index Scan on c1_idxtesting49a168d73f3ba5aacdfd495b931b8d187 -(3 rows) - -select c1 from testing4 where c1 LIKE '_one_'; - c1 -------- - JONES - JoneS - jOnes -(3 rows) - -explain (costs false) select c1 from testing4 where c1 LIKE '_one_'; - QUERY PLAN ---------------------------------------------------------------------------- - Bitmap Heap Scan on testing4 - Filter: ((c1)::text ~~* '_one_'::text) - -> Bitmap Index Scan on c1_idxtesting49a168d73f3ba5aacdfd495b931b8d187 -(3 rows) - -select c1 from testing4 where c1 LIKE '%on%s'; - c1 -------- - JONES - JoneS - jOnes -(3 rows) - -explain (costs false) select c1 from testing4 where c1 LIKE '%on%s'; - QUERY PLAN ---------------------------------------------------------------------------- - Bitmap Heap Scan on testing4 - Filter: ((c1)::text ~~* '%on%s'::text) - -> Bitmap Index Scan on c1_idxtesting49a168d73f3ba5aacdfd495b931b8d187 -(3 rows) - --- test that like is accent-senstive for CI_AS collation -select c1 from testing4 where c1 LIKE 'ab%'; - c1 ------- - abcD -(1 row) - -select c1 from testing4 where c1 LIKE 'äb%'; - c1 ------- - äbĆD -(1 row) - -select c1 from testing4 where c1 LIKE 'äḃĆ_'; - c1 ----- -(0 rows) - --- test not like -select c1 from testing4 where c1 NOT LIKE 'jones'; - c1 ------- - abcD - äbĆD -(2 rows) - -explain (costs false) select c1 from testing4 where c1 NOT LIKE 'jones'; - QUERY PLAN ---------------------------------------------------------------------------- - Bitmap Heap Scan on testing4 - Filter: ((c1)::text <> 'jones'::text) - -> Bitmap Index Scan on c1_idxtesting49a168d73f3ba5aacdfd495b931b8d187 -(3 rows) - -select c1 from testing4 where c1 NOT LIKE 'jone%'; - c1 ------- - abcD - äbĆD -(2 rows) - -explain (costs false) select c1 from testing4 where c1 NOT LIKE 'jone%'; - QUERY PLAN -------------------------------------------------------------------------------------------------------------- - Bitmap Heap Scan on testing4 - Filter: (((c1)::text !~~* 'jone%'::text) OR ((c1)::text < 'jone'::text) OR ((c1)::text >= 'joneï¿¿'::text)) - -> Bitmap Index Scan on c1_idxtesting49a168d73f3ba5aacdfd495b931b8d187 -(3 rows) - -select c1 from testing4 where c1 NOT LIKE 'ä%'; - c1 -------- - JONES - JoneS - jOnes - abcD -(4 rows) - -explain (costs false) select c1 from testing4 where c1 NOT LIKE 'ä%'; - QUERY PLAN ----------------------------------------------------------------------------------------------------- - Bitmap Heap Scan on testing4 - Filter: (((c1)::text !~~* 'ä%'::text) OR ((c1)::text < 'ä'::text) OR ((c1)::text >= 'ä￿'::text)) - -> Bitmap Index Scan on c1_idxtesting49a168d73f3ba5aacdfd495b931b8d187 -(3 rows) - --- test escape function and wildcard literal -select c1 from testing4 where c1 LIKE E'\_ones'; - c1 -------- - JONES - JoneS - jOnes -(3 rows) - -explain (costs false) select c1 from testing4 where c1 LIKE E'\_ones'; - QUERY PLAN ---------------------------------------------------------------------------- - Bitmap Heap Scan on testing4 - Filter: ((c1)::text ~~* '_ones'::text) - -> Bitmap Index Scan on c1_idxtesting49a168d73f3ba5aacdfd495b931b8d187 -(3 rows) - -select c1 from testing4 where c1 LIKE E'\%ones'; - c1 -------- - JONES - JoneS - jOnes -(3 rows) - -explain (costs false) select c1 from testing4 where c1 LIKE E'\%ones'; - QUERY PLAN ---------------------------------------------------------------------------- - Bitmap Heap Scan on testing4 - Filter: ((c1)::text ~~* '%ones'::text) - -> Bitmap Index Scan on c1_idxtesting49a168d73f3ba5aacdfd495b931b8d187 -(3 rows) - --- wild card literals are transformed to equal -select c1 from testing4 where c1 LIKE '\%ones'; - c1 ----- -(0 rows) - -explain(costs false) select c1 from testing4 where c1 LIKE '\%ones'; - QUERY PLAN ---------------------------------------------------------------------------- - Bitmap Heap Scan on testing4 - Filter: ((c1)::text = '%ones'::text) - -> Bitmap Index Scan on c1_idxtesting49a168d73f3ba5aacdfd495b931b8d187 -(3 rows) - -select c1 from testing4 where c1 LIKE '\_ones'; - c1 ----- -(0 rows) - -explain(costs false) select c1 from testing4 where c1 LIKE '\_ones'; - QUERY PLAN ---------------------------------------------------------------------------- - Bitmap Heap Scan on testing4 - Filter: ((c1)::text = '_ones'::text) - -> Bitmap Index Scan on c1_idxtesting49a168d73f3ba5aacdfd495b931b8d187 -(3 rows) - --- test combining with other string functions -select c1 from testing4 where c1 LIKE lower('_ones'); - c1 -------- - JONES - JoneS - jOnes -(3 rows) - -select c1 from testing4 where c1 LIKE upper('_ones'); - c1 -------- - JONES - JoneS - jOnes -(3 rows) - -select c1 from testing4 where c1 LIKE concat('_on','_s'); - c1 -------- - JONES - JoneS - jOnes -(3 rows) - -select c1 from testing4 where c1 LIKE concat('a','%d'); - c1 ------- - abcD -(1 row) - -select c1 from testing4 where c1 NOT LIKE lower('%s'); - c1 ------- - abcD - äbĆD -(2 rows) - --- test sub-queries -Select * from testing4 where c1 LIKE (select c1 from testing4 where c1 LIKE 'AbcD'); - c1 | c2 | c3 -------+----------------------+------ - abcD | AbcD | ABCd -(1 row) - -Select * from testing4 where c2 NOT LIKE (select c2 from testing4 where c2 NOT LIKE 'jo%' AND c2 NOT LIKE 'ä%'); - c1 | c2 | c3 --------+----------------------+------- - JONES | JONES | JONES - JoneS | JoneS | JoneS - jOnes | jOnes | jOnes - äbĆD | äḃcD | äƀCd -(4 rows) - -Select * from testing4 where c3 LIKE (select c3 from testing4 where c3 NOT LIKE'jo%' AND c3 NOT LIKE 'ä%'); - c1 | c2 | c3 -------+----------------------+------ - abcD | AbcD | ABCd -(1 row) - -with p1 as (select c1 from testing4 where c1 LIKE '__Ć_'), -p2 as (select c3 from testing4 where c3 LIKE 'äƀ__') -select * from p1 union all select * from p2; - c1 ------- - äbĆD - äƀCd -(2 rows) - --- test case expression -select c1,(case c1 LIKE 'j%' when true then 1 when false then 2 end) from testing4; - c1 | case --------+------ - JONES | 1 - JoneS | 1 - jOnes | 1 - abcD | 2 - äbĆD | 2 -(5 rows) - -select c2,(case when c2 LIKE '_bc%' then 1 when c2 LIKE 'jon%' then 2 when c3 LIKE 'ä%' then 3 end) from testing4; - c2 | case -----------------------+------ - JONES | 2 - JoneS | 2 - jOnes | 2 - AbcD | 1 - äḃcD | 3 -(5 rows) - --- test that LIKE transformation is applied only for CI_AS column -create table testing5(c1 varchar(20) COLLATE SQL_Latin1_General_CP1_CS_AS); -insert into testing5 values ('JONES'); -insert into testing5 values ('JoneS'); -insert into testing5 values ('abcD'); -insert into testing5 values ('äbĆD'); -select * from testing5 where c1 LIKE 'jo%'; -- does not use the transformation - c1 ----- -(0 rows) - -explain(costs false) select * from testing5 where c1 LIKE 'jo%'; - QUERY PLAN ---------------------------------------- - Seq Scan on testing5 - Filter: ((c1)::text ~~ 'jo%'::text) -(2 rows) - -select * from testing5 where c1 NOT LIKE 'j%'; - c1 -------- - JONES - JoneS - abcD - äbĆD -(4 rows) - -select * from testing5 where c1 LIKE 'AB%'; - c1 ----- -(0 rows) - --- test explicitly specify collation as CI_AS, like transformation is also applied. -SELECT 'JONES' like 'jo%'; - ?column? ----------- - t -(1 row) - -SELECT 'JONES' COLLATE SQL_Latin1_General_CP1_CI_AS like 'jo%' ; - ?column? ----------- - t -(1 row) - --- test when pattern is empty string or NULL -SELECT 'JONES' like ''; - ?column? ----------- - f -(1 row) - -SELECT 'JONES' like NULL; - ?column? ----------- - -(1 row) - -SELECT * from testing5 where c1 like ''; - c1 ----- -(0 rows) - -explain (costs false) SELECT * from testing5 where c1 like ''; - QUERY PLAN ------------------------------------- - Seq Scan on testing5 - Filter: ((c1)::text ~~ ''::text) -(2 rows) - -SELECT * from testing5 where c1 like NULL; - c1 ----- -(0 rows) - -explain (costs false) SELECT * from testing5 where c1 like NULL; - QUERY PLAN --------------------------- - Result - One-Time Filter: false -(2 rows) - -SELECT * FROM testing5 where c1 COLLATE French_CI_AS like 'jo%' ; - c1 -------- - JONES - JoneS -(2 rows) - -explain (costs false) SELECT * FROM testing5 where c1 COLLATE French_CI_AS like 'jo%' ; - QUERY PLAN --------------------------------------------------------------------------------------------------------- - Seq Scan on testing5 - Filter: (((c1)::text ~~* 'jo%'::text) AND ((c1)::text >= 'jo'::text) AND ((c1)::text < 'joï¿¿'::text)) -(2 rows) - -SELECT * FROM testing5 where c1 COLLATE Chinese_PRC_CI_AS like 'jo%' ; - c1 -------- - JONES - JoneS -(2 rows) - -explain (costs false) SELECT * FROM testing5 where c1 COLLATE Chinese_PRC_CI_AS like 'jo%' ; - QUERY PLAN --------------------------------------------------------------------------------------------------------- - Seq Scan on testing5 - Filter: (((c1)::text ~~* 'jo%'::text) AND ((c1)::text >= 'jo'::text) AND ((c1)::text < 'joï¿¿'::text)) -(2 rows) - --- tsql collations -alter table testing1 alter column col nvarchar(60) collate Arabic_CS_AS; -alter table testing1 alter column col nvarchar(60) collate Chinese_PRC_CS_AS; -alter table testing1 alter column col nvarchar(60) collate Cyrillic_General_CS_AS; -alter table testing1 alter column col nvarchar(60) collate French_CS_AS; -alter table testing1 alter column col nvarchar(60) collate Korean_Wansung_CS_AS; -alter table testing1 alter column col nvarchar(60) collate Traditional_Spanish_CS_AS; -alter table testing1 alter column col nvarchar(60) collate Modern_Spanish_CS_AS; -alter table testing1 alter column col nvarchar(60) collate SQL_Latin1_General_CP1_CS_AS; -alter table testing1 alter column col nvarchar(60) collate SQL_Latin1_General_CP1_CI_AS; -alter table testing1 alter column col nvarchar(60) collate Traditional_Spanish_CS_AS; -alter table testing1 alter column col nvarchar(60) collate Thai_CS_AS; -alter table testing1 alter column col nvarchar(60) collate Turkish_CS_AS; -alter table testing1 alter column col nvarchar(60) collate Ukrainian_CS_AS; -alter table testing1 alter column col nvarchar(60) collate Vietnamese_CS_AS; -alter table testing1 alter column col nvarchar(60) collate Finnish_Swedish_CS_AS; --- expect different result order from previous select -select * from testing1 order by col; - col ------------- - Magic - Muffler - MX Systems - Mülle -(4 rows) - --- test expression level collate, expect the same result order -select * from testing1 order by col collate Finnish_Swedish_CS_AS; - col ------------- - Magic - Muffler - MX Systems - Mülle -(4 rows) - --- test catalog -select * from sys.fn_helpcollations(); - name | description ------------------------------------+------------------------------------------------------------------------------------------------------------------------------------- - arabic_cs_as | Arabic, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - arabic_ci_ai | Arabic, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive - arabic_ci_as | Arabic, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - bbf_unicode_bin2 | Unicode-General, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1250_ci_ai | Default locale, code page 1250, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1250_ci_as | Default locale, code page 1250, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1250_cs_ai | Default locale, code page 1250, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1250_cs_as | Default locale, code page 1250, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - bbf_unicode_pref_cp1250_cs_as | Default locale, code page 1250, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first - bbf_unicode_cp1251_ci_ai | Default locale, code page 1251, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1251_ci_as | Default locale, code page 1251, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1251_cs_ai | Default locale, code page 1251, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1251_cs_as | Default locale, code page 1251, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - bbf_unicode_pref_cp1251_cs_as | Default locale, code page 1251, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first - bbf_unicode_cp1253_ci_ai | Default locale, code page 1253, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1253_ci_as | Default locale, code page 1253, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1253_cs_ai | Default locale, code page 1253, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1253_cs_as | Default locale, code page 1253, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - bbf_unicode_pref_cp1253_cs_as | Default locale, code page 1253, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first - bbf_unicode_cp1254_ci_ai | Default locale, code page 1254, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1254_ci_as | Default locale, code page 1254, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1254_cs_ai | Default locale, code page 1254, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1254_cs_as | Default locale, code page 1254, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - bbf_unicode_pref_cp1254_cs_as | Default locale, code page 1254, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first - bbf_unicode_cp1255_ci_ai | Default locale, code page 1255, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1255_ci_as | Default locale, code page 1255, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1255_cs_ai | Default locale, code page 1255, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1255_cs_as | Default locale, code page 1255, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - bbf_unicode_pref_cp1255_cs_as | Default locale, code page 1255, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first - bbf_unicode_cp1256_ci_ai | Default locale, code page 1256, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1256_ci_as | Default locale, code page 1256, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1256_cs_ai | Default locale, code page 1256, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1256_cs_as | Default locale, code page 1256, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - bbf_unicode_pref_cp1256_cs_as | Default locale, code page 1256, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first - bbf_unicode_cp1257_ci_ai | Default locale, code page 1257, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1257_ci_as | Default locale, code page 1257, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1257_cs_ai | Default locale, code page 1257, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1257_cs_as | Default locale, code page 1257, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - bbf_unicode_pref_cp1257_cs_as | Default locale, code page 1257, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first - bbf_unicode_cp1258_ci_ai | Default locale, code page 1258, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1258_ci_as | Default locale, code page 1258, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1258_cs_ai | Default locale, code page 1258, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1258_cs_as | Default locale, code page 1258, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - bbf_unicode_pref_cp1258_cs_as | Default locale, code page 1258, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first - bbf_unicode_cp1_ci_ai | Default locale, code page 1252, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1_ci_as | Default locale, code page 1252, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1_cs_ai | Default locale, code page 1252, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp1_cs_as | Default locale, code page 1252, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - bbf_unicode_pref_cp1_cs_as | Default locale, code page 1252, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first - bbf_unicode_cp847_ci_ai | Default locale, code page 847, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp847_ci_as | Default locale, code page 847, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp847_cs_ai | Default locale, code page 847, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive - bbf_unicode_cp847_cs_as | Default locale, code page 847, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - bbf_unicode_pref_cp847_cs_as | Default locale, code page 847, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first - bbf_unicode_general_ci_ai | Default locale, default code page, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive - bbf_unicode_general_ci_as | Default locale, default code page, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - bbf_unicode_general_cs_ai | Default locale, default code page, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive - bbf_unicode_general_cs_as | Default locale, default code page, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - bbf_unicode_general_pref_cs_as | Default locale, default code page, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first - chinese_prc_cs_as | Chinese-PRC, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - chinese_prc_ci_ai | Chinese-PRC, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive - chinese_prc_ci_as | Chinese-PRC, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - cyrillic_general_cs_as | Cyrillic-General, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - cyrillic_general_ci_ai | Cyrillic-General, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive - cyrillic_general_ci_as | Cyrillic-General, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - finnish_swedish_cs_as | Finnish-Swedish, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - finnish_swedish_ci_as | Finnish-Swedish, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - finnish_swedish_ci_ai | Finnish-Swedish, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive - french_cs_as | French, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - french_ci_as | French, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - french_ci_ai | French, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive - korean_wansung_cs_as | Korean-Wansung, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - korean_wansung_ci_as | Korean-Wansung, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - korean_wansung_ci_ai | Korean-Wansung, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive - latin1_general_bin2 | Virtual, Unicode-General, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - latin1_general_90_bin2 | Virtual, Unicode-General, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - latin1_general_100_bin2 | Virtual, Unicode-General, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - latin1_general_140_bin2 | Virtual, Unicode-General, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - latin1_general_ci_ai | Virtual, default locale, code page 1252, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive - latin1_general_ci_as | Virtual, default locale, code page 1252, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - latin1_general_cs_ai | Virtual, default locale, code page 1252, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive - latin1_general_cs_as | Virtual, default locale, code page 1252, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - modern_spanish_cs_as | Traditional-Spanish, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - modern_spanish_ci_as | Traditional-Spanish, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - modern_spanish_ci_ai | Traditional-Spanish, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive - polish_cs_as | Polish, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - polish_ci_as | Polish, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - polish_ci_ai | Polish, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive - sql_latin1_general_cp1250_ci_as | Virtual, default locale, code page 1250, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - sql_latin1_general_cp1250_cs_as | Virtual, default locale, code page 1250, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - sql_latin1_general_cp1251_ci_as | Virtual, default locale, code page 1251, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - sql_latin1_general_cp1251_cs_as | Virtual, default locale, code page 1251, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - sql_latin1_general_cp1_ci_ai | Virtual, default locale, code page 1252, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive - sql_latin1_general_cp1_ci_as | Virtual, default locale, code page 1252, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - sql_latin1_general_cp1_ci_ai | Virtual, default locale, code page 1252, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive - sql_latin1_general_cp1_cs_as | Virtual, default locale, code page 1252, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - sql_latin1_general_pref_cp1_cs_as | Virtual, default locale, code page 1252, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first - sql_latin1_general_cp1253_ci_as | Virtual, default locale, code page 1253, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - sql_latin1_general_cp1253_cs_as | Virtual, default locale, code page 1253, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - sql_latin1_general_cp1254_ci_as | Virtual, default locale, code page 1254, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - sql_latin1_general_cp1254_cs_as | Virtual, default locale, code page 1255, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - sql_latin1_general_cp1255_ci_as | Virtual, default locale, code page 1255, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - sql_latin1_general_cp1255_cs_as | Virtual, default locale, code page 1255, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - sql_latin1_general_cp1256_ci_as | Virtual, default locale, code page 1256, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - sql_latin1_general_cp1256_cs_as | Virtual, default locale, code page 1256, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - sql_latin1_general_cp1257_ci_as | Virtual, default locale, code page 1257, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - sql_latin1_general_cp1257_cs_as | Virtual, default locale, code page 1257, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - sql_latin1_general_cp1258_ci_as | Virtual, default locale, code page 1258, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - sql_latin1_general_cp1258_cs_as | Virtual, default locale, code page 1258, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - thai_cs_as | Thai, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - thai_ci_as | Thai, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - thai_ci_ai | Thai, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive - traditional_spanish_cs_as | Traditional-Spanish, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - traditional_spanish_ci_as | Traditional-Spanish, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - traditional_spanish_ci_ai | Traditional-Spanish, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive - turkish_cs_as | Turkish, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - turkish_ci_as | Turkish, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - turkish_ci_ai | Turkish, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive - ukrainian_cs_as | Ukrainian, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - ukrainian_ci_as | Ukrainian, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - ukrainian_ci_ai | Ukrainian, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive - vietnamese_cs_as | Vietnamese, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive - vietnamese_ci_as | Vietnamese, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive - vietnamese_ci_ai | Vietnamese, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive -(124 rows) - --- test the TYPE keyword is only required in postgres dialect, but not in tsql dialect -alter table testing1 alter column col varchar(60) collate Finnish_Swedish_CS_AS; -alter table testing1 alter column col TYPE varchar(60) collate Finnish_Swedish_CS_AS; -SELECT set_config('babelfishpg_tsql.sql_dialect', 'postgres', false); - set_config ------------- - postgres -(1 row) - -alter table testing1 alter column col varchar(60) collate sys.Finnish_Swedish_CS_AS; -ERROR: syntax error at or near "varchar" -LINE 1: alter table testing1 alter column col varchar(60) collate sy... - ^ -alter table testing1 alter column col TYPE varchar(60) collate sys.Finnish_Swedish_CS_AS; -SELECT set_config('babelfishpg_tsql.sql_dialect', 'tsql', false); - set_config ------------- - tsql -(1 row) - --- test collation list sys table -SELECT collation_name, l1_priority, l2_priority, l3_priority, l4_priority, l5_priority FROM sys.babelfish_collation_list() order by collation_name; - collation_name | l1_priority | l2_priority | l3_priority | l4_priority | l5_priority ---------------------------------+-------------+-------------+-------------+-------------+------------- - arabic_ci_ai | 1025 | 0 | 196608 | 0 | 15 - arabic_ci_as | 1025 | 0 | 196608 | 0 | 13 - arabic_cs_as | 1025 | 0 | 196608 | 0 | 12 - bbf_unicode_bin2 | 1033 | 0 | 196608 | 54 | 544 - bbf_unicode_cp1250_ci_ai | 1045 | 0 | 196608 | 54 | 15 - bbf_unicode_cp1250_ci_as | 1045 | 0 | 196608 | 52 | 13 - bbf_unicode_cp1250_cs_ai | 1045 | 0 | 196608 | 51 | 14 - bbf_unicode_cp1250_cs_as | 1045 | 0 | 196608 | 51 | 12 - bbf_unicode_cp1251_ci_ai | 1049 | 0 | 196608 | 54 | 15 - bbf_unicode_cp1251_ci_as | 1049 | 0 | 196608 | 52 | 13 - bbf_unicode_cp1251_cs_ai | 1049 | 0 | 196608 | 51 | 14 - bbf_unicode_cp1251_cs_as | 1049 | 0 | 196608 | 51 | 12 - bbf_unicode_cp1253_ci_ai | 1032 | 0 | 196608 | 54 | 15 - bbf_unicode_cp1253_ci_as | 1032 | 0 | 196608 | 52 | 13 - bbf_unicode_cp1253_cs_ai | 1032 | 0 | 196608 | 51 | 14 - bbf_unicode_cp1253_cs_as | 1032 | 0 | 196608 | 51 | 12 - bbf_unicode_cp1254_ci_ai | 1055 | 0 | 196608 | 54 | 15 - bbf_unicode_cp1254_ci_as | 1055 | 0 | 196608 | 52 | 13 - bbf_unicode_cp1254_cs_ai | 1055 | 0 | 196608 | 51 | 14 - bbf_unicode_cp1254_cs_as | 1055 | 0 | 196608 | 51 | 12 - bbf_unicode_cp1255_ci_ai | 1037 | 0 | 196608 | 54 | 15 - bbf_unicode_cp1255_ci_as | 1037 | 0 | 196608 | 52 | 13 - bbf_unicode_cp1255_cs_ai | 1037 | 0 | 196608 | 51 | 14 - bbf_unicode_cp1255_cs_as | 1037 | 0 | 196608 | 51 | 12 - bbf_unicode_cp1256_ci_ai | 1025 | 0 | 196608 | 54 | 15 - bbf_unicode_cp1256_ci_as | 1025 | 0 | 196608 | 52 | 13 - bbf_unicode_cp1256_cs_ai | 1025 | 0 | 196608 | 51 | 14 - bbf_unicode_cp1256_cs_as | 1025 | 0 | 196608 | 51 | 12 - bbf_unicode_cp1257_ci_ai | 1061 | 0 | 196608 | 54 | 15 - bbf_unicode_cp1257_ci_as | 1061 | 0 | 196608 | 52 | 13 - bbf_unicode_cp1257_cs_ai | 1061 | 0 | 196608 | 51 | 14 - bbf_unicode_cp1257_cs_as | 1061 | 0 | 196608 | 51 | 12 - bbf_unicode_cp1258_ci_ai | 1066 | 0 | 196608 | 54 | 15 - bbf_unicode_cp1258_ci_as | 1066 | 0 | 196608 | 52 | 13 - bbf_unicode_cp1258_cs_ai | 1066 | 0 | 196608 | 51 | 14 - bbf_unicode_cp1258_cs_as | 1066 | 0 | 196608 | 51 | 12 - bbf_unicode_cp1_ci_ai | 1033 | 0 | 196608 | 54 | 15 - bbf_unicode_cp1_ci_as | 1033 | 0 | 196608 | 52 | 13 - bbf_unicode_cp1_cs_ai | 1033 | 0 | 196608 | 51 | 14 - bbf_unicode_cp1_cs_as | 1033 | 0 | 196608 | 51 | 12 - bbf_unicode_cp874_ci_ai | 1054 | 0 | 196608 | 54 | 15 - bbf_unicode_cp874_ci_as | 1054 | 0 | 196608 | 52 | 13 - bbf_unicode_cp874_cs_ai | 1054 | 0 | 196608 | 51 | 14 - bbf_unicode_cp874_cs_as | 1054 | 0 | 196608 | 51 | 12 - bbf_unicode_general_ci_ai | 1033 | 0 | 196608 | 54 | 15 - bbf_unicode_general_ci_as | 1033 | 0 | 196608 | 52 | 13 - bbf_unicode_general_cs_ai | 1033 | 0 | 196608 | 51 | 14 - bbf_unicode_general_cs_as | 1033 | 0 | 196608 | 51 | 12 - bbf_unicode_general_pref_cs_as | 1033 | 0 | 196608 | 51 | 12 - bbf_unicode_pref_cp1250_cs_as | 1045 | 0 | 196608 | 51 | 12 - bbf_unicode_pref_cp1251_cs_as | 1049 | 0 | 196608 | 51 | 12 - bbf_unicode_pref_cp1253_cs_as | 1032 | 0 | 196608 | 51 | 12 - bbf_unicode_pref_cp1254_cs_as | 1055 | 0 | 196608 | 51 | 12 - bbf_unicode_pref_cp1255_cs_as | 1037 | 0 | 196608 | 51 | 12 - bbf_unicode_pref_cp1256_cs_as | 1025 | 0 | 196608 | 51 | 12 - bbf_unicode_pref_cp1257_cs_as | 1061 | 0 | 196608 | 51 | 12 - bbf_unicode_pref_cp1258_cs_as | 1066 | 0 | 196608 | 51 | 12 - bbf_unicode_pref_cp1_cs_as | 1033 | 0 | 196608 | 51 | 12 - bbf_unicode_pref_cp874_cs_as | 1054 | 0 | 196608 | 51 | 12 - chinese_prc_ci_ai | 2052 | 0 | 196608 | 0 | 15 - chinese_prc_ci_as | 2052 | 0 | 196608 | 0 | 13 - chinese_prc_cs_as | 2052 | 0 | 196608 | 0 | 12 - cyrillic_general_ci_ai | 1049 | 0 | 196608 | 0 | 15 - cyrillic_general_ci_as | 1049 | 0 | 196608 | 0 | 13 - cyrillic_general_cs_as | 1049 | 0 | 196608 | 0 | 12 - estonian_ci_ai | 1061 | 0 | 196608 | 0 | 15 - estonian_ci_as | 1061 | 0 | 196608 | 0 | 13 - estonian_cs_as | 1061 | 0 | 196608 | 0 | 12 - finnish_swedish_ci_ai | 1035 | 0 | 196608 | 0 | 15 - finnish_swedish_ci_as | 1035 | 0 | 196608 | 0 | 13 - finnish_swedish_cs_as | 1035 | 0 | 196608 | 0 | 12 - french_ci_ai | 1036 | 0 | 196608 | 0 | 15 - french_ci_as | 1036 | 0 | 196608 | 0 | 13 - french_cs_as | 1036 | 0 | 196608 | 0 | 12 - greek_ci_ai | 1032 | 0 | 196608 | 0 | 15 - greek_ci_as | 1032 | 0 | 196608 | 0 | 13 - greek_cs_as | 1032 | 0 | 196608 | 0 | 12 - hebrew_ci_ai | 1037 | 0 | 196608 | 0 | 15 - hebrew_ci_as | 1037 | 0 | 196608 | 0 | 13 - hebrew_cs_as | 1037 | 0 | 196608 | 0 | 12 - korean_wansung_ci_ai | 1042 | 0 | 196608 | 0 | 15 - korean_wansung_ci_as | 1042 | 0 | 196608 | 0 | 13 - korean_wansung_cs_as | 1042 | 0 | 196608 | 0 | 12 - modern_spanish_ci_ai | 3082 | 0 | 196608 | 0 | 15 - modern_spanish_ci_as | 3082 | 0 | 196608 | 0 | 13 - modern_spanish_cs_as | 3082 | 0 | 196608 | 0 | 12 - mongolian_ci_ai | 1104 | 0 | 196608 | 0 | 15 - mongolian_ci_as | 1104 | 0 | 196608 | 52 | 13 - mongolian_cs_as | 1104 | 0 | 196608 | 51 | 12 - polish_ci_ai | 1045 | 0 | 196608 | 0 | 15 - polish_ci_as | 1045 | 0 | 196608 | 0 | 13 - polish_cs_as | 1045 | 0 | 196608 | 0 | 12 - thai_ci_ai | 1054 | 0 | 196608 | 0 | 15 - thai_ci_as | 1054 | 0 | 196608 | 0 | 13 - thai_cs_as | 1054 | 0 | 196608 | 0 | 12 - traditional_spanish_ci_ai | 1034 | 0 | 196608 | 0 | 15 - traditional_spanish_ci_as | 1034 | 0 | 196608 | 0 | 13 - traditional_spanish_cs_as | 1034 | 0 | 196608 | 0 | 12 - turkish_ci_ai | 1055 | 0 | 196608 | 0 | 15 - turkish_ci_as | 1055 | 0 | 196608 | 0 | 13 - turkish_cs_as | 1055 | 0 | 196608 | 0 | 12 - ukrainian_ci_ai | 1058 | 0 | 196608 | 0 | 15 - ukrainian_ci_as | 1058 | 0 | 196608 | 0 | 13 - ukrainian_cs_as | 1058 | 0 | 196608 | 0 | 12 - vietnamese_ci_ai | 1066 | 0 | 196608 | 0 | 15 - vietnamese_ci_as | 1066 | 0 | 196608 | 0 | 13 - vietnamese_cs_as | 1066 | 0 | 196608 | 0 | 12 -(107 rows) - --- clean up -drop table testing1; -drop table testing2; -drop table testing3; -drop table testing4; -drop table testing5; diff --git a/contrib/babelfishpg_tsql/expected/test/babel_datatype.out b/contrib/babelfishpg_tsql/expected/test/babel_datatype.out deleted file mode 100644 index 11f5e9edb1..0000000000 --- a/contrib/babelfishpg_tsql/expected/test/babel_datatype.out +++ /dev/null @@ -1,1477 +0,0 @@ -CREATE EXTENSION IF NOT EXISTS "babelfishpg_tsql" CASCADE; -NOTICE: extension "babelfishpg_tsql" already exists, skipping --- The default scale is 2 in PG. -select CAST('$100,123.4567' AS money); - money -------------- - $100,123.46 -(1 row) - --- Currency symbol followed by number without being quoted is not recognized --- as Money in postgres dialect. -select CAST($100123.4567 AS money); -ERROR: syntax error at or near ".4567" -LINE 1: select CAST($100123.4567 AS money); - ^ --- Scale changes to the sql server default 4 in tsql dialect --- Currency symbol followed by number without being quoted is recognized --- as Money type in tsql dialect. -set babelfishpg_tsql.sql_dialect = "tsql"; -select CAST($100123.4567 AS money); - money -------------- - 100123.4567 -(1 row) - -select CAST($100123. AS money); - money -------------- - 100123.0000 -(1 row) - -select CAST($.4567 AS money); - money --------- - 0.4567 -(1 row) - -select CAST('$100,123.4567' AS money); - money -------------- - 100123.4567 -(1 row) - --- Test numeric types with brackets -create table testing1 (a [tinyint]); -drop table testing1; -create table testing1 (a [smallint]); -drop table testing1; -create table testing1 (a [int]); -drop table testing1; -create table testing1 (a [bigint]); -drop table testing1; -create table testing1 (a [real]); -drop table testing1; -create table testing1 (a [float]); -drop table testing1; --- Comma separated format without quote is not allowed in sql server -select CAST($100,123.4567 AS money); -ERROR: syntax error at or near "," -LINE 1: select CAST($100,123.4567 AS money); - ^ --- Smallmoney in tsql dialect -select CAST($100123.4567 AS smallmoney); - smallmoney -------------- - 100123.4567 -(1 row) - -select CAST('$100,123.4567' AS smallmoney); - smallmoney -------------- - 100123.4567 -(1 row) - --- Comma separated format without quote is not allowed in sql server -select CAST($100,123.4567 AS smallmoney); -ERROR: syntax error at or near "," -LINE 1: select CAST($100,123.4567 AS smallmoney); - ^ -create table testing1(mon money, smon smallmoney); -insert into testing1 (mon, smon) values ('$100,123.4567', '$123.9999'); -insert into testing1 (mon, smon) values ($100123.4567, $123.9999); -select * from testing1; - mon | smon --------------+---------- - 100123.4567 | 123.9999 - 100123.4567 | 123.9999 -(2 rows) - -select avg(CAST(mon AS numeric(38,4))), avg(CAST(smon AS numeric(38,4))) from testing1; - avg | avg ----------------------+---------------------- - 100123.456700000000 | 123.9999000000000000 -(1 row) - -select mon+smon as total from testing1; - total -------------- - 100247.4566 - 100247.4566 -(2 rows) - --- Comma separated format without quote is not allowed in sql server -insert into testing1 (mon, smon) values ($100,123.4567, $123.9999); -ERROR: INSERT has more expressions than target columns -LINE 1: ... into testing1 (mon, smon) values ($100,123.4567, $123.9999)... - ^ --- Test other allowed currency symbols with/without quote -select CAST(€100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST('€100.123' AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(¢100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(£100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST('£100.123' AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(¤100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(Â¥100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(৲100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(৳100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(฿100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(៛100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(â‚ 100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(â‚¡100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(â‚¢100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(â‚£100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(₤100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(â‚¥100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(₦100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(₧100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(₨100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(â‚©100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(₪100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(â‚«100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(â‚­100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(â‚®100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(₯100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(â‚°100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(₱100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(ï·¼100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(﹩100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST($100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(ï¿ 100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(ï¿¡100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(ï¿¥100.123 AS money); - money ----------- - 100.1230 -(1 row) - -select CAST('ï¿¥100.123' AS money); - money ----------- - 100.1230 -(1 row) - -select CAST(₩100.123 AS money); - money ----------- - 100.1230 -(1 row) - --- Test unsupoorted currency symbol -select CAST(ï¿©100.123 AS money); -ERROR: syntax error at or near ".123" -LINE 1: select CAST(ï¿©100.123 AS money); - ^ -select CAST('ï¿©100.123' AS money); - money ----------- - 100.1230 -(1 row) - --- Test that space is allowed between currency symbol and number, this is --- a TSQL behavior -select CAST($ 123.5 AS money); - money ----------- - 123.5000 -(1 row) - -select CAST('$ 123.5' AS money); - money ----------- - 123.5000 -(1 row) - --- Test inexact result mutliply/divide money with money, to match --- SQL Server behavior -select CAST(100 AS money)/CAST(339 AS money)*CAST(10000 AS money); - ?column? ------------ - 2949.0000 -(1 row) - --- Test postgres dialect --- Test currency symbol without quote is not allowed in postgres dialect -reset babelfishpg_tsql.sql_dialect; -select CAST(€100.123 AS money); -ERROR: syntax error at or near ".123" -LINE 1: select CAST(€100.123 AS money); - ^ --- Test exact result multiply/divide money with money in postgres dialect -select CAST(100 AS money)/CAST(339 AS money)*CAST(10000 AS money); - ?column? ------------ - $2,949.85 -(1 row) - --- Clean up -drop table testing1; --- BABEL-109 test no more not unique operator error caused by fixeddeciaml -select CAST(2 AS numeric) > 1; - ?column? ----------- - t -(1 row) - -select CAST(2 AS decimal) > 1; - ?column? ----------- - t -(1 row) - --- Test that numeric > int and fixeddecimal > int is different -select CAST(2.00001 AS numeric) > 2; - ?column? ----------- - t -(1 row) - -select CAST(2.00001 AS sys.fixeddecimal) > 2; - ?column? ----------- - f -(1 row) - --- test TSQL Money (based on fixeddecimal) cross datatype operators -set babelfishpg_tsql.sql_dialect = "tsql"; -select CAST(2 AS money) > 1; - ?column? ----------- - t -(1 row) - -select CAST(2 AS money) > CAST(1 AS int); - ?column? ----------- - t -(1 row) - -select CAST(2 AS money) > CAST(1 AS int2); - ?column? ----------- - t -(1 row) - -select CAST(2 AS money) > CAST(1 AS int4); - ?column? ----------- - t -(1 row) - -select CAST(2 AS money) > CAST(1 AS numeric); - ?column? ----------- - t -(1 row) - -select CAST(2 AS money) > CAST(1 AS decimal); - ?column? ----------- - t -(1 row) - -select CAST(2 AS money) >= 1; - ?column? ----------- - t -(1 row) - -select CAST(2 AS money) >= CAST(1 AS int); - ?column? ----------- - t -(1 row) - -select CAST(2 AS money) >= CAST(1 AS int2); - ?column? ----------- - t -(1 row) - -select CAST(2 AS money) >= CAST(1 AS int4); - ?column? ----------- - t -(1 row) - -select CAST(2 AS money) >= CAST(1 AS numeric); - ?column? ----------- - t -(1 row) - -select CAST(2 AS money) >= CAST(1 AS decimal); - ?column? ----------- - t -(1 row) - -select CAST(2 AS money) < 1; - ?column? ----------- - f -(1 row) - -select CAST(2 AS money) < CAST(1 AS int); - ?column? ----------- - f -(1 row) - -select CAST(2 AS money) < CAST(1 AS int2); - ?column? ----------- - f -(1 row) - -select CAST(2 AS money) < CAST(1 AS int4); - ?column? ----------- - f -(1 row) - -select CAST(2 AS money) < CAST(1 AS numeric); - ?column? ----------- - f -(1 row) - -select CAST(2 AS money) < CAST(1 AS decimal); - ?column? ----------- - f -(1 row) - -select CAST(2 AS money) <= 1; - ?column? ----------- - f -(1 row) - -select CAST(2 AS money) <= CAST(1 AS int); - ?column? ----------- - f -(1 row) - -select CAST(2 AS money) <= CAST(1 AS int2); - ?column? ----------- - f -(1 row) - -select CAST(2 AS money) <= CAST(1 AS int4); - ?column? ----------- - f -(1 row) - -select CAST(2 AS money) <= CAST(1 AS numeric); - ?column? ----------- - f -(1 row) - -select CAST(2 AS money) <= CAST(1 AS decimal); - ?column? ----------- - f -(1 row) - -select CAST(2 AS money) <> 1; - ?column? ----------- - t -(1 row) - -select CAST(2 AS money) <> CAST(1 AS int); - ?column? ----------- - t -(1 row) - -select CAST(2 AS money) <> CAST(1 AS int2); - ?column? ----------- - t -(1 row) - -select CAST(2 AS money) <> CAST(1 AS int4); - ?column? ----------- - t -(1 row) - -select CAST(2 AS money) <> CAST(1 AS numeric); - ?column? ----------- - t -(1 row) - -select CAST(2 AS money) <> CAST(1 AS decimal); - ?column? ----------- - t -(1 row) - -select CAST(2 AS money) + 1; - ?column? ----------- - 3.0000 -(1 row) - -select CAST(2 AS money) + CAST(1 AS int); - ?column? ----------- - 3.0000 -(1 row) - -select CAST(2 AS money) + CAST(1 AS int2); - ?column? ----------- - 3.0000 -(1 row) - -select CAST(2 AS money) + CAST(1 AS int4); - ?column? ----------- - 3.0000 -(1 row) - -select CAST(2 AS money) + CAST(1 AS numeric); - ?column? ----------- - 3.0000 -(1 row) - -select CAST(2 AS money) + CAST(1 AS decimal); - ?column? ----------- - 3.0000 -(1 row) - -select CAST(2 AS money) - 1; - ?column? ----------- - 1.0000 -(1 row) - -select CAST(2 AS money) - CAST(1 AS int); - ?column? ----------- - 1.0000 -(1 row) - -select CAST(2 AS money) - CAST(1 AS int2); - ?column? ----------- - 1.0000 -(1 row) - -select CAST(2 AS money) - CAST(1 AS int4); - ?column? ----------- - 1.0000 -(1 row) - -select CAST(2 AS money) - CAST(1 AS numeric); - ?column? ----------- - 1.0000 -(1 row) - -select CAST(2 AS money) - CAST(1 AS decimal); - ?column? ----------- - 1.0000 -(1 row) - -select CAST(2 AS money) * 2; - ?column? ----------- - 4.0000 -(1 row) - -select CAST(2 AS money) * CAST(2 AS int); - ?column? ----------- - 4.0000 -(1 row) - -select CAST(2 AS money) * CAST(2 AS int2); - ?column? ----------- - 4.0000 -(1 row) - -select CAST(2 AS money) * CAST(2 AS int4); - ?column? ----------- - 4.0000 -(1 row) - -select CAST(2 AS money) * CAST(2 AS numeric); - ?column? ----------- - 4.0000 -(1 row) - -select CAST(2 AS money) * CAST(2 AS decimal); - ?column? ----------- - 4.0000 -(1 row) - -select CAST(2 AS money) / 0.5; - ?column? --------------------- - 4.0000000000000000 -(1 row) - -select CAST(2 AS money) / CAST(2 AS int); - ?column? ----------- - 1.0000 -(1 row) - -select CAST(2 AS money) / CAST(2 AS int2); - ?column? ----------- - 1.0000 -(1 row) - -select CAST(2 AS money) / CAST(2 AS int4); - ?column? ----------- - 1.0000 -(1 row) - -select CAST(2 AS money) / CAST(0.5 AS numeric(4,2)); - ?column? --------------------- - 4.0000000000000000 -(1 row) - -select CAST(2 AS money) / CAST(0.5 AS decimal(4,2)); - ?column? --------------------- - 4.0000000000000000 -(1 row) - -reset babelfishpg_tsql.sql_dialect; --- Test DATE, DATETIME, DATETIMEOFFSET, DATETIME2 -set babelfishpg_tsql.sql_dialect = "tsql"; --- DATE DATETIME, DATETIMEOFFSET, DATETIME2 and SMALLDATETIME are defined in tsql dialect -select CAST('2020-03-15' AS date); - date ------------- - 03-15-2020 -(1 row) - -select CAST('2020-03-15 09:00:00+8' AS datetimeoffset); - datetimeoffset ---------------------------------- - Sun Mar 15 09:00:00 2020 +08:00 -(1 row) - -select CAST('2020-03-15 09:00:00' AS datetime2); - datetime2 --------------------------- - Sun Mar 15 09:00:00 2020 -(1 row) - -select CAST('2020-03-15 09:00:00' AS smalldatetime); - smalldatetime --------------------------- - Sun Mar 15 09:00:00 2020 -(1 row) - --- test the range of date -select CAST('0001-01-01' AS date); - date ------------- - 01-01-0001 -(1 row) - -select CAST('9999-12-31' AS date); - date ------------- - 12-31-9999 -(1 row) - --- test the range of datetime2 -select CAST('0001-01-01 12:00:00.12345' AS datetime2); - datetime2 --------------------------------- - Mon Jan 01 12:00:00.12345 0001 -(1 row) - -select CAST('9999-12-31 12:00:00.12345' AS datetime2); - datetime2 --------------------------------- - Fri Dec 31 12:00:00.12345 9999 -(1 row) - --- precision -select CAST('2020-03-15 09:00:00+8' AS datetimeoffset(7)) ; -WARNING: TIMESTAMP(7) WITH TIME ZONE precision reduced to maximum allowed, 6 -LINE 1: select CAST('2020-03-15 09:00:00+8' AS datetimeoffset(7)) ; - ^ - datetimeoffset ---------------------------------- - Sun Mar 15 09:00:00 2020 +08:00 -(1 row) - -create table testing1(ts DATETIME, tstz DATETIMEOFFSET(7)); -WARNING: TIMESTAMP(7) WITH TIME ZONE precision reduced to maximum allowed, 6 -LINE 1: create table testing1(ts DATETIME, tstz DATETIMEOFFSET(7)); - ^ -WARNING: TIMESTAMP(7) WITH TIME ZONE precision reduced to maximum allowed, 6 -LINE 1: create table testing1(ts DATETIME, tstz DATETIMEOFFSET(7)); - ^ -WARNING: TIMESTAMP(7) WITH TIME ZONE precision reduced to maximum allowed, 6 -insert into testing1 (ts, tstz) values ('2020-03-15 09:00:00', '2020-03-15 09:00:00+8'); -select * from testing1; - ts | tstz ---------------------------+--------------------------------- - Sun Mar 15 09:00:00 2020 | Sun Mar 15 09:00:00 2020 +08:00 -(1 row) - -drop table testing1; -select CAST('2020-03-15 09:00:00' AS datetime2(7)); -WARNING: TIMESTAMP(7) precision reduced to maximum allowed, 6 -LINE 1: select CAST('2020-03-15 09:00:00' AS datetime2(7)); - ^ - datetime2 --------------------------- - Sun Mar 15 09:00:00 2020 -(1 row) - -select CAST('2020-03-15 09:00:00.123456' AS datetime2(3)); - datetime2 ------------------------------- - Sun Mar 15 09:00:00.123 2020 -(1 row) - -select CAST('2020-03-15 09:00:00.123456' AS datetime2(0)); - datetime2 --------------------------- - Sun Mar 15 09:00:00 2020 -(1 row) - -select CAST('2020-03-15 09:00:00.123456' AS datetime2(-1)); -ERROR: Specified scale -1 is invalid. 'datetime2' datatype must have scale between 0 and 7 -create table testing1(ts DATETIME, tstz DATETIME2(7)); -WARNING: TIMESTAMP(7) precision reduced to maximum allowed, 6 -LINE 1: create table testing1(ts DATETIME, tstz DATETIME2(7)); - ^ -WARNING: TIMESTAMP(7) precision reduced to maximum allowed, 6 -LINE 1: create table testing1(ts DATETIME, tstz DATETIME2(7)); - ^ -WARNING: TIMESTAMP(7) precision reduced to maximum allowed, 6 -insert into testing1 (ts, tstz) values ('2020-03-15 09:00:00', '2020-03-15 09:00:00'); -select * from testing1; - ts | tstz ---------------------------+-------------------------- - Sun Mar 15 09:00:00 2020 | Sun Mar 15 09:00:00 2020 -(1 row) - -drop table testing1; --- DATETIME, DATETIMEOFFSET, DATETIME2 and SMALLDATETIME are not defined in --- postgres dialect -SELECT set_config('babelfishpg_tsql.sql_dialect', 'postgres', false); - set_config ------------- - postgres -(1 row) - -select CAST('2020-03-15 09:00:00+8' AS datetimeoffset); -ERROR: type "datetimeoffset" does not exist -LINE 1: select CAST('2020-03-15 09:00:00+8' AS datetimeoffset); - ^ -create table testing1(ts DATETIME); -ERROR: type "datetime" does not exist -LINE 1: create table testing1(ts DATETIME); - ^ -create table testing1(tstz DATETIMEOFFSET); -ERROR: type "datetimeoffset" does not exist -LINE 1: create table testing1(tstz DATETIMEOFFSET); - ^ -select CAST('2020-03-15 09:00:00' AS datetime2); -ERROR: type "datetime2" does not exist -LINE 1: select CAST('2020-03-15 09:00:00' AS datetime2); - ^ -create table testing1(ts SMALLDATETIME); -ERROR: type "smalldatetime" does not exist -LINE 1: create table testing1(ts SMALLDATETIME); - ^ -create table testing1(tstz DATETIME2); -ERROR: type "datetime2" does not exist -LINE 1: create table testing1(tstz DATETIME2); - ^ --- Test DATETIME, DATETIMEOFFSET, DATETIME2 and SMALLDATETIME can be used as identifier -create table testing1(DATETIME int); -insert into testing1 (DATETIME) values (1); -select * from testing1; - datetime ----------- - 1 -(1 row) - -drop table testing1; -create table testing1(DATETIMEOFFSET int); -insert into testing1 (DATETIMEOFFSET) values (1); -select * from testing1; - datetimeoffset ----------------- - 1 -(1 row) - -drop table testing1; -create table testing1(DATETIME2 int); -insert into testing1 (DATETIME2) values (1); -select * from testing1; - datetime2 ------------ - 1 -(1 row) - -drop table testing1; -create table testing1(SMALLDATETIME int); -insert into testing1 (SMALLDATETIME) values (1); -select * from testing1; - smalldatetime ---------------- - 1 -(1 row) - -set babelfishpg_tsql.sql_dialect = 'tsql'; -insert into testing1 (SMALLDATETIME) values (2); -select * from testing1; - smalldatetime ---------------- - 1 - 2 -(2 rows) - --- Test conversion between DATE and other date/time types -select CAST(CAST('2020-03-15' AS date) AS datetime); - datetime --------------------------- - Sun Mar 15 00:00:00 2020 -(1 row) - -select CAST(CAST('2020-03-15' AS date) AS smalldatetime); - smalldatetime --------------------------- - Sun Mar 15 00:00:00 2020 -(1 row) - -select CAST(CAST('2020-03-15' AS date) AS datetimeoffset(3)); - datetimeoffset ---------------------------------- - Sun Mar 15 00:00:00 2020 +00:00 -(1 row) - -select CAST(CAST('2020-03-15' AS date) AS datetime2(3)); - datetime2 --------------------------- - Sun Mar 15 00:00:00 2020 -(1 row) - --- Clean up -reset babelfishpg_tsql.sql_dialect; -drop table testing1; --- Test SYS.NCHAR, SYS.NVARCHAR and SYS.VARCHAR --- nchar is already available in postgres dialect -select CAST('£' AS nchar(1)); - bpchar --------- - £ -(1 row) - --- nvarchar is not available in postgres dialect -select CAST('£' AS nvarchar); -ERROR: type "nvarchar" does not exist -LINE 1: select CAST('£' AS nvarchar); - ^ --- both are available in tsql dialect -set babelfishpg_tsql.sql_dialect = 'tsql'; -select CAST('£' AS nchar(2)); - nchar -------- - £ -(1 row) - -select CAST('£' AS nvarchar(2)); - nvarchar ----------- - £ -(1 row) - --- multi-byte character doesn't fit in nchar(1) in tsql if it --- would require a UTF16-surrogate-pair on output -select CAST('£' AS char(1)); -- allowed - bpchar --------- - £ -(1 row) - -select CAST('£' AS sys.nchar(1)); -- allowed - nchar -------- - £ -(1 row) - -select CAST('£' AS sys.nvarchar(1)); -- allowed - nvarchar ----------- - £ -(1 row) - -select CAST('£' AS sys.varchar(1)); -- allowed - varchar ---------- - £ -(1 row) - --- Check that things work the same in postgres dialect -reset babelfishpg_tsql.sql_dialect; -select CAST('£' AS char(1)); - bpchar --------- - £ -(1 row) - -select CAST('£' AS sys.nchar(1)); - nchar -------- - £ -(1 row) - -select CAST('£' AS sys.nvarchar(1)); - nvarchar ----------- - £ -(1 row) - -select CAST('£' AS sys.varchar(1)); - varchar ---------- - £ -(1 row) - -set babelfishpg_tsql.sql_dialect = 'tsql'; --- truncate input on explicit cast -select CAST('ab' AS char(1)); - bpchar --------- - a -(1 row) - -select CAST('ab' AS nchar(1)); - nchar -------- - a -(1 row) - -select CAST('ab' AS nvarchar(1)); - nvarchar ----------- - a -(1 row) - -select CAST('ab' AS sys.varchar(1)); - varchar ---------- - a -(1 row) - --- default length of nchar/char is 1 in tsql (and pg) -create table testing1(col nchar); -reset babelfishpg_tsql.sql_dialect; -\d testing1; - Table "public.testing1" - Column | Type | Collation | Nullable | Default ---------+----------------+-----------+----------+--------- - col | sys."nchar"(1) | | | - -set babelfishpg_tsql.sql_dialect = "tsql"; --- check length at insert -insert into testing1 (col) select 'a'; -insert into testing1 (col) select '£'; -insert into testing1 (col) select 'ab'; -ERROR: value too long for type character(1) --- space is automatically truncated -insert into testing1 (col) select 'c '; -select * from testing1; - col ------ - a - £ - c -(3 rows) - --- default length of nvarchar in tsql is 1 -create table testing2(col nvarchar); -insert into testing2 (col) select 'a'; -insert into testing2 (col) select '£'; -insert into testing2 (col) select 'ab'; -ERROR: value too long for type character varying(1) --- space is automatically truncated -insert into testing2 (col) select 'c '; -select * from testing2; - col ------ - a - £ - c -(3 rows) - --- default length of varchar in tsql is 1 -create table testing4(col sys.varchar); -insert into testing4 (col) select 'a'; -insert into testing4 (col) select '£'; -insert into testing4 (col) select 'ab'; -ERROR: value too long for type character varying(1) --- space is automatically truncated -insert into testing4 (col) select 'c '; -insert into testing2 (col) select '£ '; -select * from testing4; - col ------ - a - £ - c -(3 rows) - --- test sys.varchar(max) and sys.nvarchar(max) syntax is allowed in tsql dialect -select CAST('abcdefghijklmn' AS sys.varchar(max)); - varchar ----------------- - abcdefghijklmn -(1 row) - -select CAST('abcdefghijklmn' AS varchar(max)); - varchar ----------------- - abcdefghijklmn -(1 row) - -select CAST('abcdefghijklmn' AS sys.nvarchar(max)); - nvarchar ----------------- - abcdefghijklmn -(1 row) - -select CAST('abcdefghijklmn' AS nvarchar(max)); - nvarchar ----------------- - abcdefghijklmn -(1 row) - --- test char(max), nchar(max) is invalid syntax in tsql dialect -select cast('abc' as char(max)); -ERROR: Incorrect syntax near the keyword 'bpchar'. -select cast('abc' as nchar(max)); -ERROR: Incorrect syntax near the keyword 'nchar'. --- test max can still be used as an identifier -create table max (max int); -insert into max (max) select 100; -select * from max; - max ------ - 100 -(1 row) - -drop table max; --- test sys.varchar(max) and nvarchar(max) syntax is not allowed in postgres dialect -reset babelfishpg_tsql.sql_dialect; -select CAST('abcdefghijklmn' AS sys.varchar(max)); -ERROR: invalid input syntax for type integer: "max" -LINE 1: select CAST('abcdefghijklmn' AS sys.varchar(max)); - ^ -select CAST('abcdefghijklmn' AS varchar(max)); -ERROR: syntax error at or near "max" -LINE 1: select CAST('abcdefghijklmn' AS varchar(max)); - ^ -select CAST('abcdefghijklmn' AS sys.nvarchar(max)); -ERROR: invalid input syntax for type integer: "max" -LINE 1: select CAST('abcdefghijklmn' AS sys.nvarchar(max)); - ^ -select CAST('abcdefghijklmn' AS nvarchar(max)); -ERROR: type "nvarchar" does not exist -LINE 1: select CAST('abcdefghijklmn' AS nvarchar(max)); - ^ --- test max max character length is (10 * 1024 * 1024) = 10485760 -select CAST('abc' AS varchar(10485761)); -ERROR: length for type varchar cannot exceed 10485760 -LINE 1: select CAST('abc' AS varchar(10485761)); - ^ -select CAST('abc' AS varchar(10485760)); - varchar ---------- - abc -(1 row) - --- test column type nvarchar(max) -set babelfishpg_tsql.sql_dialect = 'tsql'; -create table testing5(col nvarchar(max)); -reset babelfishpg_tsql.sql_dialect; -\d testing5 - Table "public.testing5" - Column | Type | Collation | Nullable | Default ---------+--------------+-----------+----------+--------- - col | sys.nvarchar | | | - -set babelfishpg_tsql.sql_dialect = "tsql"; -insert into testing5 (col) select 'ab'; -insert into testing5 (col) select 'abcdefghijklmn'; -select * from testing5; - col ----------------- - ab - abcdefghijklmn -(2 rows) - ---test COPY command works with sys.nvarchar -COPY public.testing5 (col) FROM stdin; -select * from testing5; - col ----------------- - ab - abcdefghijklmn - c - ab - abcdefghijk -(5 rows) - --- [BABEL-220] test varchar(max) as a column -drop table testing5; -create table testing5(col varchar(max)); -reset babelfishpg_tsql.sql_dialect; -\d testing5 - Table "public.testing5" - Column | Type | Collation | Nullable | Default ---------+---------------+-----------+----------+--------- - col | sys."varchar" | | | - -set babelfishpg_tsql.sql_dialect = "tsql"; -insert into testing5 (col) select 'ab'; -insert into testing5 (col) select 'abcdefghijklmn'; -select * from testing5; - col ----------------- - ab - abcdefghijklmn -(2 rows) - --- test type modifer persist if babelfishpg_tsql.sql_dialect changes -create table testing3(col nvarchar(2)); -insert into testing3 (col) select 'ab'; -insert into testing3 (col) select 'a£'; -insert into testing3 (col) select 'a😀'; -ERROR: value too long for type character varying(2) as UTF16 output -insert into testing3 (col) select 'abc'; -ERROR: value too long for type character varying(2) -reset babelfishpg_tsql.sql_dialect; -insert into testing3 (col) select 'ab'; -insert into testing3 (col) select 'a£'; -insert into testing3 (col) select 'a😀'; -ERROR: value too long for type character varying(2) as UTF16 output -insert into testing3 (col) select 'abc'; -ERROR: value too long for type character varying(2) -set babelfishpg_tsql.sql_dialect = 'tsql'; -insert into testing3 (col) select 'ab'; -insert into testing3 (col) select 'a£'; -insert into testing3 (col) select 'a😀'; -ERROR: value too long for type character varying(2) as UTF16 output -insert into testing3 (col) select 'abc'; -ERROR: value too long for type character varying(2) --- test normal create domain works when apg_enable_domain_typmod is enabled -set apg_enable_domain_typmod true; -create domain varchar3 as varchar(3); -select CAST('abc' AS varchar3); - varchar3 ----------- - abc -(1 row) - -select CAST('ab£' AS varchar3); - varchar3 ----------- - ab£ -(1 row) - -select CAST('abcd' AS varchar3); - varchar3 ----------- - abc -(1 row) - -reset apg_enable_domain_typmod; -ERROR: unrecognized configuration parameter "apg_enable_domain_typmod" --- [BABEL-191] test typmod of sys.varchar/nvarchar engages when the input --- is casted multiple times -select CAST(CAST('abc' AS text) AS sys.varchar(3)); - varchar ---------- - abc -(1 row) - -select CAST(CAST('abc' AS pg_catalog.varchar(3)) AS sys.varchar(3)); - varchar ---------- - abc -(1 row) - -select CAST(CAST('abc' AS text) AS sys.nvarchar(3)); - nvarchar ----------- - abc -(1 row) - -select CAST(CAST('abc' AS text) AS sys.nchar(3)); - nchar -------- - abc -(1 row) - -select CAST(CAST(CAST(CAST('abc' AS text) AS sys.varchar(3)) AS sys.nvarchar(3)) AS sys.nchar(3)); - nchar -------- - abc -(1 row) - --- test truncation on explicit cast through multiple levels -select CAST(CAST(CAST(CAST('abcde' AS text) AS sys.varchar(5)) AS sys.nvarchar(4)) AS sys.nchar(3)); - nchar -------- - abc -(1 row) - -select CAST(CAST(CAST(CAST('abcde' AS text) AS sys.varchar(3)) AS sys.nvarchar(4)) AS sys.nchar(5)); - nchar -------- - abc -(1 row) - --- test sys.ntext is available -select CAST('abc£' AS sys.ntext); - ntext -------- - abc£ -(1 row) - --- pg_catalog.text -select CAST('abc£' AS text); - text ------- - abc£ -(1 row) - --- [BABEL-218] test varchar defaults to sys.varchar in tsql dialect --- test default length of sys.varchar is 30 in CAST/CONVERT --- expect the last 'e' to be truncated -select cast('abcdefghijklmnopqrstuvwxyzabcde' as varchar); - varchar --------------------------------- - abcdefghijklmnopqrstuvwxyzabcd -(1 row) - -select cast('abcdefghijklmnopqrstuvwxyzabcde' as sys.varchar); - varchar --------------------------------- - abcdefghijklmnopqrstuvwxyzabcd -(1 row) - -select convert(varchar, 'abcdefghijklmnopqrstuvwxyzabcde'); - babelfish_conv_helper_to_varchar ----------------------------------- - abcdefghijklmnopqrstuvwxyzabcd -(1 row) - -select convert(sys.varchar, 'abcdefghijklmnopqrstuvwxyzabcde'); - varchar --------------------------------- - abcdefghijklmnopqrstuvwxyzabcd -(1 row) - --- default length of pg_catalog.varchar is unlimited, no truncation in output -select cast('abcdefghijklmnopqrstuvwxyzabcde' as pg_catalog.varchar); - varchar ---------------------------------- - abcdefghijklmnopqrstuvwxyzabcde -(1 row) - --- varchar defaults to pg_catalog.varchar in PG dialect -reset babelfishpg_tsql.sql_dialect; -select cast('abcdefghijklmnopqrstuvwxyzabcde' as pg_catalog.varchar); -- default length of pg_catalog.varchar is unlimited, no truncation - varchar ---------------------------------- - abcdefghijklmnopqrstuvwxyzabcde -(1 row) - -set babelfishpg_tsql.sql_dialect = 'tsql'; --- [BABEL-255] test nchar defaults to sys.nchar in tsql dialect -create table test_nchar (col1 nchar); -reset babelfishpg_tsql.sql_dialect; -\d test_nchar - Table "public.test_nchar" - Column | Type | Collation | Nullable | Default ---------+----------------+-----------+----------+--------- - col1 | sys."nchar"(1) | | | - -set babelfishpg_tsql.sql_dialect = "tsql"; -drop table test_nchar; --- test nchar defaults to bpchar in pg dialect -reset babelfishpg_tsql.sql_dialect; -create table test_nchar (col1 nchar); -\d test_nchar - Table "public.test_nchar" - Column | Type | Collation | Nullable | Default ---------+--------------+-----------+----------+--------- - col1 | character(1) | | | - -drop table test_nchar; -set babelfishpg_tsql.sql_dialect = 'tsql'; --- [BABEL-257] test varchar defaults to sys.varchar in new --- database and new schema -SELECT current_database(); - current_database --------------------- - contrib_regression -(1 row) - -SELECT set_config('babelfishpg_tsql.sql_dialect', 'postgres', false); - set_config ------------- - postgres -(1 row) - -CREATE DATABASE demo; -\c demo -CREATE EXTENSION IF NOT EXISTS "babelfishpg_tsql" CASCADE; -NOTICE: installing required extension "uuid-ossp" -NOTICE: installing required extension "babelfishpg_common" --- Reconnect to make sure CLUSTER_COLLATION_OID is initialized -\c postgres -\c demo -set babelfishpg_tsql.sql_dialect = 'tsql'; --- Test varchar is mapped to sys.varchar --- Expect truncated output because sys.varchar defaults to sys.varchar(30) in CAST function -select cast('abcdefghijklmnopqrstuvwxyzabcde' as varchar); - varchar --------------------------------- - abcdefghijklmnopqrstuvwxyzabcd -(1 row) - --- Expect non-truncated output because pg_catalog.varchar has unlimited length -select cast('abcdefghijklmnopqrstuvwxyzabcde' as pg_catalog.varchar); - varchar ---------------------------------- - abcdefghijklmnopqrstuvwxyzabcde -(1 row) - --- Test bit is mapped to sys.bit --- sys.bit allows numeric input -select CAST(1.5 AS bit); - bit ------ - 1 -(1 row) - --- pg_catalog.bit doesn't allow numeric input -select CAST(1.5 AS pg_catalog.bit); -ERROR: cannot cast type numeric to bit -LINE 1: select CAST(1.5 AS pg_catalog.bit); - ^ --- Test varchar is mapped to sys.varchar in a new schema and a new table -CREATE SCHEMA s1; -create table s1.test1 (col varchar); --- Test sys.varchar is created for test1.col, expect an error --- because sys.varchar defaults to sys.varchar(1) -insert into s1.test1 values('abc'); -ERROR: value too long for type character varying(1) -insert into s1.test1 values('a'); -select * from s1.test1; - col ------ - a -(1 row) - -drop schema s1 cascade; -NOTICE: drop cascades to table s1.test1 -SELECT set_config('babelfishpg_tsql.sql_dialect', 'postgres', false); - set_config ------------- - postgres -(1 row) - -\c regression -\connect: connection to server on socket "/tmp/.s.PGSQL.5432" failed: FATAL: database "regression" does not exist diff --git a/contrib/babelfishpg_tsql/expected/test/babel_ddl.out b/contrib/babelfishpg_tsql/expected/test/babel_ddl.out deleted file mode 100644 index 298ce9fa57..0000000000 --- a/contrib/babelfishpg_tsql/expected/test/babel_ddl.out +++ /dev/null @@ -1,323 +0,0 @@ --- CLUSTERED INDEX / NONCLUSTERED IDNEX -create table t1 ( a int, b int); -create nonclustered index t1_idx1 on t1 (a); -ERROR: syntax error at or near "nonclustered" -LINE 1: create nonclustered index t1_idx1 on t1 (a); - ^ -create clustered index t1_idx2 on t1(a); -ERROR: syntax error at or near "clustered" -LINE 1: create clustered index t1_idx2 on t1(a); - ^ -create table t2 ( a int, b int, primary key nonclustered (a)); -ERROR: syntax error at or near "nonclustered" -LINE 1: create table t2 ( a int, b int, primary key nonclustered (a)... - ^ -create table t3 ( a int, b int, primary key clustered (a)); -ERROR: syntax error at or near "clustered" -LINE 1: create table t3 ( a int, b int, primary key clustered (a)); - ^ -create table t4 ( a int, b int, unique nonclustered (a)); -ERROR: syntax error at or near "nonclustered" -LINE 1: create table t4 ( a int, b int, unique nonclustered (a)); - ^ -create table t5 ( a int, b int, unique clustered (a)); -ERROR: syntax error at or near "clustered" -LINE 1: create table t5 ( a int, b int, unique clustered (a)); - ^ -create table t6 ( a int primary key nonclustered, b int); -ERROR: syntax error at or near "nonclustered" -LINE 1: create table t6 ( a int primary key nonclustered, b int); - ^ -create table t7 ( a int primary key clustered, b int); -ERROR: syntax error at or near "clustered" -LINE 1: create table t7 ( a int primary key clustered, b int); - ^ -create table t8 ( a int unique nonclustered, b int); -ERROR: syntax error at or near "nonclustered" -LINE 1: create table t8 ( a int unique nonclustered, b int); - ^ -create table t9 ( a int unique clustered, b int); -ERROR: syntax error at or near "clustered" -LINE 1: create table t9 ( a int unique clustered, b int); - ^ -set babelfishpg_tsql.sql_dialect = "tsql"; -create index t1_idx1 on t1 (a); -create index t1_idx2 on t1(a); -create table t2 ( a int, b int, primary key (a)); -create table t3 ( a int, b int, primary key (a)); -create table t4 ( a int, b int, unique (a)); -create table t5 ( a int, b int, unique (a)); -create table t6 ( a int primary key, b int); -create table t7 ( a int primary key, b int); -create table t8 ( a int unique not null, b int); -create table t9 ( a int unique not null, b int); --- CREATE INDEX ... ON syntax -create index t1_idx3 on t1 (a) on [primary]; -create index t1_idx4 on t1 (a) on "default"; --- CREATE TABLE WITH ( [,...n]) syntax -create table t10 (a int) -with (fillfactor = 90, FILETABLE_COLLATE_FILENAME = database_default); -create table t11 (a int) -with (data_compression = row on partitions (2, 4, 6 to 8)); -create table t12 (a int) -with (system_versioning = on (history_table = aaa.bbb, data_consistency_check = off)); -create table t13 (a int) -with (remote_data_archive = on (filter_predicate = null, migration_state = outbound)); -create table t14 (a int) -with (data_deletion = on (filter_column = a, retention_period = 14 day)); --- CREATE INDEX WHERE... WITH ( [,...n]) syntax -create index t1_idx5 on t1(a) where a is not null -with (pad_index = off, fillfactor = 90, maxdop = 1, sort_in_tempdb = off, max_duration = 2 minutes); -create index t1_idx6 on t1(a) -with (data_compression = page on partitions (2, 4, 6 to 8)); --- CREATE COLUMNSTORE INDEX -create columnstore index t1_idx7 on t1 (a) with (drop_existing = on); -NOTICE: The COLUMNSTORE option is currently ignored -create clustered columnstore index t1_idx8 on t1 (a) on [primary]; -NOTICE: The COLUMNSTORE option is currently ignored --- CREATE TABLE... WITH FILLFACTOR = num -create table t15 (a int primary key with fillfactor=50); --- ALTER TABLE... WITH FILLFACTOR = num -create table t16 (a int not null); -alter table t16 add primary key (a) with fillfactor=50; --- check property of the index -select indexname, indexdef from pg_indexes where tablename like 't_' order by indexname; - indexname | indexdef --------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - t1_idx1t18e881e6977bd6b8cbb78725b3a8ac988 | CREATE INDEX t1_idx1t18e881e6977bd6b8cbb78725b3a8ac988 ON public.t1 USING btree (a) - t1_idx2t117dbbb74ced1fe936cdf7cd7baeff266 | CREATE INDEX t1_idx2t117dbbb74ced1fe936cdf7cd7baeff266 ON public.t1 USING btree (a) - t1_idx3t19eceb46c036c3c1bd6895a34ec3c93f1 | CREATE INDEX t1_idx3t19eceb46c036c3c1bd6895a34ec3c93f1 ON public.t1 USING btree (a) - t1_idx4t1fb4b953a652720bfa47919dff09b172e | CREATE INDEX t1_idx4t1fb4b953a652720bfa47919dff09b172e ON public.t1 USING btree (a) - t1_idx5t1b35d191ff61a4ba407b80329c7ac459a | CREATE INDEX t1_idx5t1b35d191ff61a4ba407b80329c7ac459a ON public.t1 USING btree (a) WITH (pad_index=off, fillfactor='90', maxdop='1', sort_in_tempdb=off, max_duration='2') WHERE (a IS NOT NULL) - t1_idx6t144818325f74bdb1fd5bca880a0aef84c | CREATE INDEX t1_idx6t144818325f74bdb1fd5bca880a0aef84c ON public.t1 USING btree (a) WITH (data_compression=page) - t1_idx7t1a053e704a0d67d6d079dd35cca63a489 | CREATE INDEX t1_idx7t1a053e704a0d67d6d079dd35cca63a489 ON public.t1 USING btree (a) WITH (drop_existing='on') - t1_idx8t171284af2ea6a5a7032b931c5725d1fc4 | CREATE INDEX t1_idx8t171284af2ea6a5a7032b931c5725d1fc4 ON public.t1 USING btree (a) - t2_pkey | CREATE UNIQUE INDEX t2_pkey ON public.t2 USING btree (a) - t3_pkey | CREATE UNIQUE INDEX t3_pkey ON public.t3 USING btree (a) - t4_a_key | CREATE UNIQUE INDEX t4_a_key ON public.t4 USING btree (a) - t5_a_key | CREATE UNIQUE INDEX t5_a_key ON public.t5 USING btree (a) - t6_pkey | CREATE UNIQUE INDEX t6_pkey ON public.t6 USING btree (a) - t7_pkey | CREATE UNIQUE INDEX t7_pkey ON public.t7 USING btree (a) - t8_a_key | CREATE UNIQUE INDEX t8_a_key ON public.t8 USING btree (a) - t9_a_key | CREATE UNIQUE INDEX t9_a_key ON public.t9 USING btree (a) -(16 rows) - --- CREATE TABLE(..., { PRIMARY KEY | UNIQUE } ... --- ON { partition_scheme | filegroup | "default" }) syntax --- ^ -create table t17(a int, primary key clustered (a) on [PRIMARY]); -create table t18(a int, primary key clustered (a) on [PRIMARY]); -create table t19(a int, unique clustered (a) on [PRIMARY]); -create table t20(a int, unique clustered (a) on [PRIMARY]); --- ALTER TABLE ... ADD [CONSTRAINT ...] DEFAULT ... FOR ... -create table t21 (a int, b int); -alter table t21 add default 99 for a; -NOTICE: DEFAULT added. To drop the default, use ALTER TABLE...ALTER COLUMN...DROP DEFAULT; it cannot be dropped by name -insert into t21(b) values (10); -select * from t21; - a | b -----+---- - 99 | 10 -(1 row) - -alter table t21 alter a drop default; -alter table t21 add constraint dflt11 default 11 for a; -NOTICE: DEFAULT added. To drop the default, use ALTER TABLE...ALTER COLUMN...DROP DEFAULT; it cannot be dropped by name -insert into t21(b) values (20); -select * from t21; - a | b -----+---- - 99 | 10 - 11 | 20 -(2 rows) - --- Invalid default value -alter table t21 add default 'test' for a; -NOTICE: DEFAULT added. To drop the default, use ALTER TABLE...ALTER COLUMN...DROP DEFAULT; it cannot be dropped by name -ERROR: invalid input syntax for type integer: "test" --- Invalid column -alter table t21 add default 99 for c; -NOTICE: DEFAULT added. To drop the default, use ALTER TABLE...ALTER COLUMN...DROP DEFAULT; it cannot be dropped by name -ERROR: column "c" of relation "t21" does not exist --- Invalid table -alter table t_invalid add default 99 for a; -NOTICE: DEFAULT added. To drop the default, use ALTER TABLE...ALTER COLUMN...DROP DEFAULT; it cannot be dropped by name -ERROR: relation "t_invalid" does not exist --- ALTER TABLE ... WITH [NO]CHECK ADD CONSTRAINT ... -alter table t21 with check add constraint chk1 check (a > 0); -- add chk1 and enable it -NOTICE: The WITH CHECK/NOCHECK option is currently ignored -alter table t21 with nocheck add constraint chk2 check (b > 0); -- add chk2 and disable it -NOTICE: The WITH CHECK/NOCHECK option is currently ignored -insert into t21 values (1, 1); --- error, not fulfilling constraint chk1 -insert into t21 values (0, 1); -ERROR: new row for relation "t21" violates check constraint "chk1t21848ea8bb1121ee393ad72ae0d412d8d2" -DETAIL: Failing row contains (0, 1). --- should pass after CHECK/NOCHECK is fully supported -insert into t21 values (1, 0); -ERROR: new row for relation "t21" violates check constraint "chk2t21e79a26fb83f057113598e77ab0b1983d" -DETAIL: Failing row contains (1, 0). -select * from t21; - a | b -----+---- - 99 | 10 - 11 | 20 - 1 | 1 -(3 rows) - --- ALTER TABLE ... [NO]CHECK CONSTRAINT ... --- should pass after CHECK/NOCHECK is fully supported -alter table t21 nocheck constraint chk1; -- disable chk1 -NOTICE: The CHECK/NOCHECK option is currently ignored -alter table t21 check constraint chk2; -- enable chk2 -NOTICE: The CHECK/NOCHECK option is currently ignored --- CREATE TABLE ... ( a int identity(...) NOT FOR REPLICATION) -create table t22 (a int identity(1,1) NOT FOR REPLICATION); -create table t23 (a int identity(1,1) NOT FOR REPLICATION NOT NULL); --- ROWGUIDCOL syntax support -create table t24 (a uniqueidentifier ROWGUIDCOL); -create table t25 (a int); -alter table t25 add b uniqueidentifier ROWGUIDCOL; --- computed columns --- CREATE TABLE(..., AS --- ^ [ PERSISTED ] ) -create table computed_column_t1 (a nvarchar(10), b AS substring(a,1,3) UNIQUE NOT NULL); -insert into computed_column_t1 values('abcd'); -select * from computed_column_t1; - a | b -------+----- - abcd | abc -(1 row) - --- test whether other constraints are working with computed columns -insert into computed_column_t1 values('abcd'); -- throws error -ERROR: duplicate key value violates unique constraint "computed_column_t1_b_key" -DETAIL: Key (b)=(abc) already exists. --- check PERSISTED keyword --- should be able to use columns from left and right in the expression -create table computed_column_t2 (a int, b AS (a + c) / 4 PERSISTED, c int); -insert into computed_column_t2 (a,c) values (12, 12); -select * from computed_column_t2; - a | b | c -----+---+---- - 12 | 6 | 12 -(1 row) - --- should throw error - order matters -create table computed_column_error (a int, b AS a/4 NOT NULL PERSISTED); -ERROR: syntax error at or near "PERSISTED" -LINE 1: ... computed_column_error (a int, b AS a/4 NOT NULL PERSISTED)... - ^ --- should throw error if postgres syntax is used in TSQL dialect -create table computed_column_error (a int, b numeric generated always as (a/4) stored); -ERROR: This syntax is only valid when babelfishpg_tsql.sql_dialect is postgres -LINE 1: ...computed_column_error (a int, b numeric generated always as ... - ^ --- should throw error if there is any error in computed column expression -create table computed_column_error (a nvarchar(10), b AS non_existant_function(a,1,3) UNIQUE NOT NULL); -ERROR: function non_existant_function(nvarchar, integer, integer) does not exist -LINE 1: ...able computed_column_error (a nvarchar(10), b AS non_exista... - ^ -HINT: No function matches the given name and argument types. You might need to add explicit type casts. --- should throw error in case of nested computed columns -create table computed_column_error (a int, b as c, c as a); -ERROR: computed column "c" in table "computed_column_error" is not allowed to be used in another computed-column definition -LINE 1: create table computed_column_error (a int, b as c, c as a); - ^ -create table computed_column_error (a int, b as b + 1); -ERROR: computed column "b" in table "computed_column_error" is not allowed to be used in another computed-column definition -LINE 1: create table computed_column_error (a int, b as b + 1); - ^ --- in case of multiple computed column, the entire statement should be rolled --- back even when the last one throws error -create table computed_column_error (a int, b as a, c as b); -ERROR: computed column "b" in table "computed_column_error" is not allowed to be used in another computed-column definition -LINE 1: create table computed_column_error (a int, b as a, c as b); - ^ -select * from computed_column_error; -ERROR: relation "computed_column_error" does not exist -LINE 1: select * from computed_column_error; - ^ --- ALTER TABLE... ADD AS --- ^ [ PERSISTED ] ) -alter table computed_column_t1 add c int; -alter table computed_column_t1 add d as c / 4; -insert into computed_column_t1(a, c) VALUES ('efgh', 12); -select * from computed_column_t1; - a | b | c | d -------+-----+----+--- - abcd | abc | | - efgh | efg | 12 | 3 -(2 rows) - ---should thow error in case of nested computed columns - alter table computed_column_t1 add e as d; -ERROR: cannot use generated column "d" in column generation expression -DETAIL: A generated column cannot reference another generated column. - alter table computed_column_t1 add e as e + 1; -ERROR: computed column "e" in table "computed_column_t1" is not allowed to be used in another computed-column definition --- should throw error if any of the dependant columns is modified or dropped. -alter table computed_column_t1 drop column a; -ERROR: cannot drop a column used by a generated column -DETAIL: Column "a" is used by generated column "b". -alter table computed_column_t1 alter column a varchar; -ERROR: cannot alter type of a column used by a generated column -DETAIL: Column "a" is used by generated column "b". --- should throw error as rand is non-deterministic -alter table computed_column_t1 add e as rand() persisted; -ERROR: generation expression is not immutable --- but rand[seed] should succeed -alter table computed_column_t1 add e as rand(1) persisted; --- should throw error in postgres dialect -select set_config('babelfishpg_tsql.sql_dialect', 'postgres', null); - set_config ------------- - postgres -(1 row) - -create table computed_column_error (a int, b AS (a/4) PERSISTED NOT NULL); -ERROR: syntax error at or near "AS" -LINE 1: create table computed_column_error (a int, b AS (a/4) PERSI... - ^ --- since we're in postgres dialect, also check the table definition whether --- the computed column got resolved to correct datatype -\d computed_column_t1 - Table "public.computed_column_t1" - Column | Type | Collation | Nullable | Default ---------+------------------+-----------+----------+------------------------------------------------------- - a | sys.nvarchar(10) | | | - b | sys.nvarchar | | not null | generated always as (sys."substring"(a, 1, 3)) stored - c | integer | | | - d | integer | | | generated always as (c / 4) stored - e | double precision | | | generated always as (sys.rand(1)) stored -Indexes: - "computed_column_t1_b_key" UNIQUE CONSTRAINT, btree (b) - -set babelfishpg_tsql.sql_dialect = "tsql"; -drop table t1; -drop table t2; -drop table t3; -drop table t4; -drop table t5; -drop table t6; -drop table t7; -drop table t8; -drop table t9; -drop table t10; -drop table t11; -drop table t12; -drop table t13; -drop table t14; -drop table t15; -drop table t16; -drop table t17; -drop table t18; -drop table t19; -drop table t20; -drop table t21; -drop table t22; -drop table t23; -drop table t24; -drop table t25; -drop table computed_column_t1; -drop table computed_column_t2; diff --git a/contrib/babelfishpg_tsql/expected/test/babel_delete.out b/contrib/babelfishpg_tsql/expected/test/babel_delete.out deleted file mode 100644 index 0f37c683f6..0000000000 --- a/contrib/babelfishpg_tsql/expected/test/babel_delete.out +++ /dev/null @@ -1,294 +0,0 @@ --- --- Tests for DELETE clause --- -CREATE EXTENSION IF NOT EXISTS "babelfishpg_tsql"; -NOTICE: extension "babelfishpg_tsql" already exists, skipping --- Negative cases when using postgres dialect -RESET babelfishpg_tsql.sql_dialect; -SHOW babelfishpg_tsql.sql_dialect; - babelfishpg_tsql.sql_dialect ------------------------------- - postgres -(1 row) - -CREATE TABLE delete_test_tbl ( - age int, - fname char(10), - lname char(10), - city nchar(20) -); -INSERT INTO delete_test_tbl(age, fname, lname, city) -VALUES (50, 'fname1', 'lname1', 'london'), - (34, 'fname2', 'lname2', 'paris'), - (35, 'fname3', 'lname3', 'brussels'), - (90, 'fname4', 'lname4', 'new york'), - (26, 'fname5', 'lname5', 'los angeles'), - (74, 'fname6', 'lname6', 'tokyo'), - (44, 'fname7', 'lname7', 'oslo'), - (19, 'fname8', 'lname8', 'hong kong'), - (61, 'fname9', 'lname9', 'shanghai'), - (29, 'fname10', 'lname10', 'mumbai'); -SELECT * FROM delete_test_tbl; - age | fname | lname | city ------+------------+------------+---------------------- - 50 | fname1 | lname1 | london - 34 | fname2 | lname2 | paris - 35 | fname3 | lname3 | brussels - 90 | fname4 | lname4 | new york - 26 | fname5 | lname5 | los angeles - 74 | fname6 | lname6 | tokyo - 44 | fname7 | lname7 | oslo - 19 | fname8 | lname8 | hong kong - 61 | fname9 | lname9 | shanghai - 29 | fname10 | lname10 | mumbai -(10 rows) - -\set ON_ERROR_STOP 0 -DELETE delete_test_tbl; -ERROR: syntax error at or near "delete_test_tbl" -LINE 1: DELETE delete_test_tbl; - ^ --- Positive cases when using tsql dialect -SET babelfishpg_tsql.sql_dialect = "tsql"; -SHOW babelfishpg_tsql.sql_dialect; - babelfishpg_tsql.sql_dialect ------------------------------- - tsql -(1 row) - -\set ON_ERROR_STOP 1 --- Prove that a user may delete rows from a table without using the FROM clause -SELECT * FROM delete_test_tbl; - age | fname | lname | city ------+------------+------------+---------------------- - 50 | fname1 | lname1 | london - 34 | fname2 | lname2 | paris - 35 | fname3 | lname3 | brussels - 90 | fname4 | lname4 | new york - 26 | fname5 | lname5 | los angeles - 74 | fname6 | lname6 | tokyo - 44 | fname7 | lname7 | oslo - 19 | fname8 | lname8 | hong kong - 61 | fname9 | lname9 | shanghai - 29 | fname10 | lname10 | mumbai -(10 rows) - --- Test that that WHERE clause can be used without FROM -DELETE delete_test_tbl WHERE city='hong kong'; -SELECT * FROM delete_test_tbl; - age | fname | lname | city ------+------------+------------+---------------------- - 50 | fname1 | lname1 | london - 34 | fname2 | lname2 | paris - 35 | fname3 | lname3 | brussels - 90 | fname4 | lname4 | new york - 26 | fname5 | lname5 | los angeles - 74 | fname6 | lname6 | tokyo - 44 | fname7 | lname7 | oslo - 61 | fname9 | lname9 | shanghai - 29 | fname10 | lname10 | mumbai -(9 rows) - -DELETE delete_test_tbl WHERE age > 50; -SELECT * FROM delete_test_tbl; - age | fname | lname | city ------+------------+------------+---------------------- - 50 | fname1 | lname1 | london - 34 | fname2 | lname2 | paris - 35 | fname3 | lname3 | brussels - 26 | fname5 | lname5 | los angeles - 44 | fname7 | lname7 | oslo - 29 | fname10 | lname10 | mumbai -(6 rows) - -DELETE delete_test_tbl WHERE fname IN ('fname1', 'fname2'); -SELECT * FROM delete_test_tbl; - age | fname | lname | city ------+------------+------------+---------------------- - 35 | fname3 | lname3 | brussels - 26 | fname5 | lname5 | los angeles - 44 | fname7 | lname7 | oslo - 29 | fname10 | lname10 | mumbai -(4 rows) - --- Test that DELETE works without any other clauses -DELETE delete_test_tbl; -SELECT * FROM delete_test_tbl; - age | fname | lname | city ------+-------+-------+------ -(0 rows) - --- Test delete for joined table -CREATE TABLE delete_test_tbl2 ( - age int, - fname char(10), - lname char(10), - city nchar(20) -); -INSERT INTO delete_test_tbl2(age, fname, lname, city) -VALUES (50, 'fname1', 'lname1', 'london'), - (34, 'fname2', 'lname2', 'paris'), - (50, 'fname3', 'lname3', 'brussels'), - (90, 'fname4', 'lname4', 'new york'), - (26, 'fname5', 'lname5', 'los angeles'), - (74, 'fname6', 'lname6', 'tokyo'), - (44, 'fname7', 'lname7', 'oslo'), - (19, 'fname8', 'lname8', 'hong kong'), - (61, 'fname9', 'lname9', 'shanghai'), - (29, 'fname10', 'lname10', 'mumbai'); -CREATE TABLE delete_test_tbl3 ( - year int, - lname char(10), -); -INSERT INTO delete_test_tbl3(year, lname) -VALUES (51, 'lname1'), - (34, 'lname3'), - (25, 'lname8'), - (95, 'lname9'), - (36, 'lname10'); -CREATE TABLE delete_test_tbl4 ( - lname char(10), - city char(10), -); -INSERT INTO delete_test_tbl4(lname, city) -VALUES ('lname8','london'), - ('lname9','tokyo'), - ('lname10','mumbai'); -SELECT * FROM delete_test_tbl2 ORDER BY lname; - age | fname | lname | city ------+------------+------------+---------------------- - 50 | fname1 | lname1 | london - 29 | fname10 | lname10 | mumbai - 34 | fname2 | lname2 | paris - 50 | fname3 | lname3 | brussels - 90 | fname4 | lname4 | new york - 26 | fname5 | lname5 | los angeles - 74 | fname6 | lname6 | tokyo - 44 | fname7 | lname7 | oslo - 19 | fname8 | lname8 | hong kong - 61 | fname9 | lname9 | shanghai -(10 rows) - -SELECT * FROM delete_test_tbl3 ORDER BY lname; - year | lname -------+------------ - 51 | lname1 - 36 | lname10 - 34 | lname3 - 25 | lname8 - 95 | lname9 -(5 rows) - -SELECT * FROM delete_test_tbl4 ORDER BY lname; - lname | city -------------+------------ - lname10 | mumbai - lname8 | london - lname9 | tokyo -(3 rows) - -DELETE delete_test_tbl2 -FROM delete_test_tbl2 t2 -INNER JOIN delete_test_tbl3 t3 -ON t2.lname = t3.lname -WHERE year > 50; -SELECT * FROM delete_test_tbl2 ORDER BY lname; - age | fname | lname | city ------+------------+------------+---------------------- - 29 | fname10 | lname10 | mumbai - 34 | fname2 | lname2 | paris - 50 | fname3 | lname3 | brussels - 90 | fname4 | lname4 | new york - 26 | fname5 | lname5 | los angeles - 74 | fname6 | lname6 | tokyo - 44 | fname7 | lname7 | oslo - 19 | fname8 | lname8 | hong kong -(8 rows) - -DELETE delete_test_tbl2 -FROM delete_test_tbl3 t3 -LEFT JOIN delete_test_tbl2 t2 -ON t2.lname = t3.lname -WHERE t3.year < 30 AND t2.age > 40; -SELECT * FROM delete_test_tbl2 ORDER BY lname; - age | fname | lname | city ------+------------+------------+---------------------- - 29 | fname10 | lname10 | mumbai - 34 | fname2 | lname2 | paris - 50 | fname3 | lname3 | brussels - 90 | fname4 | lname4 | new york - 26 | fname5 | lname5 | los angeles - 74 | fname6 | lname6 | tokyo - 44 | fname7 | lname7 | oslo - 19 | fname8 | lname8 | hong kong -(8 rows) - --- delete with outer join on multiple tables -DELETE delete_test_tbl2 -FROM delete_test_tbl4 t4 -LEFT JOIN delete_test_tbl2 t2 -ON t4.city = t2.city -LEFT JOIN delete_test_tbl3 t3 -ON t2.lname = t3.lname -WHERE t4.city = 'mumbai'; -SELECT * FROM delete_test_tbl2 ORDER BY lname; - age | fname | lname | city ------+------------+------------+---------------------- - 34 | fname2 | lname2 | paris - 50 | fname3 | lname3 | brussels - 90 | fname4 | lname4 | new york - 26 | fname5 | lname5 | los angeles - 74 | fname6 | lname6 | tokyo - 44 | fname7 | lname7 | oslo - 19 | fname8 | lname8 | hong kong -(7 rows) - --- delete when target table not shown in JoinExpr -DELETE delete_test_tbl2 -FROM delete_test_tbl4 t4 -LEFT JOIN delete_test_tbl3 t3 -ON t3.lname = t4.lname -WHERE t4.city = 'mumbai'; -SELECT * FROM delete_test_tbl2 ORDER BY lname; - age | fname | lname | city ------+-------+-------+------ -(0 rows) - --- delete with self join -DELETE delete_test_tbl3 -FROM delete_test_tbl3 t1 -INNER JOIN delete_test_tbl3 t2 -on t1.lname = t2.lname; -SELECT * FROM delete_test_tbl3 ORDER BY lname; - year | lname -------+------- -(0 rows) - -DELETE delete_test_tbl2 -FROM delete_test_tbl2 c -JOIN -(SELECT lname, fname, age from delete_test_tbl2) b -on b.lname = c.lname -JOIN -(SELECT lname, city, age from delete_test_tbl2) a -on a.city = c.city; -SELECT * FROM delete_test_tbl2 ORDER BY lname; - age | fname | lname | city ------+-------+-------+------ -(0 rows) - -DELETE delete_test_tbl4 -FROM -(SELECT lname, city from delete_test_tbl4) b -JOIN -(SELECT lname from delete_test_tbl4) a -on a.lname = b.lname; -SELECT * FROM delete_test_tbl4 ORDER BY lname; - lname | city --------+------ -(0 rows) - -DROP TABLE delete_test_tbl; -DROP TABLE delete_test_tbl2; -DROP TABLE delete_test_tbl3; -DROP TABLE delete_test_tbl4; diff --git a/contrib/babelfishpg_tsql/expected/test/babel_like.out b/contrib/babelfishpg_tsql/expected/test/babel_like.out deleted file mode 100644 index 310a0d6da1..0000000000 --- a/contrib/babelfishpg_tsql/expected/test/babel_like.out +++ /dev/null @@ -1,98 +0,0 @@ -set babelfishpg_tsql.sql_dialect = 'tsql'; -select relname from pg_class where relname like '['; -ERROR: pattern matching operators '[' and ']' are not supported for LIKE -select relname from pg_class where relname like ']'; -ERROR: pattern matching operators '[' and ']' are not supported for LIKE -select relname from pg_class where relname like '[]'; -ERROR: pattern matching operators '[' and ']' are not supported for LIKE -select relname from pg_class where relname like NULL; - relname ---------- -(0 rows) - -select relname from pg_class where relname like ''; - relname ---------- -(0 rows) - -select relname from pg_class where relname like 'pg[1:9]class'; -ERROR: pattern matching operators '[' and ']' are not supported for LIKE -select relname from pg_class where relname like 'pg\[1:9\]class'; - relname ---------- -(0 rows) - -select relname from pg_class where relname like 'pg\[1:9 ]class'; -ERROR: pattern matching operators '[' and ']' are not supported for LIKE -select relname from pg_class where relname like 'pg [1:9\]class'; -ERROR: pattern matching operators '[' and ']' are not supported for LIKE -select relname from pg_class where relname like 'pg*[1:9*]class' escape '*'; - relname ---------- -(0 rows) - -select relname from pg_class where relname like 'pg [1:9*]class' escape '*'; -ERROR: pattern matching operators '[' and ']' are not supported for LIKE -select relname from pg_class where relname like 'pg*[1:9 ]class' escape '*'; -ERROR: pattern matching operators '[' and ']' are not supported for LIKE -set babelfishpg_tsql.sql_dialect = 'postgres'; -select relname from pg_class where relname like '['; - relname ---------- -(0 rows) - -select relname from pg_class where relname like ']'; - relname ---------- -(0 rows) - -select relname from pg_class where relname like '[]'; - relname ---------- -(0 rows) - -select relname from pg_class where relname like NULL; - relname ---------- -(0 rows) - -select relname from pg_class where relname like ''; - relname ---------- -(0 rows) - -select relname from pg_class where relname like 'pg[1:9]class'; - relname ---------- -(0 rows) - -select relname from pg_class where relname like 'pg\[1:9\]class'; - relname ---------- -(0 rows) - -select relname from pg_class where relname like 'pg\[1:9 ]class'; - relname ---------- -(0 rows) - -select relname from pg_class where relname like 'pg [1:9\]class'; - relname ---------- -(0 rows) - -select relname from pg_class where relname like 'pg*[1:9*]class' escape '*'; - relname ---------- -(0 rows) - -select relname from pg_class where relname like 'pg [1:9*]class' escape '*'; - relname ---------- -(0 rows) - -select relname from pg_class where relname like 'pg*[1:9 ]class' escape '*'; - relname ---------- -(0 rows) - diff --git a/contrib/babelfishpg_tsql/expected/test/babel_set_command.out b/contrib/babelfishpg_tsql/expected/test/babel_set_command.out deleted file mode 100644 index 813df19745..0000000000 --- a/contrib/babelfishpg_tsql/expected/test/babel_set_command.out +++ /dev/null @@ -1,91 +0,0 @@ --- Simple SET -SET lc_messages ='fr_FR.utf8'; -show lc_messages; - lc_messages -------------- - fr_FR.utf8 -(1 row) - -reset lc_messages; --- Inside transaction with commit -BEGIN; - SET lc_messages = 'fr_FR.utf8'; -COMMIT; -show lc_messages; - lc_messages -------------- - fr_FR.utf8 -(1 row) - -reset lc_messages; --- Inside transaction with rollback -BEGIN; - SET lc_messages = 'fr_FR.utf8'; -ROLLBACK; -show lc_messages; - lc_messages -------------- - C -(1 row) - -reset lc_messages; --- Inside transaction with rollback to savepoint -BEGIN; - SET lc_messages = 'en_GB.utf8'; - SAVEPOINT SP1; - SET lc_messages = 'fr_FR.utf8'; - show lc_messages; - lc_messages -------------- - fr_FR.utf8 -(1 row) - - ROLLBACK TO SAVEPOINT SP1; - show lc_messages; - lc_messages -------------- - en_GB.utf8 -(1 row) - -ROLLBACK; -show lc_messages; - lc_messages -------------- - C -(1 row) - -reset lc_messages; --- Inside procedure -CREATE PROCEDURE lc_proc() -AS $$ -begin - SET lc_messages ='fr_FR.utf8'; - commit; -end; -$$ LANGUAGE plpgsql; -CALL lc_proc(); -show lc_messages; - lc_messages -------------- - fr_FR.utf8 -(1 row) - -drop procedure lc_proc(); -reset lc_messages; -CREATE PROCEDURE lc_proc() -AS $$ -begin - SET lc_messages ='fr_FR.utf8'; - rollback; -end; -$$ LANGUAGE plpgsql; -CALL lc_proc(); -show lc_messages; - lc_messages -------------- - C -(1 row) - --- Cleanup -drop procedure lc_proc(); -reset lc_messages; diff --git a/contrib/babelfishpg_tsql/expected/test/babel_transaction.out b/contrib/babelfishpg_tsql/expected/test/babel_transaction.out deleted file mode 100644 index 2c3031b83d..0000000000 --- a/contrib/babelfishpg_tsql/expected/test/babel_transaction.out +++ /dev/null @@ -1,509 +0,0 @@ -SET babelfishpg_tsql.sql_dialect = 'tsql'; --- setup -drop table TxnTable; -ERROR: table "txntable" does not exist -create table TxnTable(c1 int); --- Begin transaction -> commit transaction -begin transaction; -select @@trancount; - trancount ------------ - 1 -(1 row) - -begin transaction; -select @@trancount; - trancount ------------ - 2 -(1 row) - -set transaction isolation level read committed; -show transaction_isolation; - transaction_isolation ------------------------ - read committed -(1 row) - -show default_transaction_isolation; - default_transaction_isolation -------------------------------- - read committed -(1 row) - -insert into TxnTable values(1); -commit transaction; -select @@trancount; - trancount ------------ - 1 -(1 row) - -commit transaction; -select @@trancount; - trancount ------------ - 0 -(1 row) - -select c1 from TxnTable; - c1 ----- - 1 -(1 row) - --- Begin transaction -> rollback transaction -begin transaction; -insert into TxnTable values(2); -rollback transaction; -select c1 from TxnTable; - c1 ----- - 1 -(1 row) - --- Begin tran -> commit tran -begin tran; -insert into TxnTable values(2); -commit tran; -select c1 from TxnTable; - c1 ----- - 1 - 2 -(2 rows) - --- Begin tran -> rollback tran -begin tran; -select @@trancount; - trancount ------------ - 1 -(1 row) - -begin tran; -set transaction isolation level read uncommitted; -show transaction_isolation; - transaction_isolation ------------------------ - read committed -(1 row) - -show default_transaction_isolation; - default_transaction_isolation -------------------------------- - read uncommitted -(1 row) - -insert into TxnTable values(3); -select @@trancount; - trancount ------------ - 2 -(1 row) - -rollback tran; -select @@trancount; - trancount ------------ - 0 -(1 row) - -select c1 from TxnTable; - c1 ----- - 1 - 2 -(2 rows) - -set transaction isolation level repeatable read; -ERROR: REPEATABLE READ isolation level is not supported -LINE 1: set transaction isolation level repeatable read; - ^ -show transaction_isolation; - transaction_isolation ------------------------ - read committed -(1 row) - -show default_transaction_isolation; - default_transaction_isolation -------------------------------- - read committed -(1 row) - --- Begin transaction -> commit -begin transaction; -insert into TxnTable values(4); -commit; -select c1 from TxnTable; - c1 ----- - 1 - 2 - 4 -(3 rows) - --- Begin transaction -> commit work -begin transaction; -insert into TxnTable values(5); -commit work; -select c1 from TxnTable; - c1 ----- - 1 - 2 - 4 - 5 -(4 rows) - --- Begin transaction -> rollback -begin transaction; -insert into TxnTable values(6); -rollback; -select c1 from TxnTable; - c1 ----- - 1 - 2 - 4 - 5 -(4 rows) - --- Begin transaction -> rollback work -begin transaction; -insert into TxnTable values(7); -rollback work; -select c1 from TxnTable; - c1 ----- - 1 - 2 - 4 - 5 -(4 rows) - --- Begin transaction name -> commit transaction name -begin transaction txn1; -insert into TxnTable values(8); -commit transaction txn1; -select c1 from TxnTable; - c1 ----- - 1 - 2 - 4 - 5 - 8 -(5 rows) - --- Begin transaction name -> rollback transaction name -begin transaction txn1; -insert into TxnTable values(9); -rollback transaction txn1; -select c1 from TxnTable; - c1 ----- - 1 - 2 - 4 - 5 - 8 -(5 rows) - --- Begin tran name -> commit tran name -begin tran txn1; -insert into TxnTable values(10); -commit tran txn1; -select c1 from TxnTable; - c1 ----- - 1 - 2 - 4 - 5 - 8 - 10 -(6 rows) - --- Begin tran name -> rollback tran name -begin tran txn1; -insert into TxnTable values(10); -rollback tran txn1; -select c1 from TxnTable; - c1 ----- - 1 - 2 - 4 - 5 - 8 - 10 -(6 rows) - -truncate table TxnTable; --- save tran name -> rollback tran name -set transaction isolation level snapshot; -show transaction_isolation; - transaction_isolation ------------------------ - repeatable read -(1 row) - -show default_transaction_isolation; - default_transaction_isolation -------------------------------- - repeatable read -(1 row) - -begin transaction txn1; -insert into TxnTable values(1); -save transaction sp1; -select @@trancount; - trancount ------------ - 1 -(1 row) - -insert into TxnTable values(2); -save tran sp2; -insert into TxnTable values(3); -save tran sp2; -select @@trancount; - trancount ------------ - 1 -(1 row) - -insert into TxnTable values(4); -select c1 from TxnTable; - c1 ----- - 1 - 2 - 3 - 4 -(4 rows) - -rollback tran sp2; -select @@trancount; - trancount ------------ - 1 -(1 row) - -select c1 from TxnTable; - c1 ----- - 1 - 2 - 3 -(3 rows) - -rollback tran sp2; -select @@trancount; - trancount ------------ - 1 -(1 row) - -select c1 from TxnTable; - c1 ----- - 1 - 2 -(2 rows) - -rollback tran sp1; -select @@trancount; - trancount ------------ - 1 -(1 row) - -select c1 from TxnTable; - c1 ----- - 1 -(1 row) - -rollback tran txn1; -select @@trancount; - trancount ------------ - 0 -(1 row) - -select c1 from TxnTable; - c1 ----- -(0 rows) - --- begin transaction name -> save transaction name -> rollback to first --- savepoint -begin transaction txn1; -insert into TxnTable values(1); -save transaction sp1; -insert into TxnTable values(2); -save transaction sp2; -insert into TxnTable values(3); -save transaction sp3; -insert into TxnTable values(4); -rollback tran sp1; -rollback tran sp1; -ERROR: savepoint "sp1" does not exist -rollback tran; -select c1 from TxnTable; - c1 ----- -(0 rows) - --- begin transaction name -> save transaction name -> rollback tran name --- Rollback whole transaction -set transaction isolation level serializable; -ERROR: SERIALIZABLE isolation level is not supported -LINE 1: set transaction isolation level serializable; - ^ -show transaction_isolation; - transaction_isolation ------------------------ - repeatable read -(1 row) - -show default_transaction_isolation; - default_transaction_isolation -------------------------------- - repeatable read -(1 row) - -begin transaction txn1; -insert into TxnTable values(1); -save transaction sp1; -begin transaction txn1; -insert into TxnTable values(2); -save transaction sp1; -insert into TxnTable values(3); -select @@trancount; - trancount ------------ - 2 -(1 row) - -rollback tran txn1; -select @@trancount; - trancount ------------ - 0 -(1 row) - -select c1 from TxnTable; - c1 ----- -(0 rows) - --- begin transaction -> save transaction name -> rollback to savepoint --- commit transaction -begin transaction txn1; -insert into TxnTable values(1); -save transaction sp1; -insert into TxnTable values(2); -select c1 from TxnTable; - c1 ----- - 1 - 2 -(2 rows) - -rollback tran sp1; -commit transaction; -select c1 from TxnTable; - c1 ----- - 1 -(1 row) - --- begin transaction -> save transaction name -> rollback to savepoint --- save transaction name -> commit transaction -begin transaction txn1; -insert into TxnTable values(3); -save transaction sp1; -insert into TxnTable values(4); -select c1 from TxnTable; - c1 ----- - 1 - 3 - 4 -(3 rows) - -rollback tran sp1; -save transaction sp2; -insert into TxnTable values(5); -commit transaction; -select c1 from TxnTable; - c1 ----- - 1 - 3 - 5 -(3 rows) - --- begin transaction -> save transaction name -> error -> rollback to savepoint --- commit transaction -begin transaction txn1; -insert into TxnTable values(6); -save transaction sp1; -insert into TxnTable values(7); -select c1 frm TxnTable; -ERROR: syntax error at or near "TxnTable" -LINE 1: select c1 frm TxnTable; - ^ -rollback tran sp1; -commit transaction; -select c1 from TxnTable; - c1 ----- - 1 - 3 - 5 - 6 -(4 rows) - --- create and execute procedure with transaction commands --- \tsql on --- create procedure txnproc as --- begin tran; --- insert into TxnTable values(8); --- select c1 from TxnTable; --- save tran sp1; --- commit; --- rollback tran; --- go --- execute txnproc; --- go --- \tsql off --- drop procedure txnproc; --- transaction syntax error -begin; -ERROR: syntax error at or near ";" -LINE 1: begin; - ^ -begin txn1; -ERROR: syntax error at or near "txn1" -LINE 1: begin txn1; - ^ -commit txn1; -ERROR: syntax error at or near "txn1" -LINE 1: commit txn1; - ^ -rollback txx1; -ERROR: syntax error at or near "txx1" -LINE 1: rollback txx1; - ^ --- invalid transaction name -begin transaction txn1; -rollback transaction txn2; -ERROR: savepoint "txn2" does not exist -rollback; -drop table TxnTable; -reset babelfish_pg_tsql.sql_dialect; diff --git a/contrib/babelfishpg_tsql/expected/test/babel_typecode.out b/contrib/babelfishpg_tsql/expected/test/babel_typecode.out deleted file mode 100644 index 4802f93104..0000000000 --- a/contrib/babelfishpg_tsql/expected/test/babel_typecode.out +++ /dev/null @@ -1,40 +0,0 @@ -SET babelfishpg_tsql.sql_dialect = 'tsql'; --- test typecode list sys table -SELECT pg_namespace, pg_typname, tsql_typname, type_family_priority, priority, sql_variant_hdr_size FROM sys.babelfish_typecode_list(); - pg_namespace | pg_typname | tsql_typname | type_family_priority | priority | sql_variant_hdr_size ---------------+------------------+------------------+----------------------+----------+---------------------- - sys | sql_variant | sql_variant | 1 | 1 | 1 - sys | datetimeoffset | datetimeoffset | 2 | 2 | 2 - sys | datetime2 | datetime2 | 2 | 3 | 2 - sys | datetime | datetime | 2 | 4 | 1 - sys | smalldatetime | smalldatetime | 2 | 5 | 1 - pg_catalog | date | date | 2 | 6 | 1 - pg_catalog | time | time | 2 | 7 | 2 - pg_catalog | float8 | float | 3 | 8 | 1 - pg_catalog | float4 | real | 3 | 9 | 1 - pg_catalog | numeric | numeric | 4 | 10 | 3 - sys | money | money | 4 | 11 | 1 - sys | smallmoney | smallmoney | 4 | 12 | 1 - pg_catalog | int8 | bigint | 4 | 13 | 1 - pg_catalog | int4 | int | 4 | 14 | 1 - pg_catalog | int2 | smallint | 4 | 15 | 1 - sys | tinyint | tinyint | 4 | 16 | 1 - sys | bit | bit | 4 | 17 | 1 - sys | nvarchar | nvarchar | 5 | 18 | 5 - sys | nchar | nchar | 5 | 19 | 5 - sys | varchar | varchar | 5 | 20 | 5 - sys | bpchar | char | 5 | 21 | 5 - sys | varbinary | varbinary | 6 | 22 | 3 - sys | binary | binary | 6 | 23 | 3 - sys | uniqueidentifier | uniqueidentifier | 7 | 24 | 1 - pg_catalog | text | text | 5 | 25 | 5 - sys | ntext | ntext | 5 | 26 | 5 - sys | image | image | 5 | 27 | 5 - pg_catalog | xml | xml | 5 | 28 | 5 - pg_catalog | bpchar | char | 5 | 29 | 5 - sys | decimal | decimal | 5 | 30 | 5 - sys | sysname | sysname | 5 | 31 | 5 - sys | rowversion | timestamp | 8 | 32 | 3 - sys | timestamp | timestamp | 8 | 33 | 3 -(33 rows) - diff --git a/contrib/babelfishpg_tsql/expected/test/babel_uniqueidentifier.out b/contrib/babelfishpg_tsql/expected/test/babel_uniqueidentifier.out deleted file mode 100644 index 3ee92a29dc..0000000000 --- a/contrib/babelfishpg_tsql/expected/test/babel_uniqueidentifier.out +++ /dev/null @@ -1,175 +0,0 @@ -SET babelfishpg_tsql.sql_dialect = 'tsql'; -create table t1 (a uniqueidentifier, b uniqueidentifier, c uniqueidentifier, primary key(a)); -insert into t1(a) values ('6F9619FF-8B86-D011-B42D-00C04FC964FF'); -insert into t1(a) values ('6F9619FF-8B86-D011-B42D-00C04FC964FF'); -- trigger error -ERROR: duplicate key value violates unique constraint "t1_pkey" -DETAIL: Key (a)=(6F9619FF-8B86-D011-B42D-00C04FC964FF) already exists. -select * from t1; - a | b | c ---------------------------------------+---+--- - 6F9619FF-8B86-D011-B42D-00C04FC964FF | | -(1 row) - -insert into t1 values ('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', newid(), newid()); -explain (costs off) select * from t1 where a = '6F9619FF-8B86-D011-B42D-00C04FC964FF'; -- test PK - QUERY PLAN ------------------------------------------------------------------------------- - Index Scan using t1_pkey on t1 - Index Cond: (a = '6F9619FF-8B86-D011-B42D-00C04FC964FF'::uniqueidentifier) -(2 rows) - -select count(*) from t1 where a = '6F9619FF-8B86-D011-B42D-00C04FC964FF'; - count -------- - 1 -(1 row) - -select count(*) from t1 where a > '6F9619FF-8B86-D011-B42D-00C04FC964FF'; - count -------- - 1 -(1 row) - -select count(*) from t1 where a >= '6F9619FF-8B86-D011-B42D-00C04FC964FF'; - count -------- - 2 -(1 row) - -select count(*) from t1 where a < 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'; - count -------- - 1 -(1 row) - -select count(*) from t1 where a <= 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'; - count -------- - 2 -(1 row) - -select count(*) from t1 where a <> 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'; - count -------- - 1 -(1 row) - --- newid's value could not be verified -insert into t1 values (newid(), newid(), newid()); -insert into t1 values (newid(), newid(), newid()); -insert into t1 values (newid(), newid(), newid()); -select count(a) from t1; - count -------- - 5 -(1 row) - -create table t2 (like t1); -insert into t2 select * from t1 order by a; -select count(distinct a) from t2; - count -------- - 5 -(1 row) - --- test index (need more data) -create table t3 ( a uniqueidentifier, b uniqueidentifier); --- create inital distinct values -insert into t3 values (newid(), newid()); -insert into t3 values (newid(), newid()); -insert into t3 values (newid(), newid()); -insert into t3 values (newid(), newid()); -create index t3_a on t3 using btree (a); -create index t3_b on t3 using hash (b); --- test truncate feature of uniqueidentifier_in -create table t4 ( a uniqueidentifier); -insert into t4 values ('6F9619FF-8B86-D011-B42D-00C04FC964FF'); -insert into t4 values ('6F9619FF-8B86-D011-B42D-00C04FC964FFwrong'); -- characters exceeding are truncated -insert into t4 values ('{6F9619FF-8B86-D011-B42D-00C04FC964FF}'); -- with braces -insert into t4 values ('{6F9619FF-8B86-D011-B42D-00C04FC964FFwrong'); -- error due to no matching brace -ERROR: invalid input syntax for type uuid: "{6F9619FF-8B86-D011-B42D-00C04FC964FFwrong" -LINE 1: insert into t4 values ('{6F9619FF-8B86-D011-B42D-00C04FC964F... - ^ -insert into t4 values ('6F9619FF-8B86-D011-B42D-00C04FC964FF}'); -- single brace at the end are truncated -select * from t4; - a --------------------------------------- - 6F9619FF-8B86-D011-B42D-00C04FC964FF - 6F9619FF-8B86-D011-B42D-00C04FC964FF - 6F9619FF-8B86-D011-B42D-00C04FC964FF - 6F9619FF-8B86-D011-B42D-00C04FC964FF -(4 rows) - -reset babelfishpg_tsql.sql_dialect; -SET ENABLE_SEQSCAN = OFF; -SET ENABLE_BITMAPSCAN = OFF; -SET SEARCH_PATH = sys, public; -select name, setting from pg_settings where name in ('enable_seqscan', 'enable_bitmapscan'); - name | setting --------------------+--------- - enable_bitmapscan | off - enable_seqscan | off -(2 rows) - -explain (costs off) select * from t3 where a = 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'; -- test btree index - QUERY PLAN ------------------------------------------------------------------------------- - Index Scan using t3_at386baf2ea94a757b06124ac7a4c87f41f on t3 - Index Cond: (a = 'A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11'::uniqueidentifier) -(2 rows) - -explain (costs off) select * from t3 where b = 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'; -- test hash index - QUERY PLAN ------------------------------------------------------------------------------- - Index Scan using t3_bt3e585137b3a7e6e454e6dffa0e011ffe7 on t3 - Index Cond: (b = 'A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11'::uniqueidentifier) -(2 rows) - --- assignment cast, should have same behavior as normal insert -set babelfishpg_tsql.sql_dialect = "tsql"; -create table t5 ( a uniqueidentifier); -insert into t5 values (cast('6F9619FF-8B86-D011-B42D-00C04FC964FF' as varchar(50))); -insert into t5 values (cast('6F9619FF-8B86-D011-B42D-00C04FC964FFwrong' as varchar(50))); -- characters exceeding are truncated -insert into t5 values (cast('{6F9619FF-8B86-D011-B42D-00C04FC964FF}' as varchar(50))); -- with braces -insert into t5 values (cast('{6F9619FF-8B86-D011-B42D-00C04FC964FFwrong' as varchar(50))); -- error due to no matching brace -ERROR: invalid input syntax for type uuid: "{6F9619FF-8B86-D011-B42D-00C04FC964FFwrong" -insert into t5 values (cast('6F9619FF-8B86-D011-B42D-00C04FC964FF}' as varchar(50))); -- single brace at the end are truncated -insert into t5 values (cast('6F9619FF-8B86-D011-B42D-00C04FC964FF' as nvarchar(50))); -insert into t5 values (cast('6F9619FF-8B86-D011-B42D-00C04FC964FFwrong' as nvarchar(50))); -- characters exceeding are truncated -insert into t5 values (cast('{6F9619FF-8B86-D011-B42D-00C04FC964FF}' as nvarchar(50))); -- with braces -insert into t5 values (cast('{6F9619FF-8B86-D011-B42D-00C04FC964FFwrong' as nvarchar(50))); -- error due to no matching brace -ERROR: invalid input syntax for type uuid: "{6F9619FF-8B86-D011-B42D-00C04FC964FFwrong" -insert into t5 values (cast('6F9619FF-8B86-D011-B42D-00C04FC964FF}' as nvarchar(50))); -- single brace at the end are truncated --- error cases, implicit cast not supported -select * from t5 where a = cast('6F9619FF-8B86-D011-B42D-00C04FC964FF' as varchar(50)); - a --------------------------------------- - 6F9619FF-8B86-D011-B42D-00C04FC964FF - 6F9619FF-8B86-D011-B42D-00C04FC964FF - 6F9619FF-8B86-D011-B42D-00C04FC964FF - 6F9619FF-8B86-D011-B42D-00C04FC964FF - 6F9619FF-8B86-D011-B42D-00C04FC964FF - 6F9619FF-8B86-D011-B42D-00C04FC964FF - 6F9619FF-8B86-D011-B42D-00C04FC964FF - 6F9619FF-8B86-D011-B42D-00C04FC964FF -(8 rows) - -select * from t5 where a = cast('6F9619FF-8B86-D011-B42D-00C04FC964FF' as nvarchar(50)); - a --------------------------------------- - 6F9619FF-8B86-D011-B42D-00C04FC964FF - 6F9619FF-8B86-D011-B42D-00C04FC964FF - 6F9619FF-8B86-D011-B42D-00C04FC964FF - 6F9619FF-8B86-D011-B42D-00C04FC964FF - 6F9619FF-8B86-D011-B42D-00C04FC964FF - 6F9619FF-8B86-D011-B42D-00C04FC964FF - 6F9619FF-8B86-D011-B42D-00C04FC964FF - 6F9619FF-8B86-D011-B42D-00C04FC964FF -(8 rows) - -reset babelfishpg_tsql.sql_dialect; -drop table t1; -drop table t2; -drop table t3; -drop table t4; -drop table t5; diff --git a/contrib/babelfishpg_tsql/sql/test/babel_emoji.sql b/contrib/babelfishpg_tsql/sql/test/babel_emoji.sql deleted file mode 100644 index e9fbce7a2e..0000000000 --- a/contrib/babelfishpg_tsql/sql/test/babel_emoji.sql +++ /dev/null @@ -1,76 +0,0 @@ -CREATE EXTENSION IF NOT EXISTS "babelfishpg_tsql" CASCADE; - --- Test SYS.NCHAR, SYS.NVARCHAR and SYS.VARCHAR --- nchar is already available in postgres dialect -select CAST('£' AS nchar(1)); --- nvarchar is not available in postgres dialect -select CAST('£' AS nvarchar); - --- both are available in tsql dialect -set babelfishpg_tsql.sql_dialect = 'tsql'; -select CAST('£' AS nchar(2)); -select CAST('£' AS nvarchar(2)); - --- multi-byte character doesn't fit in nchar(1) in tsql if it --- would require a UTF16-surrogate-pair on output -select CAST('£' AS char(1)); -- allowed -select CAST('£' AS sys.nchar(1)); -- allowed -select CAST('£' AS sys.nvarchar(1)); -- allowed -select CAST('£' AS sys.varchar(1)); -- allowed - -select CAST('😀' AS char(1)); -- not allowed TODO: fix BABEL-3543 -select CAST('😀' AS sys.nchar(1)); -- not allowed -select CAST('😀' AS sys.nvarchar(1)); -- not allowed -select CAST('😀' AS sys.varchar(1)); -- not allowed TODO: fix BABEL-3543 - --- Check that things work the same in postgres dialect -reset babelfishpg_tsql.sql_dialect; -select CAST('£' AS char(1)); -select CAST('£' AS sys.nchar(1)); -select CAST('£' AS sys.nvarchar(1)); -select CAST('£' AS sys.varchar(1)); -select CAST('😀' AS char(1)); -select CAST('😀' AS sys.nchar(1)); -- this should not be allowed as nchar is T-SQL type -select CAST('😀' AS sys.nvarchar(1)); -- this should not be allowed as nvarchar is T-SQL type -select CAST('😀' AS sys.varchar(1)); -- this should not be allowed as sys.varchar is T-SQL type TODO: fix BABEL-3543 -set babelfishpg_tsql.sql_dialect = 'tsql'; - --- test normal create domain works when apg_enable_domain_typmod is enabled -set apg_enable_domain_typmod true; -create domain varchar3 as varchar(3); -select CAST('ab£' AS varchar3); -select CAST('ab😀' AS varchar3); --not allowed TODO: fix BABEL-3543 - --- don't allow surrogate pairs to exceed max length -select CAST('😀b' AS char(1)); -- not allowed TODO: fix BABEL-3543 -select CAST('😀b' AS nchar(1)); -select CAST('😀b' AS nvarchar(1)); -select CAST('😀b' AS sys.varchar(1)); -- not allowed TODO: fix BABEL-3543 - --- default length of nchar/char is 1 in tsql (and pg) -create table testing1(col nchar); -\d testing1; - --- check length at insert -insert into testing1 (col) select '😀'; -- not allowed TODO: fix BABEL-3543 -select * from testing1; - --- default length of nvarchar in tsql is 1 -create table testing2(col nvarchar); -insert into testing2 (col) select '😀'; -- not allowed TODO: fix BABEL-3543 -select * from testing2; - --- default length of varchar in tsql is 1 -create table testing4(col sys.varchar); -insert into testing4 (col) select '😀'; -- not allowed TODO: fix BABEL-3543 --- space is automatically truncated -insert into testing2 (col) select '£ '; -insert into testing2 (col) select '🤓 '; -- not allowed TODO: fix BABEL-3543 -select * from testing4; - - -drop table testing1; -drop table testing2; -drop table testing3; -drop table testing4; -reset babelfishpg_tsql.sql_dialect; \ No newline at end of file diff --git a/contrib/babelfishpg_tsql/sql/test/babel_like.sql b/contrib/babelfishpg_tsql/sql/test/babel_like.sql deleted file mode 100644 index 61aeead8b2..0000000000 --- a/contrib/babelfishpg_tsql/sql/test/babel_like.sql +++ /dev/null @@ -1,29 +0,0 @@ -set babelfishpg_tsql.sql_dialect = 'tsql'; -select relname from pg_class where relname like '['; -select relname from pg_class where relname like ']'; -select relname from pg_class where relname like '[]'; -select relname from pg_class where relname like NULL; -select relname from pg_class where relname like ''; -select relname from pg_class where relname like 'pg[1:9]class'; -select relname from pg_class where relname like 'pg\[1:9\]class'; -select relname from pg_class where relname like 'pg\[1:9 ]class'; -select relname from pg_class where relname like 'pg [1:9\]class'; - -select relname from pg_class where relname like 'pg*[1:9*]class' escape '*'; -select relname from pg_class where relname like 'pg [1:9*]class' escape '*'; -select relname from pg_class where relname like 'pg*[1:9 ]class' escape '*'; - -set babelfishpg_tsql.sql_dialect = 'postgres'; -select relname from pg_class where relname like '['; -select relname from pg_class where relname like ']'; -select relname from pg_class where relname like '[]'; -select relname from pg_class where relname like NULL; -select relname from pg_class where relname like ''; -select relname from pg_class where relname like 'pg[1:9]class'; -select relname from pg_class where relname like 'pg\[1:9\]class'; -select relname from pg_class where relname like 'pg\[1:9 ]class'; -select relname from pg_class where relname like 'pg [1:9\]class'; - -select relname from pg_class where relname like 'pg*[1:9*]class' escape '*'; -select relname from pg_class where relname like 'pg [1:9*]class' escape '*'; -select relname from pg_class where relname like 'pg*[1:9 ]class' escape '*'; diff --git a/contrib/babelfishpg_tsql/sql/test/babel_set_command.sql b/contrib/babelfishpg_tsql/sql/test/babel_set_command.sql deleted file mode 100644 index 32adda0241..0000000000 --- a/contrib/babelfishpg_tsql/sql/test/babel_set_command.sql +++ /dev/null @@ -1,57 +0,0 @@ --- Simple SET -SET lc_messages ='fr_FR.utf8'; -show lc_messages; -reset lc_messages; - --- Inside transaction with commit -BEGIN; - SET lc_messages = 'fr_FR.utf8'; -COMMIT; -show lc_messages; -reset lc_messages; - --- Inside transaction with rollback -BEGIN; - SET lc_messages = 'fr_FR.utf8'; -ROLLBACK; -show lc_messages; -reset lc_messages; - --- Inside transaction with rollback to savepoint -BEGIN; - SET lc_messages = 'en_GB.utf8'; - SAVEPOINT SP1; - SET lc_messages = 'fr_FR.utf8'; - show lc_messages; - ROLLBACK TO SAVEPOINT SP1; - show lc_messages; -ROLLBACK; -show lc_messages; -reset lc_messages; - --- Inside procedure -CREATE PROCEDURE lc_proc() -AS $$ -begin - SET lc_messages ='fr_FR.utf8'; - commit; -end; -$$ LANGUAGE plpgsql; -CALL lc_proc(); -show lc_messages; -drop procedure lc_proc(); -reset lc_messages; - -CREATE PROCEDURE lc_proc() -AS $$ -begin - SET lc_messages ='fr_FR.utf8'; - rollback; -end; -$$ LANGUAGE plpgsql; -CALL lc_proc(); -show lc_messages; - --- Cleanup -drop procedure lc_proc(); -reset lc_messages; diff --git a/test/JDBC/expected/babel_219.out b/test/JDBC/expected/babel_219.out new file mode 100644 index 0000000000..57683c502e --- /dev/null +++ b/test/JDBC/expected/babel_219.out @@ -0,0 +1,81 @@ +-- This test should be run without installing the babelfishpg_tsql extension +-- BABEL-219 test a domain named varchar in schema other than sys +-- is not affected by the fix of BABEL-219 +select cast('' as varchar); +GO +~~START~~ +varchar + +~~END~~ + +select cast('a' as varchar); -- pg_catalog.varchar should work +GO +~~START~~ +varchar +a +~~END~~ + + +-- Explicitly add pg_catalog to tail of search_path, +-- to force varchar default to public.varchar +select set_config('search_path', current_setting('search_path') + ', pg_catalog', false); +GO +~~START~~ +text +master_dbo, "$user", sys, pg_catalog, pg_catalog +~~END~~ + +-- Set tsql dialet so the fix for BABEL-219 can kick in +select cast('a' as varchar); -- varchar default to public.varchar. should fail exactly the same way as explicitly specifying public.varchar +GO +~~START~~ +varchar +a +~~END~~ + +select cast('' as varchar); -- varchar default to public.varchar. should pass +GO +~~START~~ +varchar + +~~END~~ + +create table t1(col varchar); +insert into t1 (col) select 'a'; -- fail +insert into t1 (col) select ''; -- pass +select * from t1 ORDER BY col; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +varchar + +a +~~END~~ + + +-- verify behavior of public.varchar is unchanged in tsql dialect +create table t2(col varchar); +GO +insert into t2 (col) select 'a'; -- fail +insert into t2 (col) select ''; -- pass +select * from t2 ORDER BY col; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +varchar + +a +~~END~~ + + +-- Clean up +drop table t1; +GO +drop table t2; +GO diff --git a/test/JDBC/expected/babel_collection.out b/test/JDBC/expected/babel_collection.out new file mode 100644 index 0000000000..ccc999a202 --- /dev/null +++ b/test/JDBC/expected/babel_collection.out @@ -0,0 +1,858 @@ +-- nvarchar is not supported in PG +create table testing1(col nvarchar(60)); -- expect this to fail in the Postgres dialect +GO + +-- check the babelfish version +select cast( + case + when cast(sys.SERVERPROPERTY('BabelfishVersion') as varchar(20)) LIKE '_._._' + THEN 'valid' + else 'invalid' + end as sys.varchar(20)); +GO +~~START~~ +varchar +valid +~~END~~ + +-- nvarchar is supported in tsql dialect +insert into testing1 (col) select N'Muffler'; +insert into testing1 (col) select N'Mülle'; +insert into testing1 (col) select N'MX Systems'; +insert into testing1 (col) select N'Magic'; +select * from testing1 order by col; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +nvarchar +Magic +Muffler +Mülle +MX Systems +~~END~~ + + +-- test case insensitive collation +create table testing2 (col varchar(20) collate SQL_Latin1_General_CP1_CI_AS); +GO + +insert into testing2 values ('JONES'); +insert into testing2 values ('jones'); +insert into testing2 values ('Jones'); +insert into testing2 values ('JoNes'); +insert into testing2 values ('JoNés'); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +select * from testing2 where col collate BBF_Unicode_General_CS_AS = 'JoNes'; +GO +~~START~~ +varchar +JoNes +~~END~~ + +select * from testing2 where col collate BBF_Unicode_General_CI_AS = 'JoNes'; +GO +~~START~~ +varchar +JONES +jones +Jones +JoNes +~~END~~ + +select * from testing2 where col collate BBF_Unicode_General_CI_AI = 'JoNes'; +GO +~~START~~ +varchar +JONES +jones +Jones +JoNes +JoNés +~~END~~ + +select * from testing2 where col collate BBF_Unicode_General_CS_AI = 'JoNes'; +GO +~~START~~ +varchar +JoNes +JoNés +~~END~~ + + +-- test case insensitivity for default collation +create table testing3 (c1 varchar(20), c2 char(20), c3 nvarchar(20)); +GO + +insert into testing3 values ('JONES','JONES','JONES'); +insert into testing3 values ('JoneS','JoneS','JoneS'); +insert into testing3 values ('jOnes','jOnes','jOnes'); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +select c1 from testing3 where c1='jones'; +GO +~~START~~ +varchar +JONES +JoneS +jOnes +~~END~~ + +select c2 from testing3 where c2='jones'; +GO +~~START~~ +char +JONES +JoneS +jOnes +~~END~~ + +select c3 from testing3 where c3='jones'; +GO +~~START~~ +nvarchar +JONES +JoneS +jOnes +~~END~~ + + +-- test LIKE to ILIKE transformation +create table testing4 (c1 varchar(20), c2 char(20), c3 nvarchar(20)); +create index c1_idx on testing4 (c1); +GO + +insert into testing4 values ('JONES','JONES','JONES'); +insert into testing4 values ('JoneS','JoneS','JoneS'); +insert into testing4 values ('jOnes','jOnes','jOnes'); +insert into testing4 values ('abcD','AbcD','ABCd'); +insert into testing4 values ('äbĆD','äḃcD','äƀCd'); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +-- set enable_seqscan doesn't work from the TSQL dialect, so switch +-- dialects, disable sequential scan so we see some index-based plans, +-- then switch back to the TSQL dialect +-- +select set_config('enable_seqscan','off','false'); +GO +~~START~~ +text +off +~~END~~ + + + +SET babelfish_showplan_all ON; +GO +-- test that like is case-insenstive +select c1 from testing4 where c1 LIKE 'jones'; -- this gets converted to '=' +GO +~~START~~ +text +Query Text: select c1 from testing4 where c1 LIKE 'jones' +Bitmap Heap Scan on testing4 (cost=11.40..29.53 rows=3 width=32) + Filter: ((c1)::text = 'jones'::text COLLATE "default") + -> Bitmap Index Scan on c1_idxtesting49a168d73f3ba5aacdfd495b931b8d187 (cost=0.00..11.40 rows=650 width=0) +~~END~~ + + +select c1 from testing4 where c1 LIKE 'Jon%'; +GO +~~START~~ +text +Query Text: select c1 from testing4 where c1 LIKE 'Jon%' +Bitmap Heap Scan on testing4 (cost=11.40..32.78 rows=1 width=32) + Filter: (((c1)::text ~~* 'Jon%'::text COLLATE "default") AND ((c1)::text >= 'Jon'::text COLLATE "default") AND ((c1)::text < 'Jon?'::text)) + -> Bitmap Index Scan on c1_idxtesting49a168d73f3ba5aacdfd495b931b8d187 (cost=0.00..11.40 rows=650 width=0) +~~END~~ + + +select c1 from testing4 where c1 LIKE 'jone_'; +GO +~~START~~ +text +Query Text: select c1 from testing4 where c1 LIKE 'jone_' +Bitmap Heap Scan on testing4 (cost=11.40..32.78 rows=1 width=32) + Filter: (((c1)::text ~~* 'jone_'::text COLLATE "default") AND ((c1)::text >= 'jone'::text COLLATE "default") AND ((c1)::text < 'jone?'::text)) + -> Bitmap Index Scan on c1_idxtesting49a168d73f3ba5aacdfd495b931b8d187 (cost=0.00..11.40 rows=650 width=0) +~~END~~ + + +select c1 from testing4 where c1 LIKE '_one_'; +GO +~~START~~ +text +Query Text: select c1 from testing4 where c1 LIKE '_one_' +Bitmap Heap Scan on testing4 (cost=11.40..29.53 rows=5 width=32) + Filter: ((c1)::text ~~* '_one_'::text COLLATE "default") + -> Bitmap Index Scan on c1_idxtesting49a168d73f3ba5aacdfd495b931b8d187 (cost=0.00..11.40 rows=650 width=0) +~~END~~ + + +select c1 from testing4 where c1 LIKE '%on%s'; +GO +~~START~~ +text +Query Text: select c1 from testing4 where c1 LIKE '%on%s' +Bitmap Heap Scan on testing4 (cost=11.41..29.53 rows=26 width=32) + Filter: ((c1)::text ~~* '%on%s'::text COLLATE "default") + -> Bitmap Index Scan on c1_idxtesting49a168d73f3ba5aacdfd495b931b8d187 (cost=0.00..11.40 rows=650 width=0) +~~END~~ + + +-- test that like is accent-senstive for CI_AS collation +select c1 from testing4 where c1 LIKE 'ab%'; +GO +~~START~~ +text +Query Text: select c1 from testing4 where c1 LIKE 'ab%' +Bitmap Heap Scan on testing4 (cost=11.40..32.78 rows=1 width=32) + Filter: (((c1)::text ~~* 'ab%'::text COLLATE "default") AND ((c1)::text >= 'ab'::text COLLATE "default") AND ((c1)::text < 'ab?'::text)) + -> Bitmap Index Scan on c1_idxtesting49a168d73f3ba5aacdfd495b931b8d187 (cost=0.00..11.40 rows=650 width=0) +~~END~~ + +select c1 from testing4 where c1 LIKE 'äb%'; +GO +~~START~~ +text +Query Text: select c1 from testing4 where c1 LIKE 'äb%' +Bitmap Heap Scan on testing4 (cost=11.40..32.78 rows=1 width=32) + Filter: (((c1)::text ~~* 'äb%'::text COLLATE "default") AND ((c1)::text >= 'äb'::text COLLATE "default") AND ((c1)::text < 'äb?'::text)) + -> Bitmap Index Scan on c1_idxtesting49a168d73f3ba5aacdfd495b931b8d187 (cost=0.00..11.40 rows=650 width=0) +~~END~~ + +select c1 from testing4 where c1 LIKE 'äḃĆ_'; +GO +~~START~~ +text +Query Text: select c1 from testing4 where c1 LIKE 'ä??_' +Bitmap Heap Scan on testing4 (cost=11.40..32.78 rows=1 width=32) + Filter: (((c1)::text ~~* 'ä??_'::text COLLATE "default") AND ((c1)::text >= 'ä??'::text COLLATE "default") AND ((c1)::text < 'ä???'::text)) + -> Bitmap Index Scan on c1_idxtesting49a168d73f3ba5aacdfd495b931b8d187 (cost=0.00..11.40 rows=650 width=0) +~~END~~ + + +-- test not like +select c1 from testing4 where c1 NOT LIKE 'jones'; +GO +~~START~~ +text +Query Text: select c1 from testing4 where c1 NOT LIKE 'jones' +Bitmap Heap Scan on testing4 (cost=11.56..29.69 rows=647 width=32) + Filter: ((c1)::text <> 'jones'::text COLLATE "default") + -> Bitmap Index Scan on c1_idxtesting49a168d73f3ba5aacdfd495b931b8d187 (cost=0.00..11.40 rows=650 width=0) +~~END~~ + + +select c1 from testing4 where c1 NOT LIKE 'jone%'; +GO +~~START~~ +text +Query Text: select c1 from testing4 where c1 NOT LIKE 'jone%' +Bitmap Heap Scan on testing4 (cost=11.56..32.94 rows=648 width=32) + Filter: (((c1)::text !~~* 'jone%'::text COLLATE "default") OR ((c1)::text < 'jone'::text COLLATE "default") OR ((c1)::text >= 'jone?'::text)) + -> Bitmap Index Scan on c1_idxtesting49a168d73f3ba5aacdfd495b931b8d187 (cost=0.00..11.40 rows=650 width=0) +~~END~~ + + +select c1 from testing4 where c1 NOT LIKE 'ä%'; +GO +~~START~~ +text +Query Text: select c1 from testing4 where c1 NOT LIKE 'ä%' +Bitmap Heap Scan on testing4 (cost=11.55..32.92 rows=592 width=32) + Filter: (((c1)::text !~~* 'ä%'::text COLLATE "default") OR ((c1)::text < 'ä'::text COLLATE "default") OR ((c1)::text >= 'ä?'::text)) + -> Bitmap Index Scan on c1_idxtesting49a168d73f3ba5aacdfd495b931b8d187 (cost=0.00..11.40 rows=650 width=0) +~~END~~ + + + +-- wild card literals are transformed to equal +select c1 from testing4 where c1 LIKE '\%ones'; +GO +~~START~~ +text +Query Text: select c1 from testing4 where c1 LIKE '\%ones' +Bitmap Heap Scan on testing4 (cost=11.40..29.53 rows=3 width=32) + Filter: ((c1)::text = '%ones'::text COLLATE "default") + -> Bitmap Index Scan on c1_idxtesting49a168d73f3ba5aacdfd495b931b8d187 (cost=0.00..11.40 rows=650 width=0) +~~END~~ + + +select c1 from testing4 where c1 LIKE '\_ones'; +GO +~~START~~ +text +Query Text: select c1 from testing4 where c1 LIKE '\_ones' +Bitmap Heap Scan on testing4 (cost=11.40..29.53 rows=3 width=32) + Filter: ((c1)::text = '_ones'::text COLLATE "default") + -> Bitmap Index Scan on c1_idxtesting49a168d73f3ba5aacdfd495b931b8d187 (cost=0.00..11.40 rows=650 width=0) +~~END~~ + + +SET babelfish_showplan_all OFF; +GO +-- test combining with other string functions +select c1 from testing4 where c1 LIKE lower('_ones'); +GO +~~START~~ +varchar +JONES +JoneS +jOnes +~~END~~ + +select c1 from testing4 where c1 LIKE upper('_ones'); +GO +~~START~~ +varchar +JONES +JoneS +jOnes +~~END~~ + +select c1 from testing4 where c1 LIKE concat('_on','_s'); +GO +~~START~~ +varchar +JONES +JoneS +jOnes +~~END~~ + +select c1 from testing4 where c1 LIKE concat('a','%d'); +GO +~~START~~ +varchar +abcD +~~END~~ + +select c1 from testing4 where c1 NOT LIKE lower('%s'); +GO +~~START~~ +varchar +abcD +äb?D +~~END~~ + +-- test sub-queries +Select * from testing4 where c1 LIKE (select c1 from testing4 where c1 LIKE 'AbcD'); +GO +~~START~~ +varchar#!#char#!#nvarchar +abcD#!#AbcD #!#ABCd +~~END~~ + +Select * from testing4 where c2 NOT LIKE (select c2 from testing4 where c2 NOT LIKE 'jo%' AND c2 NOT LIKE 'ä%'); +GO +~~START~~ +varchar#!#char#!#nvarchar +JONES#!#JONES #!#JONES +JoneS#!#JoneS #!#JoneS +jOnes#!#jOnes #!#jOnes +äb?D#!#ä?cD #!#äƀCd +~~END~~ + +Select * from testing4 where c3 LIKE (select c3 from testing4 where c3 NOT LIKE'jo%' AND c3 NOT LIKE 'ä%'); +GO +~~START~~ +varchar#!#char#!#nvarchar +abcD#!#AbcD #!#ABCd +~~END~~ + +with p1 as (select c1 from testing4 where c1 LIKE '__Ć_'), +p2 as (select c3 from testing4 where c3 LIKE 'äƀ__') +select * from p1 union all select * from p2; +GO +~~START~~ +varchar +äb?D +ä?Cd +~~END~~ + +-- test case expression +select c2,(case when c2 LIKE '_bc%' then 1 when c2 LIKE 'jon%' then 2 when c3 LIKE 'ä%' then 3 end) from testing4; +GO +~~START~~ +char#!#int +JONES #!#2 +JoneS #!#2 +jOnes #!#2 +AbcD #!#1 +ä?cD #!#3 +~~END~~ + +-- test that LIKE transformation is applied only for CI_AS column +create table testing5(c1 varchar(20) COLLATE SQL_Latin1_General_CP1_CS_AS); +GO +insert into testing5 values ('JONES'); +insert into testing5 values ('JoneS'); +insert into testing5 values ('abcD'); +insert into testing5 values ('äbĆD'); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +select * from testing5 where c1 LIKE 'jo%'; -- does not use the transformation +GO +~~START~~ +varchar +~~END~~ + +SET babelfish_showplan_all ON; +GO +select * from testing5 where c1 LIKE 'jo%'; +GO +~~START~~ +text +Query Text: select * from testing5 where c1 LIKE 'jo%' +Seq Scan on testing5 (cost=10000000000.00..10000000027.00 rows=7 width=32) + Filter: ((c1)::text ~~ 'jo%'::text COLLATE "default") +~~END~~ + +SET babelfish_showplan_all OFF; +GO +select * from testing5 where c1 NOT LIKE 'j%'; +GO +~~START~~ +varchar +JONES +JoneS +abcD +äb?D +~~END~~ + +select * from testing5 where c1 LIKE 'AB%'; +GO +~~START~~ +varchar +~~END~~ + + +SELECT * from testing5 where c1 like ''; +GO +~~START~~ +varchar +~~END~~ + +SET babelfish_showplan_all ON; +GO +SELECT * from testing5 where c1 like ''; +GO +~~START~~ +text +Query Text: SELECT * from testing5 where c1 like '' +Seq Scan on testing5 (cost=10000000000.00..10000000027.00 rows=7 width=32) + Filter: ((c1)::text ~~ ''::text COLLATE "default") +~~END~~ + +SET babelfish_showplan_all OFF; +GO +SELECT * from testing5 where c1 like NULL; +GO +~~START~~ +varchar +~~END~~ + +SET babelfish_showplan_all ON; +GO +SELECT * from testing5 where c1 like NULL; +GO +~~START~~ +text +Query Text: SELECT * from testing5 where c1 like NULL +Result (cost=0.00..0.00 rows=0 width=0) + One-Time Filter: false +~~END~~ + +SET babelfish_showplan_all OFF; +GO + +SELECT * FROM testing5 where c1 COLLATE French_CI_AS like 'jo%' ; +GO +~~START~~ +varchar +JONES +JoneS +~~END~~ + +SET babelfish_showplan_all ON; +GO +SELECT * FROM testing5 where c1 COLLATE French_CI_AS like 'jo%' ; +GO +~~START~~ +text +Query Text: SELECT * FROM testing5 where c1 COLLATE French_CI_AS like 'jo%' +Seq Scan on testing5 (cost=10000000000.00..10000000033.80 rows=1 width=32) + Filter: (((c1)::text ~~* 'jo%'::text COLLATE "default") AND ((c1)::text >= 'jo'::text COLLATE "default") AND ((c1)::text < 'jo?'::text)) +~~END~~ + +SET babelfish_showplan_all OFF; +GO +SELECT * FROM testing5 where c1 COLLATE Chinese_PRC_CI_AS like 'jo%' ; +GO +~~START~~ +varchar +JONES +JoneS +~~END~~ + +SET babelfish_showplan_all ON; +GO +SELECT * FROM testing5 where c1 COLLATE Chinese_PRC_CI_AS like 'jo%' ; +GO +~~START~~ +text +Query Text: SELECT * FROM testing5 where c1 COLLATE Chinese_PRC_CI_AS like 'jo%' +Seq Scan on testing5 (cost=10000000000.00..10000000033.80 rows=1 width=32) + Filter: (((c1)::text ~~* 'jo%'::text COLLATE "default") AND ((c1)::text >= 'jo'::text COLLATE "default") AND ((c1)::text < 'jo?'::text)) +~~END~~ + +SET babelfish_showplan_all OFF; +GO + +-- expect different result order from previous select +select * from testing1 order by col; +GO +~~START~~ +nvarchar +Magic +Muffler +Mülle +MX Systems +~~END~~ + +-- test expression level collate, expect the same result order +select * from testing1 order by col collate Finnish_Swedish_CS_AS; +GO +~~START~~ +nvarchar +Magic +Muffler +MX Systems +Mülle +~~END~~ + +-- test catalog +select * from sys.fn_helpcollations() order by name; +GO +~~START~~ +varchar#!#varchar +arabic_ci_ai#!#Arabic, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +arabic_ci_as#!#Arabic, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +arabic_cs_as#!#Arabic, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +bbf_unicode_bin2#!#Unicode-General, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1250_ci_ai#!#Default locale, code page 1250, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1250_ci_as#!#Default locale, code page 1250, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1250_cs_ai#!#Default locale, code page 1250, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1250_cs_as#!#Default locale, code page 1250, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1251_ci_ai#!#Default locale, code page 1251, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1251_ci_as#!#Default locale, code page 1251, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1251_cs_ai#!#Default locale, code page 1251, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1251_cs_as#!#Default locale, code page 1251, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1253_ci_ai#!#Default locale, code page 1253, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1253_ci_as#!#Default locale, code page 1253, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1253_cs_ai#!#Default locale, code page 1253, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1253_cs_as#!#Default locale, code page 1253, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1254_ci_ai#!#Default locale, code page 1254, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1254_ci_as#!#Default locale, code page 1254, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1254_cs_ai#!#Default locale, code page 1254, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1254_cs_as#!#Default locale, code page 1254, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1255_ci_ai#!#Default locale, code page 1255, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1255_ci_as#!#Default locale, code page 1255, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1255_cs_ai#!#Default locale, code page 1255, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1255_cs_as#!#Default locale, code page 1255, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1256_ci_ai#!#Default locale, code page 1256, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1256_ci_as#!#Default locale, code page 1256, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1256_cs_ai#!#Default locale, code page 1256, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1256_cs_as#!#Default locale, code page 1256, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1257_ci_ai#!#Default locale, code page 1257, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1257_ci_as#!#Default locale, code page 1257, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1257_cs_ai#!#Default locale, code page 1257, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1257_cs_as#!#Default locale, code page 1257, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1258_ci_ai#!#Default locale, code page 1258, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1258_ci_as#!#Default locale, code page 1258, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1258_cs_ai#!#Default locale, code page 1258, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1258_cs_as#!#Default locale, code page 1258, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1_ci_ai#!#Default locale, code page 1252, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1_ci_as#!#Default locale, code page 1252, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1_cs_ai#!#Default locale, code page 1252, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp1_cs_as#!#Default locale, code page 1252, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp847_ci_ai#!#Default locale, code page 847, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp847_ci_as#!#Default locale, code page 847, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp847_cs_ai#!#Default locale, code page 847, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive +bbf_unicode_cp847_cs_as#!#Default locale, code page 847, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +bbf_unicode_general_ci_ai#!#Default locale, default code page, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +bbf_unicode_general_ci_as#!#Default locale, default code page, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +bbf_unicode_general_cs_ai#!#Default locale, default code page, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive +bbf_unicode_general_cs_as#!#Default locale, default code page, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +bbf_unicode_general_pref_cs_as#!#Default locale, default code page, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first +bbf_unicode_pref_cp1250_cs_as#!#Default locale, code page 1250, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first +bbf_unicode_pref_cp1251_cs_as#!#Default locale, code page 1251, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first +bbf_unicode_pref_cp1253_cs_as#!#Default locale, code page 1253, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first +bbf_unicode_pref_cp1254_cs_as#!#Default locale, code page 1254, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first +bbf_unicode_pref_cp1255_cs_as#!#Default locale, code page 1255, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first +bbf_unicode_pref_cp1256_cs_as#!#Default locale, code page 1256, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first +bbf_unicode_pref_cp1257_cs_as#!#Default locale, code page 1257, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first +bbf_unicode_pref_cp1258_cs_as#!#Default locale, code page 1258, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first +bbf_unicode_pref_cp1_cs_as#!#Default locale, code page 1252, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first +bbf_unicode_pref_cp847_cs_as#!#Default locale, code page 847, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first +chinese_prc_ci_ai#!#Chinese-PRC, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +chinese_prc_ci_as#!#Chinese-PRC, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +chinese_prc_cs_as#!#Chinese-PRC, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +cyrillic_general_ci_ai#!#Cyrillic-General, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +cyrillic_general_ci_as#!#Cyrillic-General, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +cyrillic_general_cs_as#!#Cyrillic-General, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +estonian_ci_ai#!#Estonian, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +estonian_ci_as#!#Estonian, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +estonian_cs_as#!#Estonian, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +finnish_swedish_ci_ai#!#Finnish-Swedish, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +finnish_swedish_ci_as#!#Finnish-Swedish, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +finnish_swedish_cs_as#!#Finnish-Swedish, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +french_ci_ai#!#French, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +french_ci_as#!#French, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +french_cs_as#!#French, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +greek_ci_ai#!#Greek, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +greek_ci_as#!#Greek, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +greek_cs_as#!#Greek, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +hebrew_ci_ai#!#Hebrew, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +hebrew_ci_as#!#Hebrew, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitives +hebrew_cs_as#!#Hebrew, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +japanese_ci_ai#!#Japanese, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +japanese_ci_as#!#Japanese, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +japanese_cs_as#!#Japanese, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +korean_wansung_ci_ai#!#Korean-Wansung, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +korean_wansung_ci_as#!#Korean-Wansung, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +korean_wansung_cs_as#!#Korean-Wansung, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +latin1_general_100_bin2#!#Virtual, Unicode-General, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +latin1_general_140_bin2#!#Virtual, Unicode-General, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +latin1_general_90_bin2#!#Virtual, Unicode-General, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +latin1_general_bin2#!#Virtual, Unicode-General, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +latin1_general_ci_ai#!#Virtual, default locale, code page 1252, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +latin1_general_ci_as#!#Virtual, default locale, code page 1252, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +latin1_general_cs_ai#!#Virtual, default locale, code page 1252, case-sensitive, accent-insensitive, kanatype-insensitive, width-insensitive +latin1_general_cs_as#!#Virtual, default locale, code page 1252, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +modern_spanish_ci_ai#!#Traditional-Spanish, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +modern_spanish_ci_as#!#Traditional-Spanish, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +modern_spanish_cs_as#!#Traditional-Spanish, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +mongolian_ci_ai#!#Mongolian, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +mongolian_ci_as#!#Mongolian, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +mongolian_cs_as#!#Mongolian, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +polish_ci_ai#!#Polish, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +polish_ci_as#!#Polish, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +polish_cs_as#!#Polish, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +sql_latin1_general_cp1250_ci_as#!#Virtual, default locale, code page 1250, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +sql_latin1_general_cp1250_cs_as#!#Virtual, default locale, code page 1250, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +sql_latin1_general_cp1251_ci_as#!#Virtual, default locale, code page 1251, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +sql_latin1_general_cp1251_cs_as#!#Virtual, default locale, code page 1251, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +sql_latin1_general_cp1253_ci_as#!#Virtual, default locale, code page 1253, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +sql_latin1_general_cp1253_cs_as#!#Virtual, default locale, code page 1253, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +sql_latin1_general_cp1254_ci_as#!#Virtual, default locale, code page 1254, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +sql_latin1_general_cp1254_cs_as#!#Virtual, default locale, code page 1255, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +sql_latin1_general_cp1255_ci_as#!#Virtual, default locale, code page 1255, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +sql_latin1_general_cp1255_cs_as#!#Virtual, default locale, code page 1255, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +sql_latin1_general_cp1256_ci_as#!#Virtual, default locale, code page 1256, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +sql_latin1_general_cp1256_cs_as#!#Virtual, default locale, code page 1256, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +sql_latin1_general_cp1257_ci_as#!#Virtual, default locale, code page 1257, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +sql_latin1_general_cp1257_cs_as#!#Virtual, default locale, code page 1257, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +sql_latin1_general_cp1258_ci_as#!#Virtual, default locale, code page 1258, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +sql_latin1_general_cp1258_cs_as#!#Virtual, default locale, code page 1258, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +sql_latin1_general_cp1_ci_ai#!#Virtual, default locale, code page 1252, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +sql_latin1_general_cp1_ci_ai#!#Virtual, default locale, code page 1252, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +sql_latin1_general_cp1_ci_as#!#Virtual, default locale, code page 1252, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +sql_latin1_general_cp1_cs_as#!#Virtual, default locale, code page 1252, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +sql_latin1_general_cp874_ci_as#!#Virtual, default locale, code page 874, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +sql_latin1_general_cp874_cs_as#!#Virtual, default locale, code page 874, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +sql_latin1_general_pref_cp1_cs_as#!#Virtual, default locale, code page 1252, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, uppercase-first +thai_ci_ai#!#Thai, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +thai_ci_as#!#Thai, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +thai_cs_as#!#Thai, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +traditional_spanish_ci_ai#!#Traditional-Spanish, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +traditional_spanish_ci_as#!#Traditional-Spanish, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +traditional_spanish_cs_as#!#Traditional-Spanish, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +turkish_ci_ai#!#Turkish, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +turkish_ci_as#!#Turkish, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +turkish_cs_as#!#Turkish, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +ukrainian_ci_ai#!#Ukrainian, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +ukrainian_ci_as#!#Ukrainian, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +ukrainian_cs_as#!#Ukrainian, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +vietnamese_ci_ai#!#Vietnamese, case-insensitive, accent-insensitive, kanatype-insensitive, width-insensitive +vietnamese_ci_as#!#Vietnamese, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive +vietnamese_cs_as#!#Vietnamese, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive +~~END~~ + + +SELECT set_config('babelfishpg_tsql.sql_dialect', 'tsql', false); +GO +~~START~~ +text +tsql +~~END~~ + +-- test collation list sys table +SELECT collation_name, l1_priority, l2_priority, l3_priority, l4_priority, l5_priority FROM sys.babelfish_collation_list() order by collation_name; +GO +~~START~~ +text#!#int#!#int#!#int#!#int#!#int +arabic_ci_ai#!#1025#!#0#!#196608#!#0#!#15 +arabic_ci_as#!#1025#!#0#!#196608#!#0#!#13 +arabic_cs_as#!#1025#!#0#!#196608#!#0#!#12 +bbf_unicode_bin2#!#1033#!#0#!#196608#!#54#!#544 +bbf_unicode_cp1250_ci_ai#!#1045#!#0#!#196608#!#0#!#15 +bbf_unicode_cp1250_ci_as#!#1045#!#0#!#196608#!#0#!#13 +bbf_unicode_cp1250_cs_ai#!#1045#!#0#!#196608#!#0#!#14 +bbf_unicode_cp1250_cs_as#!#1045#!#0#!#196608#!#0#!#12 +bbf_unicode_cp1251_ci_ai#!#1049#!#0#!#196608#!#0#!#15 +bbf_unicode_cp1251_ci_as#!#1049#!#0#!#196608#!#0#!#13 +bbf_unicode_cp1251_cs_ai#!#1049#!#0#!#196608#!#0#!#14 +bbf_unicode_cp1251_cs_as#!#1049#!#0#!#196608#!#0#!#12 +bbf_unicode_cp1253_ci_ai#!#1032#!#0#!#196608#!#0#!#15 +bbf_unicode_cp1253_ci_as#!#1032#!#0#!#196608#!#0#!#13 +bbf_unicode_cp1253_cs_ai#!#1032#!#0#!#196608#!#0#!#14 +bbf_unicode_cp1253_cs_as#!#1032#!#0#!#196608#!#0#!#12 +bbf_unicode_cp1254_ci_ai#!#1055#!#0#!#196608#!#0#!#15 +bbf_unicode_cp1254_ci_as#!#1055#!#0#!#196608#!#0#!#13 +bbf_unicode_cp1254_cs_ai#!#1055#!#0#!#196608#!#0#!#14 +bbf_unicode_cp1254_cs_as#!#1055#!#0#!#196608#!#0#!#12 +bbf_unicode_cp1255_ci_ai#!#1037#!#0#!#196608#!#0#!#15 +bbf_unicode_cp1255_ci_as#!#1037#!#0#!#196608#!#0#!#13 +bbf_unicode_cp1255_cs_ai#!#1037#!#0#!#196608#!#0#!#14 +bbf_unicode_cp1255_cs_as#!#1037#!#0#!#196608#!#0#!#12 +bbf_unicode_cp1256_ci_ai#!#1025#!#0#!#196608#!#0#!#15 +bbf_unicode_cp1256_ci_as#!#1025#!#0#!#196608#!#0#!#13 +bbf_unicode_cp1256_cs_ai#!#1025#!#0#!#196608#!#0#!#14 +bbf_unicode_cp1256_cs_as#!#1025#!#0#!#196608#!#0#!#12 +bbf_unicode_cp1257_ci_ai#!#1061#!#0#!#196608#!#0#!#15 +bbf_unicode_cp1257_ci_as#!#1061#!#0#!#196608#!#0#!#13 +bbf_unicode_cp1257_cs_ai#!#1061#!#0#!#196608#!#0#!#14 +bbf_unicode_cp1257_cs_as#!#1061#!#0#!#196608#!#0#!#12 +bbf_unicode_cp1258_ci_ai#!#1066#!#0#!#196608#!#0#!#15 +bbf_unicode_cp1258_ci_as#!#1066#!#0#!#196608#!#0#!#13 +bbf_unicode_cp1258_cs_ai#!#1066#!#0#!#196608#!#0#!#14 +bbf_unicode_cp1258_cs_as#!#1066#!#0#!#196608#!#0#!#12 +bbf_unicode_cp1_ci_ai#!#1033#!#0#!#196608#!#54#!#15 +bbf_unicode_cp1_ci_as#!#1033#!#0#!#196608#!#52#!#13 +bbf_unicode_cp1_cs_ai#!#1033#!#0#!#196608#!#51#!#14 +bbf_unicode_cp1_cs_as#!#1033#!#0#!#196608#!#51#!#12 +bbf_unicode_cp874_ci_ai#!#1054#!#0#!#196608#!#0#!#15 +bbf_unicode_cp874_ci_as#!#1054#!#0#!#196608#!#0#!#13 +bbf_unicode_cp874_cs_ai#!#1054#!#0#!#196608#!#0#!#14 +bbf_unicode_cp874_cs_as#!#1054#!#0#!#196608#!#0#!#12 +bbf_unicode_general_ci_ai#!#1033#!#0#!#196608#!#0#!#15 +bbf_unicode_general_ci_as#!#1033#!#0#!#196608#!#0#!#13 +bbf_unicode_general_cs_ai#!#1033#!#0#!#196608#!#0#!#14 +bbf_unicode_general_cs_as#!#1033#!#0#!#196608#!#0#!#12 +bbf_unicode_general_pref_cs_as#!#1033#!#0#!#196608#!#0#!#12 +bbf_unicode_pref_cp1250_cs_as#!#1045#!#0#!#196608#!#0#!#12 +bbf_unicode_pref_cp1251_cs_as#!#1049#!#0#!#196608#!#0#!#12 +bbf_unicode_pref_cp1253_cs_as#!#1032#!#0#!#196608#!#0#!#12 +bbf_unicode_pref_cp1254_cs_as#!#1055#!#0#!#196608#!#0#!#12 +bbf_unicode_pref_cp1255_cs_as#!#1037#!#0#!#196608#!#0#!#12 +bbf_unicode_pref_cp1256_cs_as#!#1025#!#0#!#196608#!#0#!#12 +bbf_unicode_pref_cp1257_cs_as#!#1061#!#0#!#196608#!#0#!#12 +bbf_unicode_pref_cp1258_cs_as#!#1066#!#0#!#196608#!#0#!#12 +bbf_unicode_pref_cp1_cs_as#!#1033#!#0#!#196608#!#51#!#12 +bbf_unicode_pref_cp874_cs_as#!#1054#!#0#!#196608#!#0#!#12 +chinese_prc_ci_ai#!#2052#!#0#!#196608#!#0#!#15 +chinese_prc_ci_as#!#2052#!#0#!#196608#!#0#!#13 +chinese_prc_cs_as#!#2052#!#0#!#196608#!#0#!#12 +cyrillic_general_ci_ai#!#1049#!#0#!#196608#!#0#!#15 +cyrillic_general_ci_as#!#1049#!#0#!#196608#!#0#!#13 +cyrillic_general_cs_as#!#1049#!#0#!#196608#!#0#!#12 +estonian_ci_ai#!#1061#!#0#!#196608#!#0#!#15 +estonian_ci_as#!#1061#!#0#!#196608#!#0#!#13 +estonian_cs_as#!#1061#!#0#!#196608#!#0#!#12 +finnish_swedish_ci_ai#!#1035#!#0#!#196608#!#0#!#15 +finnish_swedish_ci_as#!#1035#!#0#!#196608#!#0#!#13 +finnish_swedish_cs_as#!#1035#!#0#!#196608#!#0#!#12 +french_ci_ai#!#1036#!#0#!#196608#!#0#!#15 +french_ci_as#!#1036#!#0#!#196608#!#0#!#13 +french_cs_as#!#1036#!#0#!#196608#!#0#!#12 +greek_ci_ai#!#1032#!#0#!#196608#!#0#!#15 +greek_ci_as#!#1032#!#0#!#196608#!#0#!#13 +greek_cs_as#!#1032#!#0#!#196608#!#0#!#12 +hebrew_ci_ai#!#1037#!#0#!#196608#!#0#!#15 +hebrew_ci_as#!#1037#!#0#!#196608#!#0#!#13 +hebrew_cs_as#!#1037#!#0#!#196608#!#0#!#12 +japanese_ci_ai#!#1041#!#0#!#196608#!#0#!#15 +japanese_ci_as#!#1041#!#0#!#196608#!#0#!#13 +japanese_cs_as#!#1041#!#0#!#196608#!#0#!#12 +korean_wansung_ci_ai#!#1042#!#0#!#196608#!#0#!#15 +korean_wansung_ci_as#!#1042#!#0#!#196608#!#0#!#13 +korean_wansung_cs_as#!#1042#!#0#!#196608#!#0#!#12 +modern_spanish_ci_ai#!#3082#!#0#!#196608#!#0#!#15 +modern_spanish_ci_as#!#3082#!#0#!#196608#!#0#!#13 +modern_spanish_cs_as#!#3082#!#0#!#196608#!#0#!#12 +mongolian_ci_ai#!#1104#!#0#!#196608#!#0#!#15 +mongolian_ci_as#!#1104#!#0#!#196608#!#0#!#13 +mongolian_cs_as#!#1104#!#0#!#196608#!#0#!#12 +polish_ci_ai#!#1045#!#0#!#196608#!#0#!#15 +polish_ci_as#!#1045#!#0#!#196608#!#0#!#13 +polish_cs_as#!#1045#!#0#!#196608#!#0#!#12 +thai_ci_ai#!#1054#!#0#!#196608#!#0#!#15 +thai_ci_as#!#1054#!#0#!#196608#!#0#!#13 +thai_cs_as#!#1054#!#0#!#196608#!#0#!#12 +traditional_spanish_ci_ai#!#1034#!#0#!#196608#!#0#!#15 +traditional_spanish_ci_as#!#1034#!#0#!#196608#!#0#!#13 +traditional_spanish_cs_as#!#1034#!#0#!#196608#!#0#!#12 +turkish_ci_ai#!#1055#!#0#!#196608#!#0#!#15 +turkish_ci_as#!#1055#!#0#!#196608#!#0#!#13 +turkish_cs_as#!#1055#!#0#!#196608#!#0#!#12 +ukrainian_ci_ai#!#1058#!#0#!#196608#!#0#!#15 +ukrainian_ci_as#!#1058#!#0#!#196608#!#0#!#13 +ukrainian_cs_as#!#1058#!#0#!#196608#!#0#!#12 +vietnamese_ci_ai#!#1066#!#0#!#196608#!#0#!#15 +vietnamese_ci_as#!#1066#!#0#!#196608#!#0#!#13 +vietnamese_cs_as#!#1066#!#0#!#196608#!#0#!#12 +~~END~~ + +-- clean up +drop table testing1; +GO +drop table testing2; +GO +drop table testing3; +GO +drop table testing4; +GO +drop table testing5; +GO diff --git a/test/JDBC/expected/babel_datatype.out b/test/JDBC/expected/babel_datatype.out new file mode 100644 index 0000000000..e92e1542df --- /dev/null +++ b/test/JDBC/expected/babel_datatype.out @@ -0,0 +1,3083 @@ +-- The default scale is 2 in PG. +select CAST('$100,123.4567' AS money); +GO +~~START~~ +money +100123.4567 +~~END~~ + +-- Currency symbol followed by number without being quoted is not recognized +-- as Money in postgres dialect. +select CAST($100123.4567 AS money); +GO +~~START~~ +money +100123.4567 +~~END~~ + + +-- Scale changes to the sql server default 4 in tsql dialect +-- Currency symbol followed by number without being quoted is recognized +-- as Money type in tsql dialect. +select CAST($100123.4567 AS money); +GO +~~START~~ +money +100123.4567 +~~END~~ + +select CAST($100123. AS money); +GO +~~START~~ +money +100123.0000 +~~END~~ + +select CAST($.4567 AS money); +GO +~~START~~ +money +0.4567 +~~END~~ + +select CAST('$100,123.4567' AS money); +GO +~~START~~ +money +100123.4567 +~~END~~ + + +-- Test numeric types with brackets +create table testing1 (a [tinyint]); +GO +drop table testing1; +GO +create table testing1 (a [smallint]); +GO +drop table testing1; +GO +create table testing1 (a [int]); +GO +drop table testing1; +GO +create table testing1 (a [bigint]); +GO +drop table testing1; +GO +create table testing1 (a [real]); +GO +drop table testing1; +GO +create table testing1 (a [float]); +GO +drop table testing1; +GO + + +-- Smallmoney in tsql dialect +select CAST($100123.4567 AS smallmoney); +GO +~~START~~ +smallmoney +100123.4567 +~~END~~ + +select CAST('$100,123.4567' AS smallmoney); +GO +~~START~~ +smallmoney +100123.4567 +~~END~~ + + +create table testing1(mon money, smon smallmoney); +GO +insert into testing1 (mon, smon) values ('$100,123.4567', '$123.9999'); +insert into testing1 (mon, smon) values ($100123.4567, $123.9999); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +select * from testing1; +GO +~~START~~ +money#!#smallmoney +100123.4567#!#123.9999 +100123.4567#!#123.9999 +~~END~~ + +select avg(CAST(mon AS numeric(38,4))), avg(CAST(smon AS numeric(38,4))) from testing1; +GO +~~START~~ +numeric#!#numeric +100123.456700#!#123.999900 +~~END~~ + +select mon+smon as total from testing1; +GO +~~START~~ +money +100247.4566 +100247.4566 +~~END~~ + +-- Comma separated format without quote is not allowed in sql server +insert into testing1 (mon, smon) values ($100,123.4567, $123.9999); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: INSERT has more expressions than target columns)~~ + + +-- Test other allowed currency symbols with/without quote +select CAST(€100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST('€100.123' AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(¢100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(£100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST('£100.123' AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(¤100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(Â¥100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(৲100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(৳100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(฿100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(៛100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(â‚ 100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(â‚¡100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(â‚¢100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(â‚£100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(₤100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(â‚¥100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(₦100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(₧100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(₨100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(â‚©100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(₪100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(â‚«100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(â‚­100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(â‚®100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(₯100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(â‚°100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(₱100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(ï·¼100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(﹩100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST($100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(ï¿ 100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(ï¿¡100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(ï¿¥100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST('ï¿¥100.123' AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + +select CAST(₩100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + + +-- Test unsupoorted currency symbol +select CAST('ï¿©100.123' AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + + +-- Test that space is allowed between currency symbol and number, this is +-- a TSQL behavior +select CAST($ 123.5 AS money); +GO +~~START~~ +money +123.5000 +~~END~~ + +select CAST('$ 123.5' AS money); +GO +~~START~~ +money +123.5000 +~~END~~ + + +-- Test inexact result mutliply/divide money with money, to match +-- SQL Server behavior +select CAST(100 AS money)/CAST(339 AS money)*CAST(10000 AS money); +GO +~~START~~ +money +2949.0000 +~~END~~ + + +-- Test postgres dialect +-- Test currency symbol without quote is not allowed in postgres dialect +select CAST(€100.123 AS money); +GO +~~START~~ +money +100.1230 +~~END~~ + + +-- Test exact result multiply/divide money with money in postgres dialect +select CAST(100 AS money)/CAST(339 AS money)*CAST(10000 AS money); +GO +~~START~~ +money +2949.0000 +~~END~~ + + +-- Clean up +drop table testing1; +GO + + + +select CAST(2 AS money) + 1; +GO +~~START~~ +money +3.0000 +~~END~~ + +select CAST(2 AS money) + CAST(1 AS int); +GO +~~START~~ +money +3.0000 +~~END~~ + +select CAST(2 AS money) + CAST(1 AS int2); +GO +~~START~~ +money +3.0000 +~~END~~ + +select CAST(2 AS money) + CAST(1 AS int4); +GO +~~START~~ +money +3.0000 +~~END~~ + +select CAST(2 AS money) + CAST(1 AS numeric); +GO +~~START~~ +numeric +3 +~~END~~ + +select CAST(2 AS money) + CAST(1 AS decimal); +GO +~~START~~ +numeric +3 +~~END~~ + + +select CAST(2 AS money) - 1; +GO +~~START~~ +money +1.0000 +~~END~~ + +select CAST(2 AS money) - CAST(1 AS int); +GO +~~START~~ +money +1.0000 +~~END~~ + +select CAST(2 AS money) - CAST(1 AS int2); +GO +~~START~~ +money +1.0000 +~~END~~ + +select CAST(2 AS money) - CAST(1 AS int4); +GO +~~START~~ +money +1.0000 +~~END~~ + +select CAST(2 AS money) - CAST(1 AS numeric); +GO +~~START~~ +numeric +1 +~~END~~ + +select CAST(2 AS money) - CAST(1 AS decimal); +GO +~~START~~ +numeric +1 +~~END~~ + + +select CAST(2 AS money) * 2; +GO +~~START~~ +money +4.0000 +~~END~~ + +select CAST(2 AS money) * CAST(2 AS int); +GO +~~START~~ +money +4.0000 +~~END~~ + +select CAST(2 AS money) * CAST(2 AS int2); +GO +~~START~~ +money +4.0000 +~~END~~ + +select CAST(2 AS money) * CAST(2 AS int4); +GO +~~START~~ +money +4.0000 +~~END~~ + +select CAST(2 AS money) * CAST(2 AS numeric); +GO +~~START~~ +numeric +4 +~~END~~ + +select CAST(2 AS money) * CAST(2 AS decimal); +GO +~~START~~ +numeric +4 +~~END~~ + + +select CAST(2 AS money) / 0.5; +GO +~~START~~ +numeric +4.000000 +~~END~~ + +select CAST(2 AS money) / CAST(2 AS int); +GO +~~START~~ +money +1.0000 +~~END~~ + +select CAST(2 AS money) / CAST(2 AS int2); +GO +~~START~~ +money +1.0000 +~~END~~ + +select CAST(2 AS money) / CAST(2 AS int4); +GO +~~START~~ +money +1.0000 +~~END~~ + +select CAST(2 AS money) / CAST(0.5 AS numeric(4,2)); +GO +~~START~~ +numeric +4.000000 +~~END~~ + +select CAST(2 AS money) / CAST(0.5 AS decimal(4,2)); +GO +~~START~~ +numeric +4.000000 +~~END~~ + + + +-- DATE DATETIME, DATETIMEOFFSET, DATETIME2 and SMALLDATETIME are defined in tsql dialect +select CAST('2020-03-15' AS date); +GO +~~START~~ +date +2020-03-15 +~~END~~ + +select CAST('2020-03-15 09:00:00+8' AS datetimeoffset); +GO +~~START~~ +datetimeoffset +2020-03-15 09:00:00.0000000 +08:00 +~~END~~ + +select CAST('2020-03-15 09:00:00' AS datetime2); +GO +~~START~~ +datetime2 +2020-03-15 09:00:00.0000000 +~~END~~ + +select CAST('2020-03-15 09:00:00' AS smalldatetime); +GO +~~START~~ +smalldatetime +2020-03-15 09:00:00.0 +~~END~~ + +-- test the range of date +select CAST('0001-01-01' AS date); +GO +~~START~~ +date +0001-01-01 +~~END~~ + +select CAST('9999-12-31' AS date); +GO +~~START~~ +date +9999-12-31 +~~END~~ + +-- test the range of datetime2 +select CAST('0001-01-01 12:00:00.12345' AS datetime2); +GO +~~START~~ +datetime2 +0001-01-01 12:00:00.1234500 +~~END~~ + +select CAST('9999-12-31 12:00:00.12345' AS datetime2); +GO +~~START~~ +datetime2 +9999-12-31 12:00:00.1234500 +~~END~~ + +-- precision +select CAST('2020-03-15 09:00:00+8' AS datetimeoffset(7)) ; +GO +~~START~~ +datetimeoffset +2020-03-15 09:00:00.000000 +08:00 +~~END~~ + +create table testing1(ts DATETIME, tstz DATETIMEOFFSET(7)); +GO + +insert into testing1 (ts, tstz) values ('2020-03-15 09:00:00', '2020-03-15 09:00:00+8'); +select * from testing1; +drop table testing1; +GO +~~ROW COUNT: 1~~ + +~~START~~ +datetime#!#datetimeoffset +2020-03-15 09:00:00.0#!#2020-03-15 09:00:00.0000000 +08:00 +~~END~~ + + +select CAST('2020-03-15 09:00:00' AS datetime2(7)); +GO +~~START~~ +datetime2 +2020-03-15 09:00:00.000000 +~~END~~ + +select CAST('2020-03-15 09:00:00.123456' AS datetime2(3)); +GO +~~START~~ +datetime2 +2020-03-15 09:00:00.123 +~~END~~ + +select CAST('2020-03-15 09:00:00.123456' AS datetime2(0)); +GO +~~START~~ +datetime2 +2020-03-15 09:00:00 +~~END~~ + + +create table testing1(ts DATETIME, tstz DATETIME2(7)); +insert into testing1 (ts, tstz) values ('2020-03-15 09:00:00', '2020-03-15 09:00:00'); +select * from testing1; +GO +~~ROW COUNT: 1~~ + +~~START~~ +datetime#!#datetime2 +2020-03-15 09:00:00.0#!#2020-03-15 09:00:00.0000000 +~~END~~ + +drop table testing1; +GO + +-- DATETIME, DATETIMEOFFSET, DATETIME2 and SMALLDATETIME are not defined in +-- postgres dialect +SELECT set_config('babelfishpg_tsql.sql_dialect', 'postgres', false); +GO +~~START~~ +text +postgres +~~END~~ + +select CAST('2020-03-15 09:00:00+8' AS datetimeoffset); +GO +~~START~~ +datetimeoffset +2020-03-15 09:00:00.0000000 +08:00 +~~END~~ + +create table testing1(tstz DATETIMEOFFSET); +GO +select CAST('2020-03-15 09:00:00' AS datetime2); +GO +~~START~~ +datetime2 +2020-03-15 09:00:00.0000000 +~~END~~ + + +-- Test DATETIME, DATETIMEOFFSET, DATETIME2 and SMALLDATETIME can be used as identifier +select * from testing1; +GO +~~START~~ +datetimeoffset +~~END~~ + +drop table testing1; +GO + +create table testing1(DATETIMEOFFSET int); +GO +insert into testing1 (DATETIMEOFFSET) values (1); +GO +~~ROW COUNT: 1~~ + +select * from testing1; +GO +~~START~~ +int +1 +~~END~~ + +drop table testing1; +GO + +create table testing1(DATETIME2 int); +GO +insert into testing1 (DATETIME2) values (1); +GO +~~ROW COUNT: 1~~ + +select * from testing1; +GO +~~START~~ +int +1 +~~END~~ + +drop table testing1; +GO + +create table testing1(SMALLDATETIME int); +GO +insert into testing1 (SMALLDATETIME) values (1); +GO +~~ROW COUNT: 1~~ + +select * from testing1; +GO +~~START~~ +int +1 +~~END~~ + + + +insert into testing1 (SMALLDATETIME) values (2); +GO +~~ROW COUNT: 1~~ + +select * from testing1; +GO +~~START~~ +int +1 +2 +~~END~~ + + +-- Test conversion between DATE and other date/time types +select CAST(CAST('2020-03-15' AS date) AS datetime); +GO +~~START~~ +datetime +2020-03-15 00:00:00.0 +~~END~~ + +select CAST(CAST('2020-03-15' AS date) AS smalldatetime); +GO +~~START~~ +smalldatetime +2020-03-15 00:00:00.0 +~~END~~ + +select CAST(CAST('2020-03-15' AS date) AS datetimeoffset(3)); +GO +~~START~~ +datetimeoffset +2020-03-15 00:00:00.000 +00:00 +~~END~~ + +select CAST(CAST('2020-03-15' AS date) AS datetime2(3)); +GO +~~START~~ +datetime2 +2020-03-15 00:00:00.000 +~~END~~ + + +-- Clean up +drop table testing1; +GO + +-- Test SYS.NCHAR, SYS.NVARCHAR and SYS.VARCHAR +-- nchar is already available in postgres dialect +select CAST('£' AS nchar(1)); +GO +~~START~~ +nchar +£ +~~END~~ + +-- nvarchar is not available in postgres dialect +select CAST('£' AS nvarchar); +GO +~~START~~ +nvarchar +£ +~~END~~ + + +-- both are available in tsql dialect +select CAST('£' AS nchar(2)); +GO +~~START~~ +nchar +£ +~~END~~ + +select CAST('£' AS nvarchar(2)); +GO +~~START~~ +nvarchar +£ +~~END~~ + + +-- multi-byte character doesn't fit in nchar(1) in tsql if it +-- would require a UTF16-surrogate-pair on output +select CAST('£' AS char(1)); -- allowed +GO +~~START~~ +char +£ +~~END~~ + +select CAST('£' AS sys.nchar(1)); -- allowed +GO +~~START~~ +nchar +£ +~~END~~ + +select CAST('£' AS sys.nvarchar(1)); -- allowed +GO +~~START~~ +nvarchar +£ +~~END~~ + +select CAST('£' AS sys.varchar(1)); -- allowed +GO +~~START~~ +varchar +£ +~~END~~ + + +-- Check that things work the same in postgres dialect +select CAST('£' AS char(1)); +GO +~~START~~ +char +£ +~~END~~ + +select CAST('£' AS sys.nchar(1)); +GO +~~START~~ +nchar +£ +~~END~~ + +select CAST('£' AS sys.nvarchar(1)); +GO +~~START~~ +nvarchar +£ +~~END~~ + +select CAST('£' AS sys.varchar(1)); +GO +~~START~~ +varchar +£ +~~END~~ + + +-- truncate input on explicit cast +select CAST('ab' AS char(1)); +GO +~~START~~ +char +a +~~END~~ + +select CAST('ab' AS nchar(1)); +GO +~~START~~ +nchar +a +~~END~~ + +select CAST('ab' AS nvarchar(1)); +GO +~~START~~ +nvarchar +a +~~END~~ + +select CAST('ab' AS sys.varchar(1)); +GO +~~START~~ +varchar +a +~~END~~ + + + +-- default length of nchar/char is 1 in tsql (and pg) +create table testing1(col nchar); +GO +SELECT * FROM testing1; +GO +~~START~~ +nchar +~~END~~ + + + +-- check length at insert +insert into testing1 (col) select 'a'; +insert into testing1 (col) select '£'; +insert into testing1 (col) select 'ab'; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 8152)~~ + +~~ERROR (Message: value too long for type character(1))~~ + + +-- space is automatically truncated +insert into testing1 (col) select 'c '; +select * from testing1; +GO +~~ROW COUNT: 1~~ + +~~START~~ +nchar +a +£ +c +~~END~~ + + +-- default length of nvarchar in tsql is 1 +create table testing2(col nvarchar); +GO + +insert into testing2 (col) select 'a'; +insert into testing2 (col) select '£'; +insert into testing2 (col) select 'ab'; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 8152)~~ + +~~ERROR (Message: value too long for type character varying(1))~~ + + +-- space is automatically truncated +insert into testing2 (col) select 'c '; +select * from testing2; +GO +~~ROW COUNT: 1~~ + +~~START~~ +nvarchar +a +£ +c +~~END~~ + + +-- default length of varchar in tsql is 1 +create table testing4(col sys.varchar); +GO + +insert into testing4 (col) select 'a'; +insert into testing4 (col) select '£'; +insert into testing4 (col) select 'ab'; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 8152)~~ + +~~ERROR (Message: value too long for type character varying(1))~~ + +-- space is automatically truncated +insert into testing4 (col) select 'c '; +insert into testing2 (col) select '£ '; +select * from testing4; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +varchar +a +£ +c +~~END~~ + + +-- test sys.varchar(max) and sys.nvarchar(max) syntax is allowed in tsql dialect +select CAST('abcdefghijklmn' AS sys.varchar(max)); +GO +~~START~~ +varchar +abcdefghijklmn +~~END~~ + +select CAST('abcdefghijklmn' AS varchar(max)); +GO +~~START~~ +varchar +abcdefghijklmn +~~END~~ + +select CAST('abcdefghijklmn' AS sys.nvarchar(max)); +GO +~~START~~ +nvarchar +abcdefghijklmn +~~END~~ + +select CAST('abcdefghijklmn' AS nvarchar(max)); +GO +~~START~~ +nvarchar +abcdefghijklmn +~~END~~ + + +-- test char(max), nchar(max) is invalid syntax in tsql dialect +select cast('abc' as char(max)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Incorrect syntax near the keyword 'bpchar'.)~~ + +select cast('abc' as nchar(max)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Incorrect syntax near the keyword 'nchar'.)~~ + + +-- test max can still be used as an identifier +create table max (max int); +insert into max (max) select 100; +select * from max; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int +100 +~~END~~ + +drop table max; +GO + +-- test sys.varchar(max) and nvarchar(max) syntax is not allowed in postgres dialect +select CAST('abcdefghijklmn' AS sys.varchar(max)); +GO +~~START~~ +varchar +abcdefghijklmn +~~END~~ + +select CAST('abcdefghijklmn' AS varchar(max)); +GO +~~START~~ +varchar +abcdefghijklmn +~~END~~ + +select CAST('abcdefghijklmn' AS sys.nvarchar(max)); +GO +~~START~~ +nvarchar +abcdefghijklmn +~~END~~ + +select CAST('abcdefghijklmn' AS nvarchar(max)); +GO +~~START~~ +nvarchar +abcdefghijklmn +~~END~~ + + +-- test max max character length is (10 * 1024 * 1024) = 10485760 +select CAST('abc' AS varchar(10485761)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: length for type varchar cannot exceed 10485760)~~ + +select CAST('abc' AS varchar(10485760)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The size '10485760' exceeds the maximum allowed (8000) for 'varchar' datatype.)~~ + + + +-- test column type nvarchar(max) +create table testing5(col nvarchar(max)); +GO +SELECT * FROM testing5 +GO +~~START~~ +nvarchar +~~END~~ + + +insert into testing5 (col) select 'ab'; +insert into testing5 (col) select 'abcdefghijklmn'; +select * from testing5; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +nvarchar +ab +abcdefghijklmn +~~END~~ + + + +-- [BABEL-220] test varchar(max) as a column +drop table testing5; +GO + +create table testing5(col varchar(max)); +GO + +insert into testing5 (col) select 'ab'; +insert into testing5 (col) select 'abcdefghijklmn'; +select * from testing5; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +varchar +ab +abcdefghijklmn +~~END~~ + + +-- test type modifer persist if babelfishpg_tsql.sql_dialect changes +create table testing3(col nvarchar(2)); +GO + +insert into testing3 (col) select 'ab'; +insert into testing3 (col) select 'a£'; +insert into testing3 (col) select 'a😀'; +insert into testing3 (col) select 'abc'; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: value too long for type character varying(2) as UTF16 output)~~ + + +insert into testing3 (col) select 'ab'; +insert into testing3 (col) select 'a£'; +insert into testing3 (col) select 'a😀'; +insert into testing3 (col) select 'abc'; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: value too long for type character varying(2) as UTF16 output)~~ + + + +insert into testing3 (col) select 'ab'; +insert into testing3 (col) select 'a£'; +insert into testing3 (col) select 'a😀'; +insert into testing3 (col) select 'abc'; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: value too long for type character varying(2) as UTF16 output)~~ + + +-- test normal create domain works when apg_enable_domain_typmod is enabled +select set_config('enable_seqscan','on','true'); +GO +~~START~~ +text +on +~~END~~ + +select CAST('abc' AS varchar(3)); +GO +~~START~~ +varchar +abc +~~END~~ + +select CAST('ab£' AS varchar(3)); +GO +~~START~~ +varchar +ab£ +~~END~~ + +select CAST('abcd' AS varchar(3)); +GO +~~START~~ +varchar +abc +~~END~~ + + +-- [BABEL-191] test typmod of sys.varchar/nvarchar engages when the input +-- is casted multiple times +select CAST(CAST('abc' AS text) AS sys.varchar(3)); +GO +~~START~~ +varchar +abc +~~END~~ + + +select CAST(CAST('abc' AS pg_catalog.varchar(3)) AS sys.varchar(3)); +GO +~~START~~ +varchar +abc +~~END~~ + + +select CAST(CAST('abc' AS text) AS sys.nvarchar(3)); +GO +~~START~~ +nvarchar +abc +~~END~~ + +select CAST(CAST('abc' AS text) AS sys.nchar(3)); +GO +~~START~~ +nchar +abc +~~END~~ + + +select CAST(CAST(CAST(CAST('abc' AS text) AS sys.varchar(3)) AS sys.nvarchar(3)) AS sys.nchar(3)); +GO +~~START~~ +nchar +abc +~~END~~ + + +-- test truncation on explicit cast through multiple levels +select CAST(CAST(CAST(CAST('abcde' AS text) AS sys.varchar(5)) AS sys.nvarchar(4)) AS sys.nchar(3)); +GO +~~START~~ +nchar +abc +~~END~~ + +select CAST(CAST(CAST(CAST('abcde' AS text) AS sys.varchar(3)) AS sys.nvarchar(4)) AS sys.nchar(5)); +GO +~~START~~ +nchar +abc +~~END~~ + + +-- test sys.ntext is available +select CAST('abc£' AS sys.ntext); +GO +~~START~~ +ntext +abc£ +~~END~~ + +-- pg_catalog.text +select CAST('abc£' AS text); +GO +~~START~~ +text +abc£ +~~END~~ + + +-- [BABEL-218] test varchar defaults to sys.varchar in tsql dialect +-- test default length of sys.varchar is 30 in CAST/CONVERT +-- expect the last 'e' to be truncated +select cast('abcdefghijklmnopqrstuvwxyzabcde' as varchar); +GO +~~START~~ +varchar +abcdefghijklmnopqrstuvwxyzabcd +~~END~~ + +select cast('abcdefghijklmnopqrstuvwxyzabcde' as sys.varchar); +GO +~~START~~ +varchar +abcdefghijklmnopqrstuvwxyzabcd +~~END~~ + +select convert(varchar, 'abcdefghijklmnopqrstuvwxyzabcde'); +GO +~~START~~ +varchar +abcdefghijklmnopqrstuvwxyzabcd +~~END~~ + +select convert(sys.varchar, 'abcdefghijklmnopqrstuvwxyzabcde'); +GO +~~START~~ +varchar +abcdefghijklmnopqrstuvwxyzabcd +~~END~~ + + +-- default length of pg_catalog.varchar is unlimited, no truncation in output +select cast('abcdefghijklmnopqrstuvwxyzabcde' as pg_catalog.varchar); +GO +~~START~~ +varchar +abcdefghijklmnopqrstuvwxyzabcde +~~END~~ + + +-- varchar defaults to pg_catalog.varchar in PG dialect +select cast('abcdefghijklmnopqrstuvwxyzabcde' as pg_catalog.varchar); -- default length of pg_catalog.varchar is unlimited, no truncation +GO +~~START~~ +varchar +abcdefghijklmnopqrstuvwxyzabcde +~~END~~ + + +-- [BABEL-255] test nchar defaults to sys.nchar in tsql dialect +create table test_nchar (col1 nchar); +GO + + +SELECT * FROM test_nchar +GO +~~START~~ +nchar +~~END~~ + + +drop table test_nchar; +GO + + +-- test nchar defaults to bpchar in pg dialect +create table test_nchar (col1 nchar); +GO +SELECT * FROM test_nchar +drop table test_nchar; +GO +~~START~~ +nchar +~~END~~ + + + +-- [BABEL-257] test varchar defaults to sys.varchar in new +-- database and new schema +SELECT current_database(); +GO +~~START~~ +varchar +jdbc_testdb +~~END~~ + + +SELECT set_config('babelfishpg_tsql.sql_dialect', 'postgres', false); +GO +~~START~~ +text +postgres +~~END~~ + + + +-- Test varchar is mapped to sys.varchar +-- Expect truncated output because sys.varchar defaults to sys.varchar(30) in CAST function +select cast('abcdefghijklmnopqrstuvwxyzabcde' as varchar); +GO +~~START~~ +varchar +abcdefghijklmnopqrstuvwxyzabcd +~~END~~ + +-- Expect non-truncated output because pg_catalog.varchar has unlimited length +select cast('abcdefghijklmnopqrstuvwxyzabcde' as pg_catalog.varchar); +GO +~~START~~ +varchar +abcdefghijklmnopqrstuvwxyzabcde +~~END~~ + + +-- Test bit is mapped to sys.bit +-- sys.bit allows numeric input +select CAST(1.5 AS bit); +GO +~~START~~ +bit +1 +~~END~~ + +-- pg_catalog.bit doesn't allow numeric input +select CAST(1.5 AS pg_catalog.bit); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type numeric to bit)~~ + + +-- Test varchar is mapped to sys.varchar in a new schema and a new table +CREATE SCHEMA s1; +GO + +create table s1.test1 (col varchar); +GO +-- Test sys.varchar is created for test1.col, expect an error +-- because sys.varchar defaults to sys.varchar(1) +insert into s1.test1 values('abc'); +insert into s1.test1 values('a'); +select * from s1.test1; +GO +~~ERROR (Code: 8152)~~ + +~~ERROR (Message: value too long for type character varying(1))~~ + +~~START~~ +varchar +a +~~END~~ + +SELECT set_config('babelfishpg_tsql.sql_dialect', 'postgres', false); +GO +~~START~~ +text +postgres +~~END~~ + + + +-- test tinyint data type +select CAST(100 AS tinyint); +GO +~~START~~ +tinyint +100 +~~END~~ + +select CAST(10 AS tinyint) / CAST(3 AS tinyint); +GO +~~START~~ +tinyint +3 +~~END~~ + + +-- test bit data type, bit defaults to sys.bit in tsql dialect +-- test 'true'/'false' input is allowed. 't'/'f' is not allowed. +select CAST('true' AS bit); +GO +~~START~~ +bit +1 +~~END~~ + +select CAST('True' AS bit); +GO +~~START~~ +bit +1 +~~END~~ + +select CAST('TRUE' AS bit); +GO +~~START~~ +bit +1 +~~END~~ + +select CAST('false' AS bit); +GO +~~START~~ +bit +0 +~~END~~ + +select CAST('False' AS bit); +GO +~~START~~ +bit +0 +~~END~~ + +select CAST('FALSE' AS bit); +GO +~~START~~ +bit +0 +~~END~~ + + +-- test '1'/'0' +select CAST('1' AS bit); +GO +~~START~~ +bit +1 +~~END~~ + +select CAST('0' AS bit); +GO +~~START~~ +bit +0 +~~END~~ + +select CAST('000' AS bit); +GO +~~START~~ +bit +0 +~~END~~ + +select CAST('010' AS bit); +GO +~~START~~ +bit +1 +~~END~~ + + +-- test 'abc' is not allowed +select CAST('abc' AS bit); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type bit: "abc")~~ + + +-- test NULL is allowed +select CAST(NULL AS bit); +GO +~~START~~ +bit + +~~END~~ + + +-- pg_catalog.bit doesn't recognize 'true' +select CAST('true' AS bit); +GO +~~START~~ +bit +1 +~~END~~ + +select CAST('1' AS bit); +GO +~~START~~ +bit +1 +~~END~~ + + + +-- test numeric and integer input +select CAST(1 AS bit); +GO +~~START~~ +bit +1 +~~END~~ + +select CAST(2 AS bit); +GO +~~START~~ +bit +1 +~~END~~ + +select CAST(0 AS bit); +GO +~~START~~ +bit +0 +~~END~~ + +select CAST(000 AS bit); +GO +~~START~~ +bit +0 +~~END~~ + +select CAST(0.0 AS bit); +GO +~~START~~ +bit +0 +~~END~~ + +select CAST(0.00 AS bit); +GO +~~START~~ +bit +0 +~~END~~ + +select CAST(0.5 AS bit); +GO +~~START~~ +bit +1 +~~END~~ + + +-- test negative operator +select CAST(-1 AS bit); +GO +~~START~~ +bit +1 +~~END~~ + +select CAST(-0.5 AS bit); +GO +~~START~~ +bit +1 +~~END~~ + + +-- test int2 int4 int8 input +select CAST(CAST(2 AS int2) AS bit); +GO +~~START~~ +bit +1 +~~END~~ + +select CAST(CAST(0 AS int2) AS bit); +GO +~~START~~ +bit +0 +~~END~~ + +select CAST(CAST(2 AS int4) AS bit); +GO +~~START~~ +bit +1 +~~END~~ + +select CAST(CAST(0 AS int4) AS bit); +GO +~~START~~ +bit +0 +~~END~~ + +select CAST(CAST(2 AS int8) AS bit); +GO +~~START~~ +bit +1 +~~END~~ + +select CAST(CAST(0 AS int8) AS bit); +GO +~~START~~ +bit +0 +~~END~~ + + +-- test real, double precision input +select CAST(CAST(1.5 AS real) AS bit); +GO +~~START~~ +bit +1 +~~END~~ + +select CAST(CAST(0.0 AS real) AS bit); +GO +~~START~~ +bit +0 +~~END~~ + +select CAST(CAST(1.5 AS double precision) AS bit); +GO +~~START~~ +bit +1 +~~END~~ + +select CAST(CAST(0.0 AS double precision) AS bit); +GO +~~START~~ +bit +0 +~~END~~ + + +-- test decimal, numeric input +select CAST(CAST(1.5 AS decimal(4,2)) AS bit); +GO +~~START~~ +bit +1 +~~END~~ + +select CAST(CAST(0.0 AS decimal(4,2)) AS bit); +GO +~~START~~ +bit +0 +~~END~~ + +select CAST(CAST(1.5 AS numeric(4,2)) AS bit); +GO +~~START~~ +bit +1 +~~END~~ + +select CAST(CAST(0.0 AS numeric(4,2)) AS bit); +GO +~~START~~ +bit +0 +~~END~~ + + +-- test operators of bit +create table testing6 (col1 bit, col2 bit); +GO +insert into testing6 (col1, col2) select 'true', 'false'; +insert into testing6 (col1, col2) select 0, 1; +insert into testing6 (col1, col2) select '1', '2'; +insert into testing6 (col1, col2) select 0.5, -1.5; +select * from testing6; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +bit#!#bit +1#!#0 +0#!#1 +1#!#1 +1#!#1 +~~END~~ + +select count(*) from testing6 where col1 = col2; +GO +~~START~~ +int +2 +~~END~~ + +select count(*) from testing6 where col1 <> col2; +GO +~~START~~ +int +2 +~~END~~ + +select count(*) from testing6 where col1 > col2; +GO +~~START~~ +int +1 +~~END~~ + +select count(*) from testing6 where col1 >= col2; +GO +~~START~~ +int +3 +~~END~~ + +select count(*) from testing6 where col1 < col2; +GO +~~START~~ +int +1 +~~END~~ + +select count(*) from testing6 where col1 <= col2; +GO +~~START~~ +int +3 +~~END~~ + + +-- test casting of bits to other numeric types +select cast(cast (1 as bit) as tinyint); +GO +~~START~~ +tinyint +1 +~~END~~ + +select cast(cast (1 as bit) as smallint); +GO +~~START~~ +smallint +1 +~~END~~ + +select cast(cast (1 as bit) as int); +GO +~~START~~ +int +1 +~~END~~ + +select cast(cast (1 as bit) as bigint); +GO +~~START~~ +bigint +1 +~~END~~ + +select cast(cast (1 as bit) as numeric(2,1)); +GO +~~START~~ +numeric +1.0 +~~END~~ + +select cast(cast (1 as bit) as money); +GO +~~START~~ +money +1.0000 +~~END~~ + +select cast(cast (1 as bit) as smallmoney); +GO +~~START~~ +smallmoney +1.0000 +~~END~~ + + + +-- test varbinary is available +select cast('abc' as varbinary(3)); +GO +~~START~~ +varbinary +616263 +~~END~~ + +-- test not throwing error if input would be truncated +select cast('abc' as varbinary(2)); +GO +~~START~~ +varbinary +6162 +~~END~~ + + +select * from testing6; +GO +~~START~~ +bit#!#bit +1#!#0 +0#!#1 +1#!#1 +1#!#1 +~~END~~ + + +-- test casting varbinary to varchar +select cast(cast('a' AS varchar(10)) as varbinary(2)); +GO +~~START~~ +varbinary +61 +~~END~~ + +select cast(cast(cast('a' AS varchar(10)) as varbinary(2)) as varchar(2)); +GO +~~START~~ +varchar +a +~~END~~ + +select cast(cast('ab' AS varchar(10)) as varbinary(2)); +GO +~~START~~ +varbinary +6162 +~~END~~ + +select cast(cast(cast('ab' AS varchar(10)) as varbinary(2)) as varchar(2)); +GO +~~START~~ +varchar +ab +~~END~~ + +select cast(cast('abc' AS varchar(10)) as varbinary(2)); +GO +~~START~~ +varbinary +6162 +~~END~~ + +select cast(cast(cast('abc' AS varchar(10)) as varbinary(2)) as varchar(2)); +GO +~~START~~ +varchar +ab +~~END~~ + + +-- test casting varbinary to nvarchar +select cast(cast('a' AS nvarchar(10)) as varbinary(2)); +GO +~~START~~ +varbinary +61 +~~END~~ + +select cast(cast(cast('a' AS nvarchar(10)) as varbinary(2)) as nvarchar(2)); +GO +~~START~~ +nvarchar +a +~~END~~ + +select cast(cast('ab' AS nvarchar(10)) as varbinary(2)); +GO +~~START~~ +varbinary +6162 +~~END~~ + +select cast(cast(cast('ab' AS nvarchar(10)) as varbinary(2)) as nvarchar(2)); +GO +~~START~~ +nvarchar +ab +~~END~~ + +select cast(cast('abc' AS nvarchar(10)) as varbinary(2)); +GO +~~START~~ +varbinary +6162 +~~END~~ + +select cast(cast(cast('abc' AS nvarchar(10)) as varbinary(2)) as nvarchar(2)); +GO +~~START~~ +nvarchar +ab +~~END~~ + + +-- test sys.image is available +select cast('abc' as image); +GO +~~START~~ +image +616263 +~~END~~ + + +-- test sys.binary is available +select cast('abc' as binary(3)); +GO +~~START~~ +binary +616263 +~~END~~ + +-- test not throwing error if input would be truncated +select cast('abc' as binary(2)); +GO +~~START~~ +binary +6162 +~~END~~ + + +drop table testing6; +GO +create table testing6(col binary(2)); +GO +-- test throwing error when not explicit casting +insert into testing6 values (cast('ab' as varchar)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Implicit conversion from data type varchar to binary is not allowed. Use the CONVERT function to run this query.)~~ + +insert into testing6 values (cast('ab' as binary(2))); +GO +~~ROW COUNT: 1~~ + +-- test throwing error if input would be truncated +insert into testing6 values (cast('abc' as binary(3))); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: String or binary data would be truncated. +The statement has been terminated.)~~ + +-- test null padding extra space for binary type +insert into testing6 values (cast('a' as binary(2))); +GO +~~ROW COUNT: 1~~ + +select * from testing6; +GO +~~START~~ +binary +6162 +6100 +~~END~~ + + +-- test casting binary to varchar +select cast(cast('a' AS varchar(10)) as binary(2)); +GO +~~START~~ +binary +6100 +~~END~~ + +-- BABEL-1030 +select cast(cast(cast('a' AS varchar(10)) as binary(2)) as varchar(2)); +GO +~~START~~ +varchar +a +~~END~~ + +select cast(cast('ab' AS varchar(10)) as binary(2)); +GO +~~START~~ +binary +6162 +~~END~~ + +select cast(cast(cast('ab' AS varchar(10)) as binary(2)) as varchar(2)); +GO +~~START~~ +varchar +ab +~~END~~ + +select cast(cast('abc' AS varchar(10)) as binary(2)); +GO +~~START~~ +binary +6162 +~~END~~ + +select cast(cast(cast('abc' AS varchar(10)) as binary(2)) as varchar(2)); +GO +~~START~~ +varchar +ab +~~END~~ + + +-- test casting binary to nvarchar +select cast(cast('a' AS nvarchar(10)) as binary(2)); +GO +~~START~~ +binary +6100 +~~END~~ + +-- BABEL-1030 +select cast(cast(cast('a' AS nvarchar(10)) as binary(2)) as nvarchar(2)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid Unicode code point 0x0)~~ + +select cast(cast('ab' AS nvarchar(10)) as binary(2)); +GO +~~START~~ +binary +6162 +~~END~~ + +select cast(cast(cast('ab' AS nvarchar(10)) as binary(2)) as nvarchar(2)); +GO +~~START~~ +nvarchar +ab +~~END~~ + +select cast(cast('abc' AS nvarchar(10)) as binary(2)); +GO +~~START~~ +binary +6162 +~~END~~ + +select cast(cast(cast('abc' AS nvarchar(10)) as binary(2)) as nvarchar(2)); +GO +~~START~~ +nvarchar +ab +~~END~~ + + +-- test varbinary(max) syntax +select CAST('010 ' AS varbinary(max)); +GO +~~START~~ +varbinary +30313020 +~~END~~ + +select CAST('010' AS varbinary(max)); +GO +~~START~~ +varbinary +303130 +~~END~~ + + + +-- test default length is 1 +drop table testing6; +GO +create table testing6(col varbinary); +GO +insert into testing6 values (cast('a' as varbinary)); +GO +~~ROW COUNT: 1~~ + +select * from testing6; +GO +~~START~~ +varbinary +61 +~~END~~ + +drop table testing6; +GO +create table testing6(col binary); +GO +insert into testing6 values (cast('a' as varbinary)); +GO +~~ROW COUNT: 1~~ + +insert into testing6 values (cast('ab' as varbinary)); +GO +~~ROW COUNT: 1~~ + +select * from testing6; +GO +~~START~~ +binary +61 +61 +~~END~~ + + +-- test default length of varbinary in cast/convert is 30 +-- truncation silently +select cast('abcdefghijklmnopqrstuvwxyzabcde' as varbinary); +GO +~~START~~ +varbinary +6162636465666768696A6B6C6D6E6F707172737475767778797A61626364 +~~END~~ + +-- no truncation +select cast('abcdefghijklmnopqrstuvwxyzabcd' as varbinary); +GO +~~START~~ +varbinary +6162636465666768696A6B6C6D6E6F707172737475767778797A61626364 +~~END~~ + + +-- truncation silently +select convert(varbinary, 'abcdefghijklmnopqrstuvwxyzabcde'); +GO +~~START~~ +varbinary +6162636465666768696A6B6C6D6E6F707172737475767778797A61626364 +~~END~~ + +-- no truncation +select convert(varbinary, 'abcdefghijklmnopqrstuvwxyzabcd'); +GO +~~START~~ +varbinary +6162636465666768696A6B6C6D6E6F707172737475767778797A61626364 +~~END~~ + + + +-- test escape format '\' is not specially handled for varbinary +-- but it is escaped handled for bytea +select CAST('\13' AS varbinary(5)); +GO +~~START~~ +varbinary +5C3133 +~~END~~ + +select CAST('\x13' AS varbinary(5)); +GO +~~START~~ +varbinary +5C783133 +~~END~~ + +select CAST('\x13' AS bytea); +GO +~~START~~ +varbinary +13 +~~END~~ + +select CAST('\\' AS varbinary(5)); +GO +~~START~~ +varbinary +5C5C +~~END~~ + +select CAST('\\' AS bytea); +GO +~~START~~ +varbinary +5C +~~END~~ + +select CAST('\' AS varbinary); +GO +~~START~~ +varbinary +5C +~~END~~ + + + +-- test NULL pad extra space for binary type, not for varbinary and image +select CAST('\\' AS binary(3)); +GO +~~START~~ +binary +5C5C00 +~~END~~ + +select CAST('\\' AS varbinary(3)); +GO +~~START~~ +varbinary +5C5C +~~END~~ + +select CAST('\\' AS image); +GO +~~START~~ +image +5C5C +~~END~~ + + +-- [BABEL-254] test integer input is allowed for varbinary +select cast(16 as varbinary(4)); +GO +~~START~~ +varbinary +00000010 +~~END~~ + +select cast(16*16 as varbinary(4)); +GO +~~START~~ +varbinary +00000100 +~~END~~ + +select cast(16*16*16 as varbinary(4)); +GO +~~START~~ +varbinary +00001000 +~~END~~ + +select cast(511 as varbinary(4)); +GO +~~START~~ +varbinary +000001FF +~~END~~ + +-- test truncation to the left if the number input is too large +select cast(16*16*16*16 as varbinary(2)); +GO +~~START~~ +varbinary +0000 +~~END~~ + +-- test same behavior on table insert +drop table testing6; +GO +create table testing6 (col varbinary(2)); +GO +insert into testing6 values (16); +GO +~~ROW COUNT: 1~~ + +insert into testing6 values (16*16); +GO +~~ROW COUNT: 1~~ + +insert into testing6 values (16*16*16); +GO +~~ROW COUNT: 1~~ + +insert into testing6 values (16*16*16*16); +GO +~~ROW COUNT: 1~~ + +select * from testing6; +GO +~~START~~ +varbinary +0010 +0100 +1000 +0000 +~~END~~ + + +-- test int2, int4, int8 to varbinary +select cast(16*CAST(16 AS int2) as varbinary(2)); +GO +~~START~~ +varbinary +0100 +~~END~~ + +select cast(16*CAST(16 AS int4) as varbinary(4)); +GO +~~START~~ +varbinary +00000100 +~~END~~ + +select cast(16*CAST(16 AS int8) as varbinary(8)); +GO +~~START~~ +varbinary +0000000000000100 +~~END~~ + + +-- test truncation to the left if maxlen is shorter than the input +select cast(CAST(16 AS int2) as varbinary(1)); +GO +~~START~~ +varbinary +10 +~~END~~ + +select cast(CAST(16 AS int2) as varbinary(2)); +GO +~~START~~ +varbinary +0010 +~~END~~ + +-- test varbinary will only use 2 bytes (the size of the input) rather +-- than maxlen +select cast(CAST(16 AS int2) as varbinary(3)); +GO +~~START~~ +varbinary +0010 +~~END~~ + +select cast(CAST(16 AS int2) as varbinary(4)); +GO +~~START~~ +varbinary +0010 +~~END~~ + +select cast(CAST(16 AS int2) as varbinary(8)); +GO +~~START~~ +varbinary +0010 +~~END~~ + + +select cast(CAST(16 AS int4) as varbinary(1)); +GO +~~START~~ +varbinary +10 +~~END~~ + +select cast(CAST(16 AS int4) as varbinary(2)); +GO +~~START~~ +varbinary +0010 +~~END~~ + +select cast(CAST(16 AS int4) as varbinary(3)); +GO +~~START~~ +varbinary +000010 +~~END~~ + +select cast(CAST(16 AS int4) as varbinary(4)); +GO +~~START~~ +varbinary +00000010 +~~END~~ + +select cast(CAST(16 AS int4) as varbinary(8)); +GO +~~START~~ +varbinary +00000010 +~~END~~ + + +select cast(CAST(16 AS int8) as varbinary(1)); +GO +~~START~~ +varbinary +10 +~~END~~ + +select cast(CAST(16 AS int8) as varbinary(2)); +GO +~~START~~ +varbinary +0010 +~~END~~ + +select cast(CAST(16 AS int8) as varbinary(3)); +GO +~~START~~ +varbinary +000010 +~~END~~ + +select cast(CAST(16 AS int8) as varbinary(4)); +GO +~~START~~ +varbinary +00000010 +~~END~~ + +select cast(CAST(16 AS int8) as varbinary(8)); +GO +~~START~~ +varbinary +0000000000000010 +~~END~~ + + +-- [BABEL-254] test integer iput is allowed for binary +select cast(16 as binary(2)); +GO +~~START~~ +binary +0010 +~~END~~ + +select cast(16*16 as binary(2)); +GO +~~START~~ +binary +0100 +~~END~~ + +select cast(16*16*16 as binary(2)); +GO +~~START~~ +binary +1000 +~~END~~ + +-- test truncation to the left if the number input is too large +select cast(16*16*16*16 as binary(2)); +GO +~~START~~ +binary +0000 +~~END~~ + +-- test same behavior on table insert +drop table testing6; +GO +create table testing6 (col binary(2)); +GO +insert into testing6 values (16); +GO +~~ROW COUNT: 1~~ + +insert into testing6 values (16*16); +GO +~~ROW COUNT: 1~~ + +insert into testing6 values (16*16*16); +GO +~~ROW COUNT: 1~~ + +insert into testing6 values (16*16*16*16); +GO +~~ROW COUNT: 1~~ + +select * from testing6; +GO +~~START~~ +binary +0010 +0100 +1000 +0000 +~~END~~ + + +-- test int2, int4, int8 to binary +select cast(16*CAST(16 AS int2) as binary(2)); +GO +~~START~~ +binary +0100 +~~END~~ + +select cast(16*CAST(16 AS int4) as binary(4)); +GO +~~START~~ +binary +00000100 +~~END~~ + +select cast(16*CAST(16 AS int8) as binary(8)); +GO +~~START~~ +binary +0000000000000100 +~~END~~ + + +-- test truncation to the left if maxlen is shorter than the input +select cast(CAST(16 AS int2) as binary(1)); +GO +~~START~~ +binary +10 +~~END~~ + +select cast(CAST(16 AS int2) as binary(2)); +GO +~~START~~ +binary +0010 +~~END~~ + +select cast(CAST(16 AS int2) as binary(3)); +GO +~~START~~ +binary +000010 +~~END~~ + +-- test 0 padding to the left if maxlen is longer than the input +select cast(CAST(16 AS int2) as binary(4)); +GO +~~START~~ +binary +00000010 +~~END~~ + +select cast(CAST(16 AS int2) as binary(8)); +GO +~~START~~ +binary +0000000000000010 +~~END~~ + + +select cast(CAST(16 AS int4) as binary(1)); +GO +~~START~~ +binary +10 +~~END~~ + +select cast(CAST(16 AS int4) as binary(2)); +GO +~~START~~ +binary +0010 +~~END~~ + +select cast(CAST(16 AS int4) as binary(3)); +GO +~~START~~ +binary +000010 +~~END~~ + +select cast(CAST(16 AS int4) as binary(4)); +GO +~~START~~ +binary +00000010 +~~END~~ + +-- test 0 padding to the left if maxlen is longer than the input +select cast(CAST(16 AS int4) as binary(8)); +GO +~~START~~ +binary +0000000000000010 +~~END~~ + + +select cast(CAST(16 AS int8) as binary(1)); +GO +~~START~~ +binary +10 +~~END~~ + +select cast(CAST(16 AS int8) as binary(2)); +GO +~~START~~ +binary +0010 +~~END~~ + +select cast(CAST(16 AS int8) as binary(3)); +GO +~~START~~ +binary +000010 +~~END~~ + +select cast(CAST(16 AS int8) as binary(4)); +GO +~~START~~ +binary +00000010 +~~END~~ + +select cast(CAST(16 AS int8) as binary(8)); +GO +~~START~~ +binary +0000000000000010 +~~END~~ + +-- test 0 padding to the left if maxlen is longer than the input +select cast(CAST(16 AS int8) as binary(10)); +GO +~~START~~ +binary +00000000000000000010 +~~END~~ + + +-- test casting varbinary to int4 +CREATE PROCEDURE cast_varbinary(@val int) AS +BEGIN + DECLARE @BinaryVariable varbinary(4) = @val + PRINT @BinaryVariable + PRINT cast(@BinaryVariable as int) +END; +GO + +EXEC cast_varbinary 16; +GO + +EXEC cast_varbinary 511; +GO +drop procedure cast_varbinary; +GO + +-- test real to varbinary +select cast(CAST(0.125 AS real) as varbinary(4)); +GO +~~START~~ +varbinary +3E000000 +~~END~~ + +drop table testing6; +GO +create table testing6 (col varbinary(4)); +GO +insert into testing6 values (CAST(0.125 AS real)); +insert into testing6 values (CAST(3.125 AS real)); +select * from testing6; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +varbinary +3E000000 +40480000 +~~END~~ + + +-- test truncation rule when input is too long/varbinary length is too short +select cast(CAST(0.125 AS real) as varbinary(2)); +GO +~~START~~ +varbinary +0000 +~~END~~ + +select cast(CAST(0.125 AS real) as varbinary(4)); +GO +~~START~~ +varbinary +3E000000 +~~END~~ + + +-- test dobule precision to varbinary +select cast(CAST(0.123456789 AS double precision) as varbinary(8)); +GO +~~START~~ +varbinary +3FBF9ADD3739635F +~~END~~ + +drop table testing6; +GO +create table testing6 (col varbinary(8)); +GO +insert into testing6 values (CAST(0.123456789 AS double precision)); +insert into testing6 values (CAST(3.123456789 AS double precision)); +select * from testing6; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +varbinary +3FBF9ADD3739635F +4008FCD6E9B9CB1B +~~END~~ + + +-- test truncation rule when input is too long/varbinary length is too short +select cast(CAST(0.123456789 AS double precision) as varbinary(2)); +GO +~~START~~ +varbinary +635F +~~END~~ + +select cast(CAST(0.123456789 AS double precision) as varbinary(8)); +GO +~~START~~ +varbinary +3FBF9ADD3739635F +~~END~~ + + + +-- test real to binary +select cast(CAST(0.125 AS real) as binary(4)); +GO +~~START~~ +binary +3E000000 +~~END~~ + +drop table testing6; +GO +create table testing6 (col binary(4)); +GO +insert into testing6 values (CAST(0.125 AS real)); +insert into testing6 values (CAST(3.125 AS real)); +select * from testing6; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +binary +3E000000 +40480000 +~~END~~ + + +-- test truncation rule when input is too long/binary length is too short +select cast(CAST(0.125 AS real) as binary(2)); +GO +~~START~~ +binary +0000 +~~END~~ + +select cast(CAST(0.125 AS real) as binary(4)); +GO +~~START~~ +binary +3E000000 +~~END~~ + + + +-- test dobule precision to binary +select cast(CAST(0.123456789 AS double precision) as binary(8)); +GO +~~START~~ +binary +3FBF9ADD3739635F +~~END~~ + +drop table testing6; +GO +create table testing6 (col binary(8)); +GO +insert into testing6 values (CAST(0.123456789 AS double precision)); +insert into testing6 values (CAST(3.123456789 AS double precision)); +select * from testing6; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +binary +3FBF9ADD3739635F +4008FCD6E9B9CB1B +~~END~~ + + +-- test truncation rule when input is too long/binary length is too short +select cast(CAST(0.123456789 AS double precision) as binary(2)); +GO +~~START~~ +binary +635F +~~END~~ + +select cast(CAST(0.123456789 AS double precision) as binary(8)); +GO +~~START~~ +binary +3FBF9ADD3739635F +~~END~~ + + + +-- sys.sysname +select CAST('£' AS sysname); -- allowed +GO +~~START~~ +varchar +£ +~~END~~ + +select CAST(NULL AS sysname); -- not allowed +GO +~~START~~ +varchar + +~~END~~ + + +-- sys.sysname is working in both dialects +select CAST('£' AS sys.sysname); -- allowed +GO +~~START~~ +varchar +£ +~~END~~ + +select CAST(NULL AS sys.sysname); -- not allowed +GO +~~START~~ +varchar + +~~END~~ + +select CAST('£' AS sys.sysname); -- allowed +GO +~~START~~ +varchar +£ +~~END~~ + +select CAST(NULL AS sys.sysname); -- not allowed +GO +~~START~~ +varchar + +~~END~~ + + + +create table test_sysname (col sys.sysname); +GO +insert into test_sysname values (repeat('£', 128)); -- allowed +GO +~~ROW COUNT: 1~~ + +insert into test_sysname values (repeat('😀', 128)); -- not allowed due to UTF check +GO +~~ROW COUNT: 1~~ + +insert into test_sysname values (repeat('😀', 128)); -- not allowed due to UTF check +GO +~~ROW COUNT: 1~~ + + + +-- clean up +drop table testing1; +GO +drop table testing2; +GO +drop table testing3; +GO +drop table testing4; +GO +drop table testing5; +GO +drop table testing6; +GO +drop table test_sysname; +GO diff --git a/test/JDBC/expected/babel_ddl.out b/test/JDBC/expected/babel_ddl.out new file mode 100644 index 0000000000..1d4a252481 --- /dev/null +++ b/test/JDBC/expected/babel_ddl.out @@ -0,0 +1,399 @@ +-- CLUSTERED INDEX / NONCLUSTERED IDNEX +create table t1 ( a int, b int); +GO + +create nonclustered index t1_idx1 on t1 (a); +GO + +create clustered index t1_idx2 on t1(a); +GO + +create table t2 ( a int, b int, primary key nonclustered (a)); +GO +create table t3 ( a int, b int, primary key clustered (a)); +GO +create table t4 ( a int, b int, unique nonclustered (a)); +GO +create table t5 ( a int, b int, unique clustered (a)); +GO + +create table t6 ( a int primary key nonclustered, b int); +GO +create table t7 ( a int primary key clustered, b int); +GO + +create table t8 ( a int unique not null, b int); +GO +create table t9 ( a int unique not null, b int); +GO + +-- CREATE INDEX ... ON syntax +create index t1_idx3 on t1 (a) on [primary]; +GO +create index t1_idx4 on t1 (a) on "default"; +GO + +-- CREATE TABLE WITH ( [,...n]) syntax +create table t12 (a int) +with (system_versioning = on (history_table = aaa.bbb, data_consistency_check = off)); +GO +create table t13 (a int) +with (remote_data_archive = on (filter_predicate = null, migration_state = outbound)); +GO +create table t14 (a int) +with (data_deletion = on (filter_column = a, retention_period = 14 day)); +GO + + +-- CREATE TABLE... WITH FILLFACTOR = num +create table t15 (a int primary key with fillfactor=50); +GO +-- ALTER TABLE... WITH FILLFACTOR = num +create table t16 (a int not null); +GO +alter table t16 add primary key (a) with fillfactor=50; +GO + +-- check property of the index +select indexname, indexdef from pg_indexes where tablename like 't_' order by indexname; +GO +~~START~~ +varchar#!#text +t1_idx1t18e881e6977bd6b8cbb78725b3a8ac988#!#CREATE INDEX t1_idx1t18e881e6977bd6b8cbb78725b3a8ac988 ON master_dbo.t1 USING btree (a) +t1_idx2t117dbbb74ced1fe936cdf7cd7baeff266#!#CREATE INDEX t1_idx2t117dbbb74ced1fe936cdf7cd7baeff266 ON master_dbo.t1 USING btree (a) +t1_idx3t19eceb46c036c3c1bd6895a34ec3c93f1#!#CREATE INDEX t1_idx3t19eceb46c036c3c1bd6895a34ec3c93f1 ON master_dbo.t1 USING btree (a) +t1_idx4t1fb4b953a652720bfa47919dff09b172e#!#CREATE INDEX t1_idx4t1fb4b953a652720bfa47919dff09b172e ON master_dbo.t1 USING btree (a) +t2_pkey#!#CREATE UNIQUE INDEX t2_pkey ON master_dbo.t2 USING btree (a) +t3_pkey#!#CREATE UNIQUE INDEX t3_pkey ON master_dbo.t3 USING btree (a) +t4_a_key#!#CREATE UNIQUE INDEX t4_a_key ON master_dbo.t4 USING btree (a) +t5_a_key#!#CREATE UNIQUE INDEX t5_a_key ON master_dbo.t5 USING btree (a) +t6_pkey#!#CREATE UNIQUE INDEX t6_pkey ON master_dbo.t6 USING btree (a) +t7_pkey#!#CREATE UNIQUE INDEX t7_pkey ON master_dbo.t7 USING btree (a) +t8_a_key#!#CREATE UNIQUE INDEX t8_a_key ON master_dbo.t8 USING btree (a) +t9_a_key#!#CREATE UNIQUE INDEX t9_a_key ON master_dbo.t9 USING btree (a) +~~END~~ + + +-- CREATE TABLE(..., { PRIMARY KEY | UNIQUE } ... +-- ON { partition_scheme | filegroup | "default" }) syntax +-- ^ +create table t17(a int, primary key clustered (a) on [PRIMARY]); +GO +create table t18(a int, primary key clustered (a) on [PRIMARY]); +GO +create table t19(a int, unique clustered (a) on [PRIMARY]); +GO +create table t20(a int, unique clustered (a) on [PRIMARY]); +GO + +-- ALTER TABLE ... ADD [CONSTRAINT ...] DEFAULT ... FOR ... +create table t21 (a int, b int); +GO +alter table t21 add default 99 for a; +GO +insert into t21(b) values (10); +GO +~~ROW COUNT: 1~~ + +select * from t21; +GO +~~START~~ +int#!#int +99#!#10 +~~END~~ + + +alter table t21 add constraint dflt11 default 11 for a; +GO +insert into t21(b) values (20); +GO +~~ROW COUNT: 1~~ + +select * from t21; +GO +~~START~~ +int#!#int +99#!#10 +11#!#20 +~~END~~ + + +-- Invalid default value +alter table t21 add default 'test' for a; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type integer: "test")~~ + +-- Invalid column +alter table t21 add default 99 for c; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "c" of relation "t21" does not exist)~~ + +-- Invalid table +alter table t_invalid add default 99 for a; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "t_invalid" does not exist)~~ + + +-- ALTER TABLE ... WITH [NO]CHECK ADD CONSTRAINT ... +insert into t21 values (1, 1); +GO +~~ROW COUNT: 1~~ + +-- error, not fulfilling constraint chk1 +insert into t21 values (0, 1); +GO +~~ROW COUNT: 1~~ + +-- should pass after CHECK/NOCHECK is fully supported +insert into t21 values (1, 0); +GO +~~ROW COUNT: 1~~ + +select * from t21; +GO +~~START~~ +int#!#int +99#!#10 +11#!#20 +1#!#1 +0#!#1 +1#!#0 +~~END~~ + + + +-- ROWGUIDCOL syntax support +create table t24 (a uniqueidentifier ROWGUIDCOL); +GO +create table t25 (a int); +GO +alter table t25 add b uniqueidentifier ROWGUIDCOL; +GO + +-- computed columns +-- CREATE TABLE(..., AS +-- ^ [ PERSISTED ] ) +create table computed_column_t1 (a nvarchar(10), b AS substring(a,1,3) UNIQUE NOT NULL); +GO +insert into computed_column_t1 values('abcd'); +GO +~~ROW COUNT: 1~~ + +select * from computed_column_t1; +GO +~~START~~ +nvarchar#!#nvarchar +abcd#!#abc +~~END~~ + + +-- test whether other constraints are working with computed columns +insert into computed_column_t1 values('abcd'); -- throws error +GO +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "computed_column_t1_b_key")~~ + + +-- check PERSISTED keyword +-- should be able to use columns from left and right in the expression +create table computed_column_t2 (a int, b AS (a + c) / 4 PERSISTED, c int); +GO +insert into computed_column_t2 (a,c) values (12, 12); +GO +~~ROW COUNT: 1~~ + +select * from computed_column_t2; +GO +~~START~~ +int#!#int#!#int +12#!#6#!#12 +~~END~~ + + +-- should throw error - order matters +create table computed_column_error (a int, b AS a/4 NOT NULL PERSISTED); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'PERSISTED' is not currently supported in Babelfish)~~ + + +-- should throw error if postgres syntax is used in TSQL dialect +create table computed_column_error (a int, b numeric generated always as (a/4) stored); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near '(' at line 2 and character position 73)~~ + + +-- should throw error if there is any error in computed column expression +create table computed_column_error (a nvarchar(10), b AS non_existant_function(a,1,3) UNIQUE NOT NULL); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function non_existant_function(nvarchar, integer, integer) does not exist)~~ + +-- should throw error in case of nested computed columns +create table computed_column_error (a int, b as c, c as a); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: computed column "c" in table "computed_column_error" is not allowed to be used in another computed-column definition)~~ + +create table computed_column_error (a int, b as b + 1); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: computed column "b" in table "computed_column_error" is not allowed to be used in another computed-column definition)~~ + + +-- in case of multiple computed column, the entire statement should be rolled +-- back even when the last one throws error +create table computed_column_error (a int, b as a, c as b); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: computed column "b" in table "computed_column_error" is not allowed to be used in another computed-column definition)~~ + +select * from computed_column_error; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "computed_column_error" does not exist)~~ + + +-- ALTER TABLE... ADD AS +-- ^ [ PERSISTED ] ) +alter table computed_column_t1 add c int; +GO +alter table computed_column_t1 add d as c / 4; +GO +insert into computed_column_t1(a, c) VALUES ('efgh', 12); +GO +~~ROW COUNT: 1~~ + +select * from computed_column_t1; +GO +~~START~~ +nvarchar#!#nvarchar#!#int#!#int +abcd#!#abc#!##!# +efgh#!#efg#!#12#!#3 +~~END~~ + + +--should thow error in case of nested computed columns +alter table computed_column_t1 add e as d; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot use generated column "d" in column generation expression)~~ + +alter table computed_column_t1 add e as e + 1; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: computed column "e" in table "computed_column_t1" is not allowed to be used in another computed-column definition)~~ + + +-- should throw error if any of the dependant columns is modified or dropped. +alter table computed_column_t1 drop column a; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot drop a column used by a generated column)~~ + +alter table computed_column_t1 alter column a varchar; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot alter type of a column used by a generated column)~~ + + +-- should throw error as rand is non-deterministic +alter table computed_column_t1 add e as rand() persisted; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: generation expression is not immutable)~~ + + +-- but rand[seed] should succeed +alter table computed_column_t1 add e as rand(1) persisted; +GO + +-- should throw error in postgres dialect +select set_config('babelfishpg_tsql.sql_dialect', 'postgres', null); +GO +~~START~~ +text +postgres +~~END~~ + +create table computed_column_error (a int, b AS (a/4) PERSISTED NOT NULL); +GO + +-- since we're in postgres dialect, also check the table definition whether +-- the computed column got resolved to correct datatype +SELECT * FROM computed_column_t1 +GO +~~START~~ +nvarchar#!#nvarchar#!#int#!#int#!#float +abcd#!#abc#!##!##!#0.39485815595643303 +efgh#!#efg#!#12#!#3#!#0.39485815595643303 +~~END~~ + + + +drop table t1; +GO +drop table t2; +GO +drop table t3; +GO +drop table t4; +GO +drop table t5; +GO +drop table t6; +GO +drop table t7; +GO +drop table t8; +GO +drop table t9; +GO +drop table t12; +GO +drop table t13; +GO +drop table t14; +GO +drop table t15; +GO +drop table t16; +GO +drop table t17; +GO +drop table t18; +GO +drop table t19; +GO +drop table t20; +GO +drop table t21; +GO +drop table t24; +GO +drop table t25; +GO +drop table computed_column_t1; +GO +drop table computed_column_t2; +GO diff --git a/test/JDBC/expected/babel_delete1.out b/test/JDBC/expected/babel_delete1.out new file mode 100644 index 0000000000..a68b738fc8 --- /dev/null +++ b/test/JDBC/expected/babel_delete1.out @@ -0,0 +1,352 @@ +CREATE TABLE delete_test_tbl ( + age int, + fname char(10), + lname char(10), + city nchar(20) +); +GO + +INSERT INTO delete_test_tbl(age, fname, lname, city) +VALUES (50, 'fname1', 'lname1', 'london'), + (34, 'fname2', 'lname2', 'paris'), + (35, 'fname3', 'lname3', 'brussels'), + (90, 'fname4', 'lname4', 'new york'), + (26, 'fname5', 'lname5', 'los angeles'), + (74, 'fname6', 'lname6', 'tokyo'), + (44, 'fname7', 'lname7', 'oslo'), + (19, 'fname8', 'lname8', 'hong kong'), + (61, 'fname9', 'lname9', 'shanghai'), + (29, 'fname10', 'lname10', 'mumbai'); +SELECT * FROM delete_test_tbl ORDER BY age DESC, city ASC; +GO +~~ROW COUNT: 10~~ + +~~START~~ +int#!#char#!#char#!#nchar +90#!#fname4 #!#lname4 #!#new york +74#!#fname6 #!#lname6 #!#tokyo +61#!#fname9 #!#lname9 #!#shanghai +50#!#fname1 #!#lname1 #!#london +44#!#fname7 #!#lname7 #!#oslo +35#!#fname3 #!#lname3 #!#brussels +34#!#fname2 #!#lname2 #!#paris +29#!#fname10 #!#lname10 #!#mumbai +26#!#fname5 #!#lname5 #!#los angeles +19#!#fname8 #!#lname8 #!#hong kong +~~END~~ + + +-- Prove that a user may delete rows from a table without using the FROM clause +SELECT * FROM delete_test_tbl ORDER BY age DESC, city ASC; +GO +~~START~~ +int#!#char#!#char#!#nchar +90#!#fname4 #!#lname4 #!#new york +74#!#fname6 #!#lname6 #!#tokyo +61#!#fname9 #!#lname9 #!#shanghai +50#!#fname1 #!#lname1 #!#london +44#!#fname7 #!#lname7 #!#oslo +35#!#fname3 #!#lname3 #!#brussels +34#!#fname2 #!#lname2 #!#paris +29#!#fname10 #!#lname10 #!#mumbai +26#!#fname5 #!#lname5 #!#los angeles +19#!#fname8 #!#lname8 #!#hong kong +~~END~~ + + +-- Test that that WHERE clause can be used without FROM +DELETE delete_test_tbl WHERE city='hong kong'; +GO +~~ROW COUNT: 1~~ + +SELECT * FROM delete_test_tbl ORDER BY age DESC, city ASC; +GO +~~START~~ +int#!#char#!#char#!#nchar +90#!#fname4 #!#lname4 #!#new york +74#!#fname6 #!#lname6 #!#tokyo +61#!#fname9 #!#lname9 #!#shanghai +50#!#fname1 #!#lname1 #!#london +44#!#fname7 #!#lname7 #!#oslo +35#!#fname3 #!#lname3 #!#brussels +34#!#fname2 #!#lname2 #!#paris +29#!#fname10 #!#lname10 #!#mumbai +26#!#fname5 #!#lname5 #!#los angeles +~~END~~ + + +DELETE delete_test_tbl WHERE age > 50; +GO +~~ROW COUNT: 3~~ + +SELECT * FROM delete_test_tbl ORDER BY age DESC, city ASC; +GO +~~START~~ +int#!#char#!#char#!#nchar +50#!#fname1 #!#lname1 #!#london +44#!#fname7 #!#lname7 #!#oslo +35#!#fname3 #!#lname3 #!#brussels +34#!#fname2 #!#lname2 #!#paris +29#!#fname10 #!#lname10 #!#mumbai +26#!#fname5 #!#lname5 #!#los angeles +~~END~~ + + +DELETE delete_test_tbl WHERE fname IN ('fname1', 'fname2'); +GO +~~ROW COUNT: 2~~ + +SELECT * FROM delete_test_tbl ORDER BY age DESC, city ASC; +GO +~~START~~ +int#!#char#!#char#!#nchar +44#!#fname7 #!#lname7 #!#oslo +35#!#fname3 #!#lname3 #!#brussels +29#!#fname10 #!#lname10 #!#mumbai +26#!#fname5 #!#lname5 #!#los angeles +~~END~~ + + +-- Test that DELETE works without any other clauses +DELETE delete_test_tbl; +GO +~~ROW COUNT: 4~~ + +SELECT * FROM delete_test_tbl ORDER BY age DESC, city ASC; +GO +~~START~~ +int#!#char#!#char#!#nchar +~~END~~ + + +-- Test delete for joined table +CREATE TABLE delete_test_tbl2 ( + age int, + fname char(10), + lname char(10), + city nchar(20) +); +GO + +INSERT INTO delete_test_tbl2(age, fname, lname, city) +VALUES (50, 'fname1', 'lname1', 'london'), + (34, 'fname2', 'lname2', 'paris'), + (50, 'fname3', 'lname3', 'brussels'), + (90, 'fname4', 'lname4', 'new york'), + (26, 'fname5', 'lname5', 'los angeles'), + (74, 'fname6', 'lname6', 'tokyo'), + (44, 'fname7', 'lname7', 'oslo'), + (19, 'fname8', 'lname8', 'hong kong'), + (61, 'fname9', 'lname9', 'shanghai'), + (29, 'fname10', 'lname10', 'mumbai'); +GO +~~ROW COUNT: 10~~ + + +CREATE TABLE delete_test_tbl3 ( + year int, + lname char(10), +); +GO + +INSERT INTO delete_test_tbl3(year, lname) +VALUES (51, 'lname1'), + (34, 'lname3'), + (25, 'lname8'), + (95, 'lname9'), + (36, 'lname10'); +GO +~~ROW COUNT: 5~~ + + +CREATE TABLE delete_test_tbl4 ( + lname char(10), + city char(10), +); +GO + +INSERT INTO delete_test_tbl4(lname, city) +VALUES ('lname8','london'), + ('lname9','tokyo'), + ('lname10','mumbai'); +GO +~~ROW COUNT: 3~~ + + +SELECT * FROM delete_test_tbl2 ORDER BY lname; +GO +~~START~~ +int#!#char#!#char#!#nchar +50#!#fname1 #!#lname1 #!#london +29#!#fname10 #!#lname10 #!#mumbai +34#!#fname2 #!#lname2 #!#paris +50#!#fname3 #!#lname3 #!#brussels +90#!#fname4 #!#lname4 #!#new york +26#!#fname5 #!#lname5 #!#los angeles +74#!#fname6 #!#lname6 #!#tokyo +44#!#fname7 #!#lname7 #!#oslo +19#!#fname8 #!#lname8 #!#hong kong +61#!#fname9 #!#lname9 #!#shanghai +~~END~~ + +SELECT * FROM delete_test_tbl3 ORDER BY lname; +GO +~~START~~ +int#!#char +51#!#lname1 +36#!#lname10 +34#!#lname3 +25#!#lname8 +95#!#lname9 +~~END~~ + +SELECT * FROM delete_test_tbl4 ORDER BY lname; +GO +~~START~~ +char#!#char +lname10 #!#mumbai +lname8 #!#london +lname9 #!#tokyo +~~END~~ + + + + +DELETE delete_test_tbl2 +FROM delete_test_tbl2 t2 +INNER JOIN delete_test_tbl3 t3 +ON t2.lname = t3.lname +WHERE year > 50; +SELECT * FROM delete_test_tbl2 ORDER BY lname; +GO +~~ROW COUNT: 2~~ + +~~START~~ +int#!#char#!#char#!#nchar +29#!#fname10 #!#lname10 #!#mumbai +34#!#fname2 #!#lname2 #!#paris +50#!#fname3 #!#lname3 #!#brussels +90#!#fname4 #!#lname4 #!#new york +26#!#fname5 #!#lname5 #!#los angeles +74#!#fname6 #!#lname6 #!#tokyo +44#!#fname7 #!#lname7 #!#oslo +19#!#fname8 #!#lname8 #!#hong kong +~~END~~ + + + +DELETE delete_test_tbl2 +FROM delete_test_tbl3 t3 +LEFT JOIN delete_test_tbl2 t2 +ON t2.lname = t3.lname +WHERE t3.year < 30 AND t2.age > 40; +SELECT * FROM delete_test_tbl2 ORDER BY lname; +GO +~~START~~ +int#!#char#!#char#!#nchar +29#!#fname10 #!#lname10 #!#mumbai +34#!#fname2 #!#lname2 #!#paris +50#!#fname3 #!#lname3 #!#brussels +90#!#fname4 #!#lname4 #!#new york +26#!#fname5 #!#lname5 #!#los angeles +74#!#fname6 #!#lname6 #!#tokyo +44#!#fname7 #!#lname7 #!#oslo +19#!#fname8 #!#lname8 #!#hong kong +~~END~~ + + + +-- delete with outer join on multiple tables +DELETE delete_test_tbl2 +FROM delete_test_tbl4 t4 +LEFT JOIN delete_test_tbl2 t2 +ON t4.city = t2.city +LEFT JOIN delete_test_tbl3 t3 +ON t2.lname = t3.lname +WHERE t4.city = 'mumbai'; +SELECT * FROM delete_test_tbl2 ORDER BY lname; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#char#!#char#!#nchar +34#!#fname2 #!#lname2 #!#paris +50#!#fname3 #!#lname3 #!#brussels +90#!#fname4 #!#lname4 #!#new york +26#!#fname5 #!#lname5 #!#los angeles +74#!#fname6 #!#lname6 #!#tokyo +44#!#fname7 #!#lname7 #!#oslo +19#!#fname8 #!#lname8 #!#hong kong +~~END~~ + + + +-- delete when target table not shown in JoinExpr +DELETE delete_test_tbl2 +FROM delete_test_tbl4 t4 +LEFT JOIN delete_test_tbl3 t3 +ON t3.lname = t4.lname +WHERE t4.city = 'mumbai'; +SELECT * FROM delete_test_tbl2 ORDER BY lname; +GO +~~ROW COUNT: 7~~ + +~~START~~ +int#!#char#!#char#!#nchar +~~END~~ + + + +-- delete with self join +DELETE delete_test_tbl3 +FROM delete_test_tbl3 t1 +INNER JOIN delete_test_tbl3 t2 +on t1.lname = t2.lname; +SELECT * FROM delete_test_tbl3 ORDER BY lname; +GO +~~ROW COUNT: 5~~ + +~~START~~ +int#!#char +~~END~~ + + +DELETE delete_test_tbl2 +FROM delete_test_tbl2 c +JOIN +(SELECT lname, fname, age from delete_test_tbl2) b +on b.lname = c.lname +JOIN +(SELECT lname, city, age from delete_test_tbl2) a +on a.city = c.city; +SELECT * FROM delete_test_tbl2 ORDER BY lname; +GO +~~START~~ +int#!#char#!#char#!#nchar +~~END~~ + + + +DELETE delete_test_tbl4 +FROM +(SELECT lname, city from delete_test_tbl4) b +JOIN +(SELECT lname from delete_test_tbl4) a +on a.lname = b.lname; +SELECT * FROM delete_test_tbl4 ORDER BY lname; +GO +~~ROW COUNT: 3~~ + +~~START~~ +char#!#char +~~END~~ + + +DROP TABLE delete_test_tbl; +GO +DROP TABLE delete_test_tbl2; +GO +DROP TABLE delete_test_tbl3; +GO +DROP TABLE delete_test_tbl4; +GO diff --git a/test/JDBC/expected/babel_emoji.out b/test/JDBC/expected/babel_emoji.out new file mode 100644 index 0000000000..93ef792bc4 --- /dev/null +++ b/test/JDBC/expected/babel_emoji.out @@ -0,0 +1,184 @@ +-- Test SYS.NCHAR, SYS.NVARCHAR and SYS.VARCHAR +-- nchar is already available in postgres dialect +select CAST('£' AS nchar(1)); +GO +~~START~~ +nchar +£ +~~END~~ + +-- nvarchar is not available in postgres dialect +select CAST('£' AS nvarchar); +GO +~~START~~ +nvarchar +£ +~~END~~ + + +-- both are available in tsql dialect +select CAST('£' AS nchar(2)); +GO +~~START~~ +nchar +£ +~~END~~ + +select CAST('£' AS nvarchar(2)); +GO +~~START~~ +nvarchar +£ +~~END~~ + + +-- multi-byte character doesn't fit in nchar(1) in tsql if it +-- would require a UTF16-surrogate-pair on output +select CAST('£' AS char(1)); -- allowed +GO +~~START~~ +char +£ +~~END~~ + +select CAST('£' AS sys.nchar(1)); -- allowed +GO +~~START~~ +nchar +£ +~~END~~ + +select CAST('£' AS sys.nvarchar(1)); -- allowed +GO +~~START~~ +nvarchar +£ +~~END~~ + +select CAST('£' AS sys.varchar(1)); -- allowed +GO +~~START~~ +varchar +£ +~~END~~ + + +select CAST('😀' AS char(1)); -- not allowed TODO: fix BABEL-3543 +GO +~~START~~ +char +? +~~END~~ + +select CAST('😀' AS sys.varchar(1)); -- not allowed TODO: fix BABEL-3543 +GO +~~START~~ +varchar +? +~~END~~ + + +-- Check that things work the same in postgres dialect +select CAST('£' AS char(1)); +GO +~~START~~ +char +£ +~~END~~ + +select CAST('£' AS sys.nchar(1)); +GO +~~START~~ +nchar +£ +~~END~~ + +select CAST('£' AS sys.nvarchar(1)); +GO +~~START~~ +nvarchar +£ +~~END~~ + +select CAST('£' AS sys.varchar(1)); +GO +~~START~~ +varchar +£ +~~END~~ + +select CAST('😀' AS char(1)); +GO +~~START~~ +char +? +~~END~~ + + + +-- test normal create domain works when apg_enable_domain_typmod is enabled +-- set apg_enable_domain_typmod true; +create TYPE varchar3 FROM varchar(3); +select CAST('ab£' AS varchar3); +GO +~~START~~ +varchar +ab£ +~~END~~ + +select CAST('ab😀' AS varchar3); --not allowed TODO: fix BABEL-3543 +GO +~~START~~ +varchar +ab? +~~END~~ + + +-- don't allow surrogate pairs to exceed max length +select CAST('😀b' AS char(1)); -- not allowed TODO: fix BABEL-3543 +GO +~~START~~ +char +? +~~END~~ + +select CAST('😀b' AS sys.varchar(1)); -- not allowed TODO: fix BABEL-3543 +GO +~~START~~ +varchar +? +~~END~~ + + +-- default length of nchar/char is 1 in tsql (and pg) +create table testing_1(col nchar); +GO + +SELECT * FROM information_schema.columns WHERE table_name = 'testing_1' +GO +~~START~~ +nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#int#!#nvarchar#!#varchar#!#nvarchar#!#int#!#int#!#tinyint#!#smallint#!#int#!#smallint#!#nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#nvarchar +master#!#dbo#!#testing_1#!#col#!#1#!##!#YES#!#nchar#!#1#!#2#!##!##!##!##!##!##!##!##!##!#bbf_unicode_cp1_ci_as#!##!##!# +~~END~~ + + +-- default length of varchar in tsql is 1 +create table testing_4(col sys.varchar); +insert into testing_4 (col) select '😀'; -- not allowed TODO: fix BABEL-3543 +GO +~~ROW COUNT: 1~~ + + +select * from testing_4; +GO +~~START~~ +varchar +? +~~END~~ + + + +drop table testing_1; +GO +drop table testing_4; +GO diff --git a/test/JDBC/expected/babel_function.out b/test/JDBC/expected/babel_function.out new file mode 100644 index 0000000000..c58c0a80e5 --- /dev/null +++ b/test/JDBC/expected/babel_function.out @@ -0,0 +1,2861 @@ +CREATE FUNCTION test_func() +RETURNS INT +AS +BEGIN + DECLARE @a int = 1; + RETURN @a; +END; +GO + +-- should be able execute a pltsql function in postgres dialect +select test_func(); +GO +~~START~~ +int +1 +~~END~~ + + + +-- test executing pltsql trigger in postgres dialect +CREATE TABLE employees( + id SERIAL PRIMARY KEY, + first_name VARCHAR(40) NOT NULL, + last_name VARCHAR(40) NOT NULL +); +GO + +CREATE TABLE employee_audits ( + id SERIAL PRIMARY KEY, + employee_id INT NOT NULL, + last_name VARCHAR(40) NOT NULL +); +GO + + +INSERT INTO employees (first_name, last_name) VALUES ('A', 'B'); +INSERT INTO employees (first_name, last_name) VALUES ('C', 'D'); +SELECT * FROM employees; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar#!#varchar +1#!#A#!#B +2#!#C#!#D +~~END~~ + + +UPDATE employees SET last_name = 'E' WHERE ID = 2; +GO +~~ROW COUNT: 1~~ + + +SELECT * FROM employees; +GO +~~START~~ +int#!#varchar#!#varchar +1#!#A#!#B +2#!#C#!#E +~~END~~ + +SELECT * FROM employee_audits; +GO +~~START~~ +int#!#int#!#varchar +~~END~~ + + +-- cleanup +drop function test_func; +GO +drop table employees; +GO +drop table employee_audits; +GO + + + +select OBJECT_NAME(1); +GO +~~START~~ +varchar + +~~END~~ + + + +-- test CONVERT function +-- Conversion between varchar and date/time/datetime +select CONVERT(varchar(30), CAST('2017-08-25' AS date), 102); +GO +~~START~~ +varchar +2017.08.25 +~~END~~ + +select CONVERT(varchar(30), CAST('13:01:59' AS time), 8); +GO +~~START~~ +varchar +13:01:59 +~~END~~ + +select CONVERT(varchar(30), CAST('13:01:59' AS time), 22); +GO +~~START~~ +varchar + 1:01:59 PM +~~END~~ + +select CONVERT(varchar(30), CAST('13:01:59' AS time), 22); +GO +~~START~~ +varchar + 1:01:59 PM +~~END~~ + +select CONVERT(varchar(30), CAST('2017-08-25 13:01:59' AS datetime), 100); +GO +~~START~~ +varchar +Aug 25 2017 1:01PM +~~END~~ + +select CONVERT(varchar(30), CAST('2017-08-25 13:01:59' AS datetime), 109); +GO +~~START~~ +varchar +Aug 25 2017 1:01:59:000PM +~~END~~ + +select CONVERT(date, '08/25/2017', 101); +GO +~~START~~ +date +2017-08-25 +~~END~~ + +select CONVERT(time, '12:01:59', 101); +GO +~~START~~ +time +12:01:59.0000000 +~~END~~ + +select CONVERT(datetime, '2017-08-25 01:01:59PM', 120); +GO +~~START~~ +datetime +2017-08-25 13:01:59.0 +~~END~~ + +select CONVERT(varchar, CONVERT(datetime2(7), '9999-12-31 23:59:59.9999999')); +GO +~~START~~ +varchar +9999-12-31 23:59:59.999999 +~~END~~ + + +-- Conversion from float to varchar +select CONVERT(varchar(30), CAST(11234561231231.234 AS float), 1); +GO +~~START~~ +varchar + 1.1234561e+13 +~~END~~ + +select CONVERT(varchar(30), CAST(11234561231231.234 AS float), 2); +GO +~~START~~ +varchar + 1.123456123123123e+13 +~~END~~ + +select CONVERT(varchar(30), CAST(11234561231231.234 AS float), 3); +GO +~~START~~ +varchar + 1.1234561231231234e+13 +~~END~~ + + +-- Conversion from money to varchar +select CONVERT(varchar(10), CAST(4936.56 AS MONEY), 0); +GO +~~START~~ +varchar + 4936.56 +~~END~~ + +select CONVERT(varchar(10), CAST(4936.56 AS MONEY), 1); +GO +~~START~~ +varchar +4,936.56 +~~END~~ + +select CONVERT(varchar(10), CAST(4936.56 AS MONEY), 2); +GO +~~START~~ +varchar + 4936.5600 +~~END~~ + + +select CONVERT(varchar(10), CAST(-4936.56 AS MONEY), 0); +-- Floor conversion to smallint, int, bigint +SELECT CONVERT(int, 99.9); +GO +~~START~~ +varchar +-4936.56 +~~END~~ + +~~START~~ +int +99 +~~END~~ + +SELECT CONVERT(smallint, 99.9); +GO +~~START~~ +smallint +99 +~~END~~ + +SELECT CONVERT(bigint, 99.9); +GO +~~START~~ +bigint +99 +~~END~~ + +SELECT CONVERT(int, -99.9); +GO +~~START~~ +int +-99 +~~END~~ + +SELECT CONVERT(int, '99'); +GO +~~START~~ +int +99 +~~END~~ + +SELECT CONVERT(int, CAST(99.9 AS double precision)); +GO +~~START~~ +int +99 +~~END~~ + +SELECT CONVERT(int, CAST(99.9 AS real)); +GO +~~START~~ +int +99 +~~END~~ + + +-- test TRY_CONVERT function +-- Conversion between different types and varchar +select TRY_CONVERT(varchar(30), CAST('2017-08-25' AS date), 102); +GO +~~START~~ +varchar +2017.08.25 +~~END~~ + +select TRY_CONVERT(varchar(30), CAST('13:01:59' AS time), 8); +GO +~~START~~ +varchar +13:01:59 +~~END~~ + +select TRY_CONVERT(varchar(30), CAST('13:01:59' AS time), 22); +GO +~~START~~ +varchar + 1:01:59 PM +~~END~~ + +select TRY_CONVERT(varchar(30), CAST('2017-08-25 13:01:59' AS datetime), 109); +GO +~~START~~ +varchar +Aug 25 2017 1:01:59:000PM +~~END~~ + +select TRY_CONVERT(varchar(30), CAST('11234561231231.234' AS float), 0); +GO +~~START~~ +varchar + +~~END~~ + +select TRY_CONVERT(varchar(30), CAST('11234561231231.234'AS float), 1); +GO +~~START~~ +varchar + 1.1234561e+13 +~~END~~ + +select TRY_CONVERT(varchar(10), CAST(4936.56 AS MONEY), 0); +GO +~~START~~ +varchar + 4936.56 +~~END~~ + + +-- Wrong conversions that return NULL +select TRY_CONVERT(date, 123); +GO +~~START~~ +date + +~~END~~ + +select TRY_CONVERT(time, 123); +GO +~~START~~ +time + +~~END~~ + +select TRY_CONVERT(datetime, 123); +GO +~~START~~ +datetime + +~~END~~ + +select TRY_CONVERT(money, 'asdf'); +GO +~~START~~ +money + +~~END~~ + + +-- test TRY_PARSE function +-- Expect null return on error +-- Conversion from string to date/time/datetime +select TRY_PARSE('2017-08-25' AS date); +GO +~~START~~ +date +2017-08-25 +~~END~~ + + +select TRY_PARSE('2017-08-25 13:01:59' AS datetime); +GO +~~START~~ +datetime +2017-08-25 13:01:59.0 +~~END~~ + + +-- Wrong conversions that return NULL +select TRY_PARSE('asdf' AS numeric(3,2)); +GO +~~START~~ +numeric + +~~END~~ + +select TRY_PARSE('123' AS datetime2); +GO +~~START~~ +datetime2 + +~~END~~ + +select TRY_PARSE('asdf' AS MONEY); +GO +~~START~~ +money + +~~END~~ + + +-- test serverproperty() function +-- invalid property name, should reutnr NULL +select serverproperty(N'invalid property'); +GO +~~START~~ +sql_variant + +~~END~~ + +-- valid supported properties +select serverproperty(N'collation'); +GO +~~START~~ +sql_variant +sql_latin1_general_cp1_ci_as +~~END~~ + +select serverproperty(N'IsSingleUser'); +GO +~~START~~ +sql_variant +0 +~~END~~ + + +-- test ISDATE function +-- test valid argument +SELECT ISDATE('12/26/2016'); +GO +~~START~~ +int +1 +~~END~~ + +SELECT ISDATE('12-26-2016'); +GO +~~START~~ +int +1 +~~END~~ + +SELECT ISDATE('12.26.2016'); +GO +~~START~~ +int +1 +~~END~~ + +SELECT ISDATE('2016-12-26 23:30:05.523456'); +GO +~~START~~ +int +1 +~~END~~ + +-- test invalid argument +SELECT ISDATE('02/30/2016'); +GO +~~START~~ +int +0 +~~END~~ + +SELECT ISDATE('12/32/2016'); +GO +~~START~~ +int +0 +~~END~~ + +SELECT ISDATE('1995-10-1a'); +GO +~~START~~ +int +0 +~~END~~ + +SELECT ISDATE(NULL); +GO +~~START~~ +int +0 +~~END~~ + + +-- test DATEFROMPARTS function +-- test valid arguments +select datefromparts(2020,12,31); +GO +~~START~~ +date +2020-12-31 +~~END~~ + +-- test invalid arguments, should fail +select datefromparts(2020, 2, 30); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: date field value out of range: 2020-02-30)~~ + +select datefromparts(2020, 13, 1); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: date field value out of range: 2020-13-01)~~ + +select datefromparts(-4, 3, 150); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: date field value out of range: -3-03-150)~~ + +select datefromparts(10, 55, 10.1); +GO +~~START~~ +date +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: date field value out of range: 10-55-10)~~ + +select datefromparts('2020', 55, 100.1); +GO +~~START~~ +date +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: date field value out of range: 2020-55-100)~~ + + +-- test DATETIMEFROMPARTS function +-- test valid arguments +select datetimefromparts(2016, 12, 26, 23, 30, 5, 32); +GO +~~START~~ +datetime +2016-12-26 23:30:05.033 +~~END~~ + +select datetimefromparts(2016.0, 12, 26, 23, 30, 5, 32); +GO +~~START~~ +datetime +2016-12-26 23:30:05.033 +~~END~~ + +select datetimefromparts(2016.1, 12, 26, 23, 30, 5, 32); +GO +~~START~~ +datetime +2016-12-26 23:30:05.033 +~~END~~ + +select datetimefromparts(2016, 12, 26.99, 23, 30, 5, 32); +GO +~~START~~ +datetime +2016-12-26 23:30:05.033 +~~END~~ + +select datetimefromparts(2016, 12.90, 26, 23, 30, 5, 32); +GO +~~START~~ +datetime +2016-12-26 23:30:05.033 +~~END~~ + +-- test invalid arguments +select datetimefromparts(2016, 2, 30, 23, 30, 5, 32); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: date field value out of range: 2016-02-30)~~ + +select datetimefromparts(2016, 12, 26, 23, 30, 5); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The datetimefromparts function requires 7 arguments)~~ + +select datetimefromparts(2016, 12, 26, 23, 30, 5, NULL); +GO +~~START~~ +datetime + +~~END~~ + + +-- test DATEPART function +-- test all valid datepart arguments +SELECT DATEPART(YEAR, CAST('2016-12-26 23:30:05.523456 -08:00' AS DATETIMEOFFSET)); +GO +~~START~~ +int +2016 +~~END~~ + +select datepart(yyyy, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +2016 +~~END~~ + +select datepart(yy, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +2016 +~~END~~ + +select datepart(quarter, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +4 +~~END~~ + +select datepart(qq, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +4 +~~END~~ + +select datepart(qq, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +4 +~~END~~ + +select datepart(q, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +4 +~~END~~ + +select datepart(month, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +12 +~~END~~ + +select datepart(mm, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +12 +~~END~~ + +select datepart(m, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +12 +~~END~~ + +select datepart(dayofyear, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +361 +~~END~~ + +select datepart(dy, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +361 +~~END~~ + +select datepart(day, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +26 +~~END~~ + +select datepart(dd, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +26 +~~END~~ + +select datepart(d,CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +26 +~~END~~ + +select datepart(week, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +53 +~~END~~ + +select datepart(wk, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +53 +~~END~~ + +select datepart(ww, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +53 +~~END~~ + +select datepart(weekday, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +2 +~~END~~ + +select datepart(dw, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +2 +~~END~~ + +select datepart(hour, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +15 +~~END~~ + +select datepart(hh, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +15 +~~END~~ + +select datepart(minute, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +30 +~~END~~ + +select datepart(n, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +30 +~~END~~ + +select datepart(second, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +5 +~~END~~ + +select datepart(ss, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +5 +~~END~~ + +select datepart(s, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +5 +~~END~~ + +select datepart(millisecond, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +456 +~~END~~ + +select datepart(ms, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +456 +~~END~~ + +select datepart(microsecond, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +523456 +~~END~~ + +select datepart(mcs,CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +523456 +~~END~~ + +select datepart(nanosecond, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +523456000 +~~END~~ + +select datepart(ns, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +523456000 +~~END~~ + +select datepart(tzoffset, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +480 +~~END~~ + +select datepart(tz, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +480 +~~END~~ + +select datepart(iso_week, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +52 +~~END~~ + +select datepart(isowk, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +52 +~~END~~ + +select datepart(isoww, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +52 +~~END~~ + +-- test different types of date/time arguments +select datepart(month, CAST('2016-12-26 23:30:05.523'AS sys.datetime)); +GO +~~START~~ +int +12 +~~END~~ + +select datepart(quarter, CAST('2016-12-26 23:30:05.523456'AS datetime2)); +GO +~~START~~ +int +4 +~~END~~ + +select datepart(hour, CAST('2016-12-26 23:30:05'AS smalldatetime)); +GO +~~START~~ +int +23 +~~END~~ + +select datepart(dayofyear,CAST('2016-12-26'AS date)); +GO +~~START~~ +int +361 +~~END~~ + +select datepart(second,CAST ('04:12:34.876543'AS time)); +GO +~~START~~ +int +34 +~~END~~ + +-- test edge cases: try to get datepart that does not exist in the argument +select datepart(year, cast('12:10:30.123' as time)); +GO +~~START~~ +int +1900 +~~END~~ + +select datepart(yyyy, cast('12:10:30.123' as time)); +GO +~~START~~ +int +1900 +~~END~~ + +select datepart(yy, cast('12:10:30.123' as time)); +GO +~~START~~ +int +1900 +~~END~~ + +select datepart(quarter, cast('12:10:30.123' as time)); +GO +~~START~~ +int +1 +~~END~~ + +select datepart(qq, cast('12:10:30.123' as time)); +GO +~~START~~ +int +1 +~~END~~ + +select datepart(q, cast('12:10:30.123' as time)); +GO +~~START~~ +int +1 +~~END~~ + +select datepart(month, cast('12:10:30.123' as time)); +GO +~~START~~ +int +1 +~~END~~ + +select datepart(mm, cast('12:10:30.123' as time)); +GO +~~START~~ +int +1 +~~END~~ + +select datepart(m, cast('12:10:30.123' as time)); +GO +~~START~~ +int +1 +~~END~~ + +select datepart(dayofyear, cast('12:10:30.123' as time)); +GO +~~START~~ +int +1 +~~END~~ + +select datepart(dy, cast('12:10:30.123' as time)); +GO +~~START~~ +int +1 +~~END~~ + +select datepart(y, cast('12:10:30.123' as time)); +GO +~~START~~ +int +1 +~~END~~ + +select datepart(day, cast('12:10:30.123' as time)); +GO +~~START~~ +int +1 +~~END~~ + +select datepart(dd, cast('12:10:30.123' as time)); +GO +~~START~~ +int +1 +~~END~~ + +select datepart(d, cast('12:10:30.123' as time)); +GO +~~START~~ +int +1 +~~END~~ + +select datepart(week, cast('12:10:30.123' as time)); +GO +~~START~~ +int +1 +~~END~~ + +select datepart(wk, cast('12:10:30.123' as time)); +GO +~~START~~ +int +1 +~~END~~ + +select datepart(ww, cast('12:10:30.123' as time)); +GO +~~START~~ +int +1 +~~END~~ + +select datepart(weekday, cast('12:10:30.123' as time)); +GO +~~START~~ +int +2 +~~END~~ + +select datepart(dw, cast('12:10:30.123' as time)); +GO +~~START~~ +int +2 +~~END~~ + +select datepart(tzoffset, cast('12:10:30.123' as time)); +GO +~~START~~ +int +0 +~~END~~ + +select datepart(tz, cast('12:10:30.123' as time)); +GO +~~START~~ +int +0 +~~END~~ + +select datepart(iso_week, cast('12:10:30.123' as time)); +GO +~~START~~ +int +1 +~~END~~ + +select datepart(isowk, cast('12:10:30.123' as time)); +GO +~~START~~ +int +1 +~~END~~ + +select datepart(isoww, cast('12:10:30.123' as time)); +GO +~~START~~ +int +1 +~~END~~ + +select datepart(hour, cast('2016-12-26' as date)); +GO +~~START~~ +int +0 +~~END~~ + +select datepart(hh, cast('2016-12-26' as date)); +GO +~~START~~ +int +0 +~~END~~ + +select datepart(minute, cast('2016-12-26' as date)); +GO +~~START~~ +int +0 +~~END~~ + +select datepart(n, cast('2016-12-26' as date)); +GO +~~START~~ +int +0 +~~END~~ + +select datepart(second, cast('2016-12-26' as date)); +GO +~~START~~ +int +0 +~~END~~ + +select datepart(ss, cast('2016-12-26' as date)); +GO +~~START~~ +int +0 +~~END~~ + +select datepart(s, cast('2016-12-26' as date)); +GO +~~START~~ +int +0 +~~END~~ + +select datepart(millisecond, cast('2016-12-26' as date)); +GO +~~START~~ +int +0 +~~END~~ + +select datepart(ms, cast('2016-12-26' as date)); +GO +~~START~~ +int +0 +~~END~~ + +select datepart(microsecond, cast('2016-12-26' as date)); +GO +~~START~~ +int +0 +~~END~~ + +select datepart(mcs, cast('2016-12-26' as date)); +GO +~~START~~ +int +0 +~~END~~ + +select datepart(nanosecond, cast('2016-12-26' as date)); +GO +~~START~~ +int +0 +~~END~~ + +select datepart(ns, cast('2016-12-26' as date)); +GO +~~START~~ +int +0 +~~END~~ + +-- test invalid interval, expect error +select datepart(invalid_interval, cast('2016-12-26 23:30:05.523456' as date)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'invalid_interval' is not a recognized datepart option)~~ + +select datepart(invalidinterval, cast('12:10:30.123' as time)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'invalidinterval' is not a recognized datepart option)~~ + + +-- test DATENAME function +SELECT DATENAME(year, CAST('2016-12-26 23:30:05.523456+8' AS datetimeoffset)); +GO +~~START~~ +text +2016 +~~END~~ + +select datename(dd, CAST('2016-12-26 23:30:05.523456+8' AS datetimeoffset)); +GO +~~START~~ +text +26 +~~END~~ + +select datename(weekday, CAST('2016-12-26 23:30:05.523456+8' AS datetimeoffset)); +GO +~~START~~ +text +Monday +~~END~~ + +select datename(dw, CAST('2016-12-26 23:30:05.523456+8' AS datetimeoffset)); +GO +~~START~~ +text +Monday +~~END~~ + +select datename(month, CAST('2016-12-26 23:30:05.523456+8' AS datetimeoffset)); +GO +~~START~~ +text +December +~~END~~ + +select datename(mm, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +text +December +~~END~~ + +select datename(m, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +text +December +~~END~~ + +select datename(isowk, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +text +52 +~~END~~ + +-- test invalid argument, expect error +select datename(invalid_interval, cast('2016-12-26 23:30:05.523456' as date)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'invalid_interval' is not a recognized datepart option)~~ + + +-- test DATEFIRST option, together DATEPART function +-- This shows the return value for the week and weekday datepart for '2007-04-21' for each SET DATEFIRST argument. +-- January 1, 2007 falls on a Monday. April 21, 2007 falls on a Saturday. +-- DATEFIRST week weekday +-- 1 16 6 +-- 2 17 5 +-- 3 17 4 +-- 4 17 3 +-- 5 17 2 +-- 6 17 1 +-- 7 16 7 +select @@datefirst; +GO +~~START~~ +int +7 +~~END~~ + +set datefirst 1; +select datepart(week, CAST('2007-04-21'AS date)), datepart(weekday, CAST('2007-04-21'AS date)); +GO +~~START~~ +int#!#int +16#!#6 +~~END~~ + + +set datefirst 2; +select datepart(week, CAST('2007-04-21'AS date)), datepart(weekday, CAST('2007-04-21'AS date)); +GO +~~START~~ +int#!#int +17#!#5 +~~END~~ + +set datefirst 3; +select datepart(week, CAST('2007-04-21'AS date)), datepart(weekday, CAST('2007-04-21'AS date)); +GO +~~START~~ +int#!#int +17#!#4 +~~END~~ + +set datefirst 4; +select datepart(week, CAST('2007-04-21'AS date)), datepart(weekday, CAST('2007-04-21'AS date)); +GO +~~START~~ +int#!#int +17#!#3 +~~END~~ + +set datefirst 5; +select datepart(week, CAST('2007-04-21'AS date)), datepart(weekday, CAST('2007-04-21'AS date)); +GO +~~START~~ +int#!#int +17#!#2 +~~END~~ + +set datefirst 6; +select datepart(week, CAST('2007-04-21'AS date)), datepart(weekday, CAST('2007-04-21'AS date)); +GO +~~START~~ +int#!#int +17#!#1 +~~END~~ + +set datefirst 7; +select datepart(week, CAST('2007-04-21'AS date)), datepart(weekday, CAST('2007-04-21'AS date)); +GO +~~START~~ +int#!#int +16#!#7 +~~END~~ + +-- test edge case: date within the week of Jan. 1st +select datepart(week, CAST('2007-01-01'AS date)), datepart(weekday, CAST('2007-01-01'AS date)); +GO +~~START~~ +int#!#int +1#!#2 +~~END~~ + +select datepart(week, CAST('2007-01-02'AS date)), datepart(weekday, CAST('2007-01-02'AS date)); +GO +~~START~~ +int#!#int +1#!#3 +~~END~~ + +select datepart(week, CAST('2007-01-03'AS date)), datepart(weekday, CAST('2007-01-03'AS date)); +GO +~~START~~ +int#!#int +1#!#4 +~~END~~ + +select datepart(week, CAST('2007-01-04'AS date)), datepart(weekday, CAST('2007-01-04'AS date)); +GO +~~START~~ +int#!#int +1#!#5 +~~END~~ + +select datepart(week, CAST('2007-01-05'AS date)), datepart(weekday, CAST('2007-01-05'AS date)); +GO +~~START~~ +int#!#int +1#!#6 +~~END~~ + +select datepart(week, CAST('2007-01-06'AS date)), datepart(weekday, CAST('2007-01-06'AS date)); +GO +~~START~~ +int#!#int +1#!#7 +~~END~~ + +-- test edge case: date just outside the week of Jan. 1st +select datepart(week, CAST('2007-01-07'AS date)), datepart(weekday, CAST('2007-01-07'AS date)); +GO +~~START~~ +int#!#int +2#!#1 +~~END~~ + + +-- test DATEDIFF function +select datediff(year, CAST('2037-03-01 23:30:05.523'AS sys.datetime), CAST('2036-02-28 23:30:05.523'AS sys.datetime)); +GO +~~START~~ +int +-1 +~~END~~ + +select datediff(quarter, CAST('2037-03-01 23:30:05.523'AS sys.datetime), CAST('2036-02-28 23:30:05.523'AS sys.datetime)); +GO +~~START~~ +int +-4 +~~END~~ + +select datediff(month, CAST('2037-03-01 23:30:05.523'AS sys.datetime), CAST('2036-02-28 23:30:05.523'AS sys.datetime)); +GO +~~START~~ +int +-13 +~~END~~ + +select datediff(dayofyear, CAST('2037-03-01 23:30:05.523'AS sys.datetime), CAST('2036-02-28 23:30:05.523'AS sys.datetime)); +GO +~~START~~ +int +-367 +~~END~~ + +select datediff(day, CAST('2037-03-01 23:30:05.523'AS sys.datetime), CAST('2036-02-28 23:30:05.523'AS sys.datetime)); +GO +~~START~~ +int +-367 +~~END~~ + +select datediff(week,CAST('2037-03-01 23:30:05.523'AS sys.datetime),CAST('2036-02-28 23:30:05.523'AS sys.datetime)); +GO +~~START~~ +int +-52 +~~END~~ + +select datediff(hour, CAST('2037-03-01 23:30:05.523'AS sys.datetime), CAST('2036-02-28 23:30:05.523'AS sys.datetime)); +GO +~~START~~ +int +-8808 +~~END~~ + +select datediff(minute,CAST('2037-03-01 23:30:05.523'AS sys.datetime), CAST('2036-02-28 23:30:05.523'AS sys.datetime)); +GO +~~START~~ +int +-528480 +~~END~~ + +select datediff(second, CAST('2037-03-01 23:30:05.523'AS sys.datetime), CAST('2036-02-28 23:30:05.523'AS sys.datetime)); +GO +~~START~~ +int +-31708800 +~~END~~ + +select datediff(millisecond, CAST('2036-02-28 01:23:45.234'AS sys.datetime), CAST('2036-02-28 01:23:45.123'AS sys.datetime)); +GO +~~START~~ +int +-111 +~~END~~ + +select datediff(microsecond, CAST('2036-02-28 01:23:45.234'AS sys.datetime), CAST('2036-02-28 01:23:45.123'AS sys.datetime)); +GO +~~START~~ +int +-111000 +~~END~~ + +select datediff(nanosecond, CAST('2036-02-28 01:23:45.234'AS sys.datetime), CAST('2036-02-28 01:23:45.123'AS sys.datetime)); +GO +~~START~~ +int +-111000000 +~~END~~ + +-- test different types of date/time arguments +select datediff(minute, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset), CAST('2016-12-31 23:30:05.523456+8'AS datetimeoffset)); +GO +~~START~~ +int +7200 +~~END~~ + +select datediff(quarter,CAST('2016-12-26 23:30:05.523456'AS datetime2), CAST('2018-08-31 23:30:05.523456'AS datetime2)); +GO +~~START~~ +int +6 +~~END~~ + +select datediff(hour, CAST('2016-12-26 23:30:05'AS smalldatetime), CAST('2016-12-28 21:29:05'AS smalldatetime)); +GO +~~START~~ +int +46 +~~END~~ + +select datediff(year, CAST('2037-03-01'AS date), CAST('2036-02-28'AS date)); +GO +~~START~~ +int +-1 +~~END~~ + + +-- test DATEADD function +select dateadd(year, 2, '20060830'); +GO +~~START~~ +datetime +2008-08-30 00:00:00.0 +~~END~~ + +select dateadd(quarter, 2, '20060830'); +GO +~~START~~ +datetime +2007-02-28 00:00:00.0 +~~END~~ + +select dateadd(month, 1, '20060831'); +GO +~~START~~ +datetime +2006-09-30 00:00:00.0 +~~END~~ + +select dateadd(dayofyear, 2, '20060830'); +GO +~~START~~ +datetime +2006-09-01 00:00:00.0 +~~END~~ + +select dateadd(day, 2, '20060830'); +GO +~~START~~ +datetime +2006-09-01 00:00:00.0 +~~END~~ + +select dateadd(week, 2, '20060830'); +GO +~~START~~ +datetime +2006-09-13 00:00:00.0 +~~END~~ + +select dateadd(weekday, 2, '20060830'); +GO +~~START~~ +datetime +2006-09-01 00:00:00.0 +~~END~~ + +select dateadd(hour, 2, '20060830'); +GO +~~START~~ +datetime +2006-08-30 02:00:00.0 +~~END~~ + +select dateadd(minute, 2, '20060830'); +GO +~~START~~ +datetime +2006-08-30 00:02:00.0 +~~END~~ + +select dateadd(second, 2, '20060830'); +GO +~~START~~ +datetime +2006-08-30 00:00:02.0 +~~END~~ + +select dateadd(millisecond, 123, '20060830'); +GO +~~START~~ +datetime +2006-08-30 00:00:00.12 +~~END~~ + +-- test different types of date/time arguments +select dateadd(quarter, 3, '2037-03-01'); +GO +~~START~~ +datetime +2037-12-01 00:00:00.0 +~~END~~ + +select dateadd(second, 56, '2016-12-26 23:30:05'); +GO +~~START~~ +datetime +2016-12-26 23:31:01.0 +~~END~~ + +-- test negative argument +select dateadd(year, -2, CAST('20060830'AS datetime)); +GO +~~START~~ +datetime +2004-08-30 00:00:00.0 +~~END~~ + +select dateadd(month, -20, CAST('2016-12-26 23:30:05.523456' AS datetime2)); +GO +~~START~~ +datetime2 +2015-04-26 23:30:05.5234560 +~~END~~ + +select dateadd(hour, -2, CAST('01:12:34.876543' AS time)); +GO +~~START~~ +time +23:12:34.8765430 +~~END~~ + +select dateadd(minute, -70, CAST('2016-12-26 00:30:05.523456+8' AS datetimeoffset)); +GO +~~START~~ +datetimeoffset +2016-12-25 23:20:05.5234560 +08:00 +~~END~~ + + +-- test using variables, instead of constants, for the second parameter +create table dateadd_table(a int, b datetime); +GO +insert into dateadd_table values(1, CAST('2020-10-29' AS datetime)); +select * from dateadd_table; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#datetime +1#!#2020-10-29 00:00:00.0 +~~END~~ + +update dateadd_table set b = dateadd(dd, a, CAST('2020-10-30' AS datetime)); +GO +~~ROW COUNT: 1~~ + +select * from dateadd_table; +GO +~~START~~ +int#!#datetime +1#!#2020-10-31 00:00:00.0 +~~END~~ + +select * from dateadd_table; +GO +~~START~~ +int#!#datetime +1#!#2020-10-31 00:00:00.0 +~~END~~ + + +-- test CHARINDEX function +select CHARINDEX('hello', 'hello world'); +GO +~~START~~ +int +1 +~~END~~ + +select CHARINDEX('hello ', 'hello world'); +GO +~~START~~ +int +0 +~~END~~ + +select CHARINDEX('hello world', 'hello'); +GO +~~START~~ +int +0 +~~END~~ + +-- test NULL input +select CHARINDEX(NULL, NULL); +GO +~~START~~ +int + +~~END~~ + +select CHARINDEX(NULL, 'string'); +GO +~~START~~ +int + +~~END~~ + +select CHARINDEX('pattern', NULL); +GO +~~START~~ +int + +~~END~~ + +select CHARINDEX('pattern', 'string', NULL); +GO +~~START~~ +int + +~~END~~ + +-- test start_location parameter +select CHARINDEX('hello', 'hello world', -1); +GO +~~START~~ +int +1 +~~END~~ + +select CHARINDEX('hello', 'hello world', 0); +GO +~~START~~ +int +1 +~~END~~ + +select CHARINDEX('hello', 'hello world', 1); +GO +~~START~~ +int +1 +~~END~~ + +select CHARINDEX('hello', 'hello world', 2); +GO +~~START~~ +int +0 +~~END~~ + +select CHARINDEX('world', 'hello world', 6); +GO +~~START~~ +int +7 +~~END~~ + +select CHARINDEX('world', 'hello world', 7); +GO +~~START~~ +int +7 +~~END~~ + +select CHARINDEX('world', 'hello world', 8); +GO +~~START~~ +int +0 +~~END~~ + +select CHARINDEX('is', 'This is a string'); +GO +~~START~~ +int +3 +~~END~~ + +select CHARINDEX('is', 'This is a string', 4); +GO +~~START~~ +int +6 +~~END~~ + + +-- test STUFF function +select STUFF(N'abcdef', 2, 3, N'ijklmn'); +GO +~~START~~ +nvarchar +aijklmnef +~~END~~ + +select STUFF(N' abcdef', 2, 3, N'ijklmn '); +GO +~~START~~ +nvarchar + ijklmn def +~~END~~ + +select STUFF(N'abcdef', 2, 3, N' ijklmn '); +GO +~~START~~ +nvarchar +a ijklmn ef +~~END~~ + +select STUFF(N'abcdef', 2, 3, N'ijklmn '); +GO +~~START~~ +nvarchar +aijklmn ef +~~END~~ + +-- test corner cases +-- when start is negative or zero or longer than expr, return NULL +select STUFF(N'abcdef', -1, 3, N'ijklmn'); +GO +~~START~~ +nvarchar + +~~END~~ + +select STUFF(N'abcdef', 0, 3, N'ijklmn'); +GO +~~START~~ +nvarchar + +~~END~~ + +select STUFF(N'abcdef', 7, 3, N'ijklmn'); +GO +~~START~~ +nvarchar + +~~END~~ + +-- when length is negative, return NULL +select STUFF(N'abcdef', 2, -3, N'ijklmn'); +GO +~~START~~ +nvarchar + +~~END~~ + +-- when length is zero, just insert without deleting +select STUFF(N'abcdef', 2, 0, N'ijklmn'); +GO +~~START~~ +nvarchar +aijklmnbcdef +~~END~~ + +-- when length is longer than expr, delete up to the last character in expr +select STUFF(N'abcdef', 2, 7, N'ijklmn'); +GO +~~START~~ +nvarchar +aijklmn +~~END~~ + +-- when replace_expr is NULL, just delete without inserting +select STUFF(N'abcdef', 2, 3, NULL); +GO +~~START~~ +text +aef +~~END~~ + +-- when argument are type unknown +select STUFF('abcdef', 2, 3, 'ijklmn'); +GO +~~START~~ +text +aijklmnef +~~END~~ + +select STUFF('abcdef', 2, 3, N'ijklmn'); +GO +~~START~~ +text +aijklmnef +~~END~~ + +select STUFF(N'abcdef', 2, 3, 'ijklmn'); +GO +~~START~~ +text +aijklmnef +~~END~~ + +-- when argument are type text +SELECT STUFF(CAST('abcdef' as text), 2, 3, CAST('ijklmn' as text)); +GO +~~START~~ +text +aijklmnef +~~END~~ + +SELECT STUFF(CAST('abcdef' as text), 2, 3, 'ijklmn'); +GO +~~START~~ +text +aijklmnef +~~END~~ + +SELECT STUFF('abcdef', 2, 3, CAST('ijklmn' as text)); +GO +~~START~~ +text +aijklmnef +~~END~~ + +-- when argument are type sys.varchar +SELECT STUFF(CAST('abcdef' as sys.varchar), 2, 3, CAST('ijklmn' as sys.varchar)); +GO +~~START~~ +varchar +aijklmnef +~~END~~ + +SELECT STUFF('abcdef', 2, 3, CAST('ijklmn' as sys.varchar)); +GO +~~START~~ +text +aijklmnef +~~END~~ + +SELECT STUFF(CAST('abcdef' as sys.varchar), 2, 3, 'ijklmn'); +GO +~~START~~ +text +aijklmnef +~~END~~ + + +-- test ROUND function +-- test rounding to the left of decimal point +select ROUND(748.58, -1); +GO +~~START~~ +numeric +750 +~~END~~ + +select ROUND(748.58, -2); +GO +~~START~~ +numeric +700 +~~END~~ + +select ROUND(748.58, -3); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: value overflows for numeric format)~~ + +select ROUND(748.58, -4); +GO +~~START~~ +numeric +0 +~~END~~ + +select ROUND(-648.1234, -2); +GO +~~START~~ +numeric +-600 +~~END~~ + +select ROUND(-648.1234, -3); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: value overflows for numeric format)~~ + +select ROUND(-1548.1234, -3); +GO +~~START~~ +numeric +-2000 +~~END~~ + +select ROUND(-1548.1234, -4); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: value overflows for numeric format)~~ + +-- test NULL input +select ROUND(NULL, -3); +GO +~~START~~ +numeric + +~~END~~ + +select ROUND(748.58, NULL); +GO +~~START~~ +numeric + +~~END~~ + +-- test rounding +SELECT ROUND(123.9994, 3); +GO +~~START~~ +numeric +123.999 +~~END~~ + +SELECT ROUND(123.9995, 3); +GO +~~START~~ +numeric +124.000 +~~END~~ + +SELECT ROUND(123.4545, 2); +GO +~~START~~ +numeric +123.45 +~~END~~ + +SELECT ROUND(123.45, -2); +GO +~~START~~ +numeric +100 +~~END~~ + +-- test function parameter, i.e. truncation when not NULL or 0 +SELECT ROUND(150.75, 0); +GO +~~START~~ +numeric +151 +~~END~~ + +SELECT ROUND(150.75, 0, 0); +GO +~~START~~ +numeric +151 +~~END~~ + +SELECT ROUND(150.75, 0, NULL); +GO +~~START~~ +numeric +151 +~~END~~ + +SELECT ROUND(150.75, 0, 1); +GO +~~START~~ +numeric +150 +~~END~~ + +-- test negative numbers +SELECT ROUND(-150.49, 0); +GO +~~START~~ +numeric +-150 +~~END~~ + +SELECT ROUND(-150.75, 0); +GO +~~START~~ +numeric +-151 +~~END~~ + +SELECT ROUND(-150.49, 0, 1); +GO +~~START~~ +numeric +-150 +~~END~~ + +SELECT ROUND(-150.75, 0, 1); +GO +~~START~~ +numeric +-150 +~~END~~ + + +-- test SELECT ROUND(col, ) +create table t1 (col numeric(4,2)); +GO +insert into t1 values (64.24); +insert into t1 values (79.65); +insert into t1 values (NULL); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +select ROUND(col, 3) from t1; +GO +~~START~~ +numeric +64.24000000 +79.65000000 + +~~END~~ + +select ROUND(col, 2) from t1; +GO +~~START~~ +numeric +64.24000000 +79.65000000 + +~~END~~ + +select ROUND(col, 1) from t1; +GO +~~START~~ +numeric +64.20000000 +79.70000000 + +~~END~~ + +select ROUND(col, 0) from t1; +GO +~~START~~ +numeric +64.00000000 +80.00000000 + +~~END~~ + +select ROUND(col, -1) from t1; +GO +~~START~~ +numeric +60.00000000 +80.00000000 + +~~END~~ + +select ROUND(col, -2) from t1; +GO +~~START~~ +numeric +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: value overflows for numeric format)~~ + +select ROUND(col, -3) from t1; +GO +~~START~~ +numeric +0E-8 +0E-8 + +~~END~~ + +select ROUND(col, 1, 1) from t1; +GO +~~START~~ +numeric +64.20000000 +79.60000000 + +~~END~~ + +drop table t1; +GO + +-- test DAY function +select DAY(CAST('2016-12-26 23:30:05.523456+8' AS datetimeoffset)); +GO +~~START~~ +int +26 +~~END~~ + +select DAY(CAST('2016-12-26 23:30:05.523456' AS datetime2)); +GO +~~START~~ +int +26 +~~END~~ + +select DAY(CAST('2016-12-26 23:30:05' AS smalldatetime)); +GO +~~START~~ +int +26 +~~END~~ + +select DAY(CAST('04:12:34.876543' AS time)); +GO +~~START~~ +int +1 +~~END~~ + +select DAY(CAST('2037-03-01' AS date)); +GO +~~START~~ +int +1 +~~END~~ + +select DAY(CAST('2037-03-01 23:30:05.523' AS sys.datetime)); +GO +~~START~~ +int +1 +~~END~~ + +-- test MONTH function +SELECT MONTH(CAST('2016-12-26 23:30:05.523456-08:00' AS datetimeoffset)); +GO +~~START~~ +int +12 +~~END~~ + +select MONTH(CAST('2016-12-26 23:30:05.523456' AS datetime2)); +GO +~~START~~ +int +12 +~~END~~ + +select MONTH(CAST('2016-12-26 23:30:05'AS smalldatetime)); +GO +~~START~~ +int +12 +~~END~~ + +select MONTH(CAST('04:12:34.876543' AS time)); +GO +~~START~~ +int +1 +~~END~~ + +select MONTH(CAST('2037-03-01' AS date)); +GO +~~START~~ +int +3 +~~END~~ + +select MONTH(CAST('2037-03-01 23:30:05.523' AS sys.datetime)); +GO +~~START~~ +int +3 +~~END~~ + +-- test YEAR function +select YEAR(CAST('2016-12-26 23:30:05.523456+8' AS datetimeoffset)); +GO +~~START~~ +int +2016 +~~END~~ + +select YEAR(CAST('2016-12-26 23:30:05.523456' AS datetime2)); +GO +~~START~~ +int +2016 +~~END~~ + +select YEAR(CAST('2016-12-26 23:30:05' AS smalldatetime)); +GO +~~START~~ +int +2016 +~~END~~ + +select YEAR(CAST('04:12:34.876543' AS time)); +GO +~~START~~ +int +1900 +~~END~~ + +select YEAR(CAST('2037-03-01' AS date)); +GO +~~START~~ +int +2037 +~~END~~ + +select YEAR(CAST('2037-03-01 23:30:05.523' AS sys.datetime)); +GO +~~START~~ +int +2037 +~~END~~ + + +-- test SPACE function +select SPACE(NULL); +GO +~~START~~ +varchar + +~~END~~ + +select SPACE(2); +GO +~~START~~ +varchar + +~~END~~ + +select LEN(SPACE(5)); +GO +~~START~~ +int +0 +~~END~~ + +select DATALENGTH(SPACE(5)); +GO +~~START~~ +int +5 +~~END~~ + + +-- test COUNT and COUNT_BIG aggregate function +CREATE TABLE t2(a int, b int); +GO +INSERT INTO t2 VALUES(1, 100); +INSERT INTO t2 VALUES(2, 200); +INSERT INTO t2 VALUES(NULL, 300); +INSERT INTO t2 VALUES(2, 400); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +CREATE TABLE t3(a varchar(255), b varchar(255),c int); +GO +INSERT INTO t3 VALUES('xyz', 'a',1); +INSERT INTO t3 VALUES('xyz', 'b',1); +INSERT INTO t3 VALUES('abc', 'a',2); +INSERT INTO t3 VALUES('abc', 'b',2); +INSERT INTO t3 VALUES('efg', 'a',3); +INSERT INTO t3 VALUES('efg', 'b',3); +INSERT INTO t3 VALUES(NULL, NULL, 1); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +-- Aggregation Function Syntax +-- COUNT[_BIG] ( { [ [ ALL | DISTINCT ] expression ] | * } ) +-- should return all rows - 4 +SELECT COUNT(*) from t2; +GO +~~START~~ +int +4 +~~END~~ + +SELECT COUNT_BIG(*) from t2; +GO +~~START~~ +bigint +4 +~~END~~ + +-- should return all rows where a is not NULL - 3 +SELECT COUNT(a) from t2; +GO +~~START~~ +int +3 +~~END~~ + +SELECT COUNT_BIG(a) from t2; +GO +~~START~~ +bigint +3 +~~END~~ + +-- should return all rows where a is not NULL - 3 +SELECT COUNT(ALL a) from t2; +GO +~~START~~ +int +3 +~~END~~ + +SELECT COUNT_BIG(ALL a) from t2; +GO +~~START~~ +bigint +3 +~~END~~ + +-- should return all rows where a is distinct - 2 +SELECT COUNT(DISTINCT a) from t2; +GO +~~START~~ +int +2 +~~END~~ + +SELECT COUNT_BIG(DISTINCT a) from t2; +GO +~~START~~ +bigint +2 +~~END~~ + + +-- Analytic Function Syntax +-- COUNT[_BIG] ( [ ALL ] { expression | * } ) OVER ( [ ] ) +SELECT COUNT(*) from t3; +GO +~~START~~ +int +7 +~~END~~ + +SELECT a, b, COUNT(*) OVER () from t3; +GO +~~START~~ +varchar#!#varchar#!#int +xyz#!#a#!#7 +xyz#!#b#!#7 +abc#!#a#!#7 +abc#!#b#!#7 +efg#!#a#!#7 +efg#!#b#!#7 +#!##!#7 +~~END~~ + +-- The result for order by is different in sql server because we have +-- an ordering issue for null type (JIRA: BABEL-788) +SELECT a, b, COUNT(*) OVER (ORDER BY a) from t3; +GO +~~START~~ +varchar#!#varchar#!#int +abc#!#b#!#2 +abc#!#a#!#2 +efg#!#a#!#4 +efg#!#b#!#4 +xyz#!#a#!#6 +xyz#!#b#!#6 +#!##!#7 +~~END~~ + +SELECT a, b, COUNT(*) OVER (ORDER BY a DESC) from t3; +GO +~~START~~ +varchar#!#varchar#!#int +#!##!#1 +xyz#!#b#!#3 +xyz#!#a#!#3 +efg#!#b#!#5 +efg#!#a#!#5 +abc#!#b#!#7 +abc#!#a#!#7 +~~END~~ + +SELECT a, b, COUNT(*) OVER(PARTITION BY a) from t3; +GO +~~START~~ +varchar#!#varchar#!#int +abc#!#b#!#2 +abc#!#a#!#2 +efg#!#a#!#2 +efg#!#b#!#2 +xyz#!#a#!#2 +xyz#!#b#!#2 +#!##!#1 +~~END~~ + +SELECT a, b, COUNT(*) OVER(PARTITION BY a ORDER BY b) from t3; +GO +~~START~~ +varchar#!#varchar#!#int +abc#!#a#!#1 +abc#!#b#!#2 +efg#!#a#!#1 +efg#!#b#!#2 +xyz#!#a#!#1 +xyz#!#b#!#2 +#!##!#1 +~~END~~ + +SELECT a, b, COUNT(*) OVER(PARTITION BY a ORDER BY b ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING) from t3; +GO +~~START~~ +varchar#!#varchar#!#int +abc#!#a#!#2 +abc#!#b#!#1 +efg#!#a#!#2 +efg#!#b#!#1 +xyz#!#a#!#2 +xyz#!#b#!#1 +#!##!#1 +~~END~~ + +SELECT COUNT_BIG(*) from t3; +GO +~~START~~ +bigint +7 +~~END~~ + +SELECT a, b, COUNT_BIG(*) OVER () from t3; +GO +~~START~~ +varchar#!#varchar#!#bigint +xyz#!#a#!#7 +xyz#!#b#!#7 +abc#!#a#!#7 +abc#!#b#!#7 +efg#!#a#!#7 +efg#!#b#!#7 +#!##!#7 +~~END~~ + +SELECT a, b, COUNT_BIG(*) OVER (ORDER BY a) from t3; +GO +~~START~~ +varchar#!#varchar#!#bigint +abc#!#b#!#2 +abc#!#a#!#2 +efg#!#a#!#4 +efg#!#b#!#4 +xyz#!#a#!#6 +xyz#!#b#!#6 +#!##!#7 +~~END~~ + +SELECT a, b, COUNT_BIG(*) OVER (ORDER BY a DESC) from t3; +GO +~~START~~ +varchar#!#varchar#!#bigint +#!##!#1 +xyz#!#b#!#3 +xyz#!#a#!#3 +efg#!#b#!#5 +efg#!#a#!#5 +abc#!#b#!#7 +abc#!#a#!#7 +~~END~~ + +SELECT a, b, COUNT_BIG(*) OVER(PARTITION BY a) from t3; +GO +~~START~~ +varchar#!#varchar#!#bigint +abc#!#b#!#2 +abc#!#a#!#2 +efg#!#a#!#2 +efg#!#b#!#2 +xyz#!#a#!#2 +xyz#!#b#!#2 +#!##!#1 +~~END~~ + +SELECT a, b, COUNT_BIG(*) OVER(PARTITION BY a ORDER BY b) from t3; +GO +~~START~~ +varchar#!#varchar#!#bigint +abc#!#a#!#1 +abc#!#b#!#2 +efg#!#a#!#1 +efg#!#b#!#2 +xyz#!#a#!#1 +xyz#!#b#!#2 +#!##!#1 +~~END~~ + +SELECT a, b, COUNT_BIG(*) OVER(PARTITION BY a ORDER BY b ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING) from t3; +GO +~~START~~ +varchar#!#varchar#!#bigint +abc#!#a#!#2 +abc#!#b#!#1 +efg#!#a#!#2 +efg#!#b#!#1 +xyz#!#a#!#2 +xyz#!#b#!#1 +#!##!#1 +~~END~~ + + +-- COUNT(*) takes no parameters and does not support the use of DISTINC, expect error +DROP TABLE t2; +GO +DROP TABLE t3; +GO + +-- clean up +drop table dateadd_table; +GO + +-- test inline table-valued functions +-- simple case +create function itvf1 (@number int) returns table as return (select 1 as a, 2 as b); +GO +select * from itvf1(5); +GO +~~START~~ +int#!#int +1#!#2 +~~END~~ + +-- should fail because column names are not specified +create function itvf2 (@number int) returns table as return (select 1, 2); +GO +~~ERROR (Code: 4514)~~ + +~~ERROR (Message: CREATE FUNCTION failed because a column name is not specified for column 1)~~ + + +-- select from a table +create table example_table(name text, age int); +GO +insert into example_table values('hello', 3); +GO +~~ROW COUNT: 1~~ + +-- should have 'a' and 'b' as result column names +create function itvf3 (@number int) returns table as return (select name as a, age as b from example_table); +GO +select * from itvf3(5); +GO +~~START~~ +text#!#int +hello#!#3 +~~END~~ + +-- test returning multiple rows +insert into example_table values('hello1', 4); +insert into example_table values('hello2', 5); +insert into example_table values('hello3', 6); +select * from itvf3(5); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +text#!#int +hello#!#3 +hello1#!#4 +hello2#!#5 +hello3#!#6 +~~END~~ + + + +-- complex queries with use of function parameter +create table id_name(id int, name text); +GO +insert into id_name values(1001, 'adam'); +insert into id_name values(1002, 'bob'); +insert into id_name values(1003, 'chaz'); +insert into id_name values(1004, 'dave'); +insert into id_name values(1005, 'ed'); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +create table id_score(id int, score int); +GO +insert into id_score values(1001, 90); +insert into id_score values(1001, 70); +insert into id_score values(1002, 90); +insert into id_score values(1002, 80); +insert into id_score values(1003, 80); +insert into id_score values(1003, 70); +insert into id_score values(1004, 80); +insert into id_score values(1004, 60); +insert into id_score values(1005, 80); +insert into id_score values(1005, 100); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + + +-- test inline table-valued function with table-valued parameter +create type tableType as table( + a text not null, + b int primary key, + c int); +GO + +create function itvf8 (@number int, @tableVar tableType READONLY) returns table as return ( +select n.id, n.name as first_name, sum(s.score) as total_score +from id_name as n +join id_score as s +on n.id = s.id +where s.id <= @number and s.id in (select c from @tableVar) +group by n.id, n.name +order by n.id +); +GO + +create procedure itvf8_proc as +begin + declare @tableVariable tableType + insert into @tableVariable values('hello1', 1, 1001) + insert into @tableVariable values('hello2', 2, 1002) + select * from itvf8(1004, @tableVariable) +end; +GO + +EXEC itvf8_proc; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#text#!#int +1001#!#adam#!#160 +1002#!#bob#!#170 +~~END~~ + + +-- test using parameter in projection list +create function itvf9(@number int) returns table as return ( +select @number as a from id_name +); +GO + +select * from itvf9(1); +GO +~~START~~ +int +1 +1 +1 +1 +1 +~~END~~ + + +-- clean up +drop function itvf1; +GO +drop table example_table; +GO +drop function itvf3; +GO +drop table id_name; +GO +drop table id_score; +GO +drop procedure itvf8_proc; +GO +drop function itvf8; +GO +drop type tableType; +GO +drop function itvf9; +GO + + +-- test RETURN not followed by a semicolon +create function test_return1(@stringToSplit VARCHAR(MAX)) +RETURNS @returnList TABLE([Name] [nvarchar] (500)) +AS +BEGIN + RETURN +END +GO +select * from test_return1('test'); +GO +~~START~~ +nvarchar +~~END~~ + +drop function test_return1; +GO +create function test_return2(@stringToSplit VARCHAR(MAX)) +RETURNS @returnList TABLE([Name] [nvarchar] (500)) +AS +BEGIN + RETURN; +END +GO +select * from test_return2('test'); +GO +~~START~~ +nvarchar +~~END~~ + +drop function test_return2; +GO +create function test_return3(@a int) +RETURNS @returnList TABLE([Name] [nvarchar] (500)) +AS +BEGIN + IF @a = 1 + RETURN + SELECT @a = 2 + INSERT into @returnList values('abc') + RETURN +END +GO +select * from test_return3(1); +GO +~~START~~ +nvarchar +~~END~~ + +select * from test_return3(2); +GO +~~START~~ +nvarchar +abc +~~END~~ + +drop function test_return3; +GO +create function test_return4(@a int) +RETURNS @returnList TABLE([Name] [nvarchar] (500)) +AS +BEGIN + IF @a = 1 + RETURN + ELSE + SELECT @a = 2 + INSERT into @returnList values('abc') + RETURN +END +GO +select * from test_return4(1); +GO +~~START~~ +nvarchar +~~END~~ + +select * from test_return4(2); +GO +~~START~~ +nvarchar +abc +~~END~~ + +drop function test_return4; +GO diff --git a/test/JDBC/expected/babel_like.out b/test/JDBC/expected/babel_like.out new file mode 100644 index 0000000000..4ad5272cda --- /dev/null +++ b/test/JDBC/expected/babel_like.out @@ -0,0 +1,52 @@ +select relname from pg_class where relname like NULL; +GO +~~START~~ +varchar +~~END~~ + +select relname from pg_class where relname like ''; +GO +~~START~~ +varchar +~~END~~ + +select relname from pg_class where relname like 'pg\[1:9\]class'; +GO +~~START~~ +varchar +~~END~~ + + +select relname from pg_class where relname like 'pg*[1:9*]class' escape '*'; +GO +~~START~~ +varchar +~~END~~ + + +select relname from pg_class where relname like NULL; +GO +~~START~~ +varchar +~~END~~ + +select relname from pg_class where relname like ''; +GO +~~START~~ +varchar +~~END~~ + +select relname from pg_class where relname like 'pg\[1:9\]class'; +GO +~~START~~ +varchar +~~END~~ + + + +select relname from pg_class where relname like 'pg*[1:9*]class' escape '*'; +GO +~~START~~ +varchar +~~END~~ + diff --git a/test/JDBC/expected/babel_select_distinct_top.out b/test/JDBC/expected/babel_select_distinct_top.out new file mode 100644 index 0000000000..0e7ad75448 --- /dev/null +++ b/test/JDBC/expected/babel_select_distinct_top.out @@ -0,0 +1,59 @@ +create table babel_select_distinct_top (a int); +GO +insert into babel_select_distinct_top values (3), (1), (2), (2), (1); +GO +~~ROW COUNT: 5~~ + +select * from babel_select_distinct_top ORDER BY a ASC; +GO +~~START~~ +int +1 +1 +2 +2 +3 +~~END~~ + +select distinct a from babel_select_distinct_top order by a; +GO +~~START~~ +int +1 +2 +3 +~~END~~ + +select distinct top(2) a from babel_select_distinct_top order by a; +GO +~~START~~ +int +1 +2 +~~END~~ + +select * from (select distinct top(2) a from babel_select_distinct_top order by a) b; +GO +~~START~~ +int +1 +2 +~~END~~ + +select (select distinct top(1) a from babel_select_distinct_top order by a); +GO +~~START~~ +int +1 +~~END~~ + +select 'foo' where (select distinct top(1) a from babel_select_distinct_top order by a) = 1; +GO +~~START~~ +varchar +foo +~~END~~ + +-- Clean up +drop table babel_select_distinct_top; +GO diff --git a/test/JDBC/expected/babel_set_command.out b/test/JDBC/expected/babel_set_command.out new file mode 100644 index 0000000000..4b8034dbdd --- /dev/null +++ b/test/JDBC/expected/babel_set_command.out @@ -0,0 +1,68 @@ +-- Simple SET +DECLARE @lc_messages VARCHAR(20); +SELECT @lc_messages = 'fr_FR.utf8'; +SELECT @lc_messages; +GO +~~START~~ +varchar +fr_FR.utf8 +~~END~~ + + +-- Inside transaction with commit +BEGIN TRANSACTION; + DECLARE @lc_messages VARCHAR(20); +SELECT @lc_messages = 'fr_FR.utf8'; +COMMIT TRANSACTION; +SELECT @lc_messages; +SET @lc_messages = NULL; +GO +~~START~~ +varchar +fr_FR.utf8 +~~END~~ + +-- Inside transaction with rollback +DECLARE @lc_messages VARCHAR(20); +SET @lc_messages = 'fr_FR.utf8'; +BEGIN TRANSACTION; + SET @lc_messages = 'fr_FR.utf8'; +ROLLBACK TRANSACTION; +SELECT @lc_messages; +SET @lc_messages = NULL; +GO +~~START~~ +varchar +fr_FR.utf8 +~~END~~ + + +-- Inside transaction with rollback to savepoint +DECLARE @lc_messages VARCHAR(20); +SET @lc_messages = 'en_GB.utf8'; +BEGIN TRANSACTION; + SET @lc_messages = 'en_GB.utf8'; + SAVE TRANSACTION SP1; + SET @lc_messages = 'fr_FR.utf8'; + SELECT @lc_messages; + ROLLBACK TRANSACTION SP1; + SELECT @lc_messages; +ROLLBACK TRANSACTION; +SELECT @lc_messages; +SET @lc_messages = NULL; +GO +~~START~~ +varchar +fr_FR.utf8 +~~END~~ + +~~START~~ +varchar +fr_FR.utf8 +~~END~~ + +~~START~~ +varchar +fr_FR.utf8 +~~END~~ + diff --git a/contrib/babelfishpg_tsql/sql/test/babel_table_type.sql b/test/JDBC/expected/babel_table_type.out similarity index 72% rename from contrib/babelfishpg_tsql/sql/test/babel_table_type.sql rename to test/JDBC/expected/babel_table_type.out index 9a03bf8b75..8628c8356a 100644 --- a/contrib/babelfishpg_tsql/sql/test/babel_table_type.sql +++ b/test/JDBC/expected/babel_table_type.out @@ -1,72 +1,29 @@ -CREATE USER my_test_user; -GRANT CREATE ON DATABASE contrib_regression TO my_test_user; -GRANT CREATE ON SCHEMA public TO PUBLIC; -SET SESSION AUTHORIZATION my_test_user; -- table type is only supported in tsql dialect CREATE TYPE tableType AS table( a text not null, b int primary key, c int); - -set babelfishpg_tsql.sql_dialect = 'tsql'; -\tsql ON - --- table type supports all CREATE TABLE element lists -CREATE TYPE tableType AS table( - a text not null, - b int primary key, - c int); -GO - -- a table with the same name is created select * from tableType; GO +~~START~~ +text#!#int#!#int +~~END~~ --- create type with same name, should fail -CREATE TYPE tableType as (d int, e int); -GO - --- create table with same name, should succeed --- TODO: BABEL-689: Postgres doesn't support this yet, because CREATE TABLE will automatically --- create a composite type as well, which will cause name collision -CREATE TABLE tableType(d int, e int); -GO -- dropping the table should fail, as it depends on the table type DROP TABLE tableType; GO +~~ERROR (Code: 3723)~~ --- dropping the table type should drop the table as well -DROP TYPE tableType; -GO -SELECT * FROM tableType; -GO +~~ERROR (Message: cannot drop table tabletype because type tabletype requires it)~~ --- creating index (other than primary and unique keys) during table type creation is not --- yet supported --- TODO: BABEL-688: fully support TSQL CREATE TABLE syntax -CREATE TYPE tableType AS table( - a text not null, - b int primary key, - c int, - d int index idx1 nonclustered, - index idx2(c), - index idx3(e), - e varchar); -GO - --- test dotted prefixes of the table type name --- allowed to have one dotted prefix -CREATE TYPE public.tableType AS table(a int, b int); -GO -DROP TYPE public.tableType; +-- dropping the table type should drop the table as well +DROP TYPE tableType; GO --- not allowed to have more than one dotted prefix -CREATE TYPE postgres.public.tableType AS table(a int, b int); -GO CREATE TYPE tableType AS table( a text not null, @@ -83,8 +40,15 @@ begin select count(*) from @b; end; GO -CALL table_var_procedure(); +EXEC table_var_procedure; GO +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + DROP PROCEDURE table_var_procedure; GO @@ -99,8 +63,21 @@ begin select * from @tableVar; end; GO -CALL table_var_procedure(); +EXEC table_var_procedure; GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#1000 +~~END~~ + DROP PROCEDURE table_var_procedure; GO @@ -115,36 +92,20 @@ begin select * from @tableVar1 t1 join @tableVar2 t2 on t1.a = t2.c; end; GO -CALL table_var_procedure(); +EXEC table_var_procedure; GO -DROP PROCEDURE table_var_procedure; -GO - --- test MERGE on table variables --- TODO: BABEL-877 Support MERGE -/* -create procedure merge_proc as -begin - declare @tv1 table(a int); - insert into @tv1 values (200); +~~ROW COUNT: 1~~ - declare @tv2 table(b int); - insert into @tv2 values (100); - insert into @tv2 values (200); +~~ROW COUNT: 1~~ - merge into @tv1 using @tv2 on a=b - when not matched then insert (a) values(b) - when matched then update set a = a + b; +~~START~~ +int#!#int#!#int#!#varchar +1#!#100#!#1#!#a +~~END~~ - select * from @tv1; -end; -GO -CALL merge_proc(); -GO --- result should have two rows, 400 and 100. -DROP PROCEDURE merge_proc; +DROP PROCEDURE table_var_procedure; GO -*/ + -- test declaring a variable whose name is already used - should throw error create procedure dup_var_name_procedure as @@ -153,9 +114,13 @@ begin declare @a tableType; end; GO +~~ERROR (Code: 134)~~ + +~~ERROR (Message: duplicate declaration)~~ + -- test declaring a variable whose name is already used as table name - should work -create table @test_table (d int); +create table test_table (d int); GO create procedure dup_var_name_procedure as begin @@ -164,11 +129,18 @@ begin select * from @test_table; end; GO -call dup_var_name_procedure(); +EXEC dup_var_name_procedure; GO +~~ROW COUNT: 1~~ + +~~START~~ +text#!#int#!#int +hello1#!#1#!#100 +~~END~~ + drop procedure dup_var_name_procedure; GO -drop table @test_table; +drop table test_table; GO -- test assigning to table variables, should not be allowed @@ -176,30 +148,19 @@ create table test_table(a int, b int); GO insert into test_table values(1, 10); GO +~~ROW COUNT: 1~~ + create procedure assign_proc as begin declare @tableVar table (a int, b int); set @tableVar = test_table; end; GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: unrecognized dtype: 3)~~ --- test selecting into table variables, should not be allowed -create procedure select_into_proc as -begin - declare @tableVar table (a int, b int); - select * into @tableVar from test_table; -end; -GO --- test truncating table variables, should not be allowed -create procedure truncate_proc as -begin - declare @tableVar table (a int, b int); - insert into @tableVar values(1, 2); - truncate table @tableVar; - select * from @tableVar; -end; -GO -- test JOIN on table variables, on both sides create procedure join_proc1 as @@ -209,9 +170,17 @@ begin select * from test_table t inner join @tableVar tv on t.a = tv.a; end; GO -CALL join_proc1(); +EXEC join_proc1; GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int#!#int#!#int#!#int +1#!#10#!#1#!#2#!#3 +~~END~~ + DROP PROCEDURE join_proc1; +GO create procedure join_proc2 as begin @@ -220,19 +189,18 @@ begin select * from @tableVar tv inner join test_table t on tv.a = t.a; end; GO -CALL join_proc2(); +EXEC join_proc2; GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int#!#int#!#int#!#int +1#!#2#!#3#!#1#!#10 +~~END~~ + DROP PROCEDURE join_proc2; GO --- test altering table variables, should not be allowed -create procedure alter_proc as -begin - declare @tableVar table (a int); - alter table @tableVar add b int; - select * from @tableVar; -end; -GO -- test using the same variables as source and target create procedure source_target_proc as @@ -245,26 +213,30 @@ begin select * from @tv; end; GO -CALL source_target_proc(); -GO -DROP PROCEDURE source_target_proc; +EXEC source_target_proc; GO +~~ROW COUNT: 1~~ --- test multiple '@' characters in table variable name --- TODO: BABEL-476 Support variable name with multiple '@' characters -/* -create procedure nameing_proc as -begin - declare @@@tv@1@@@ as table(a int); - insert @@@tv@1@@@ values(1); - select * from @@@tv@1@@@; -end; -GO -CALL naming_proc(); -GO -DROP PROCEDURE naming_proc; +~~ROW COUNT: 1~~ + +~~ROW COUNT: 2~~ + +~~ROW COUNT: 4~~ + +~~START~~ +int +1 +2 +3 +4 +5 +6 +7 +8 +~~END~~ + +DROP PROCEDURE source_target_proc; GO -*/ -- test nested functions using table variables with the same name, each should -- have its own variable @@ -291,6 +263,11 @@ end; GO select outer_func(); GO +~~START~~ +int +2 +~~END~~ + DROP FUNCTION outer_func; GO @@ -310,8 +287,13 @@ begin select @result; end; GO -call loop_func_proc(); +EXEC loop_func_proc; GO +~~START~~ +int +5 +~~END~~ + DROP PROCEDURE loop_func_proc; GO @@ -338,8 +320,23 @@ begin select @result; end; GO -call loop_proc() +EXEC loop_proc GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +15 +~~END~~ + DROP PROCEDURE loop_proc; GO @@ -354,8 +351,19 @@ begin WITH t1 (a) AS (SELECT a FROM @tablevar1) SELECT * FROM @tablevar2 t2 JOIN t1 ON t2.a = t1.a; end; GO -call cte_proc() +EXEC cte_proc GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +text#!#int#!#int#!#text +hello1#!#1#!#100#!#hello1 +~~END~~ + DROP PROCEDURE cte_proc; GO @@ -367,7 +375,7 @@ begin set datefirst 7; end; GO -call pl_set_proc() +EXEC pl_set_proc GO DROP PROCEDURE pl_set_proc; GO @@ -383,8 +391,20 @@ begin select * from @tablevar1, @tablevar2; end; GO -call select_multi_tablevars() +EXEC select_multi_tablevars GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +text#!#int#!#int#!#text#!#int#!#int +hello1#!#1#!#100#!#hello1#!#1#!#100 +hello1#!#1#!#100#!#hello2#!#2#!#200 +~~END~~ + DROP PROCEDURE select_multi_tablevars; GO @@ -396,8 +416,15 @@ begin select * from test_table, @tablevar; end; GO -call select_table_tablevar() +EXEC select_table_tablevar GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int#!#text#!#int#!#int +1#!#10#!#hello1#!#1#!#100 +~~END~~ + DROP PROCEDURE select_table_tablevar; GO @@ -408,12 +435,20 @@ begin return 1; end GO +~~ERROR (Code: 352)~~ + +~~ERROR (Message: The table-valued parameter "@tablevar" must be declared with the READONLY option.)~~ + -- if READONLY on other param type: report error create function error_func(@a int, @b int READONLY) returns int as begin return 1; end GO +~~ERROR (Code: 346)~~ + +~~ERROR (Message: The parameter "@b" can not be declared READONLY since it is not a table-valued parameter.)~~ + -- correct syntax create function tvp_func(@tableVar tableType READONLY) returns int as begin @@ -424,17 +459,6 @@ end GO -- test passing in a table variable whose type is different from what the function wants -- TODO: BABEL-899: error message should be "Operand type clash: table is incompatible with tableType" -create procedure error_proc as -begin - declare @tableVar as table (a text, b int, c int); - insert into @tableVar values('hello1', 1, 100); - select tvp_func(@tableVar); -end; -GO -call error_proc() -GO -DROP PROCEDURE error_proc; -GO create procedure tvp_proc as begin declare @tableVar tableType; @@ -442,8 +466,15 @@ begin select tvp_func(@tableVar); end; GO -call tvp_proc() +EXEC tvp_proc GO +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + DROP PROCEDURE tvp_proc; GO DROP FUNCTION tvp_func; @@ -469,8 +500,19 @@ begin select multi_tvp_func(@v1, @v2); end; GO -call multi_tvp_proc() +EXEC multi_tvp_proc GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + DROP PROCEDURE multi_tvp_proc; GO DROP FUNCTION multi_tvp_func; @@ -493,6 +535,12 @@ end; GO select * from mstvf(1); GO +~~START~~ +text#!#int#!#int +hello1#!#1#!#100 +hello2#!#2#!#200 +~~END~~ + DROP FUNCTION mstvf; GO -- test mstvf whose return table has only one column @@ -507,6 +555,11 @@ end; GO select * from mstvf_one_col(1); GO +~~START~~ +text +hello1 +~~END~~ + DROP FUNCTION mstvf_one_col; GO -- test mstvf whose return table has only one column @@ -522,6 +575,11 @@ end; GO select * from mstvf_return(1); GO +~~START~~ +text +hello2 +~~END~~ + DROP FUNCTION mstvf_return; GO -- test mstvf's with same names in different schemas @@ -549,8 +607,18 @@ end; GO select * from mstvf_schema(1); GO +~~START~~ +varchar +test_name +~~END~~ + select * from test_schema.mstvf_schema(1); GO +~~START~~ +varchar +test_name1 +~~END~~ + drop function mstvf_schema; GO drop function test_schema.mstvf_schema; @@ -573,6 +641,11 @@ end; GO select * from mstvf_constraints(1); GO +~~START~~ +varchar#!#int +test_name#!#1 +~~END~~ + drop function mstvf_constraints; GO @@ -581,10 +654,3 @@ DROP TYPE tableType; GO DROP TABLE test_table; GO -\tsql OFF -reset babelfishpg_tsql.sql_dialect; -RESET SESSION AUTHORIZATION; --- if we are able to drop the user, then it means that all the underlying tables --- of table variables have been dropped because they depend on the user. -REVOKE CREATE ON DATABASE contrib_regression FROM my_test_user; -DROP USER my_test_user; diff --git a/test/JDBC/expected/babel_transaction.out b/test/JDBC/expected/babel_transaction.out new file mode 100644 index 0000000000..c0aa474e67 --- /dev/null +++ b/test/JDBC/expected/babel_transaction.out @@ -0,0 +1,430 @@ +create table TxnTable(c1 int); +GO + + +-- Begin transaction -> commit transaction +begin transaction; +select @@trancount; +GO +~~START~~ +int +1 +~~END~~ + +begin transaction; +select @@trancount; +GO +~~START~~ +int +2 +~~END~~ + +insert into TxnTable values(1); +commit transaction; +select @@trancount; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + +commit transaction; +select @@trancount; +GO +~~START~~ +int +0 +~~END~~ + +select c1 from TxnTable; +GO +~~START~~ +int +1 +~~END~~ + + +-- Begin transaction -> rollback transaction +begin transaction; +insert into TxnTable values(2); +rollback transaction; +select c1 from TxnTable; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + + +-- Begin tran -> commit tran +begin tran; +insert into TxnTable values(2); +commit tran; +select c1 from TxnTable; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +2 +~~END~~ + + +-- Begin tran -> rollback tran +begin tran; +select @@trancount; +begin tran; +set transaction isolation level read uncommitted; +insert into TxnTable values(3); +select @@trancount; +rollback tran; +select @@trancount; +select c1 from TxnTable; +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +2 +~~END~~ + +~~START~~ +int +0 +~~END~~ + +~~START~~ +int +1 +2 +~~END~~ + + + +-- Begin transaction -> commit +begin transaction; +insert into TxnTable values(4); +commit; +select c1 from TxnTable; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +2 +4 +~~END~~ + + +-- Begin transaction -> commit work +begin transaction; +insert into TxnTable values(5); +commit work; +select c1 from TxnTable; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +2 +4 +5 +~~END~~ + + +-- Begin transaction -> rollback +begin transaction; +insert into TxnTable values(6); +rollback; +select c1 from TxnTable; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +2 +4 +5 +~~END~~ + + +-- Begin transaction -> rollback work +begin transaction; +insert into TxnTable values(7); +rollback work; +select c1 from TxnTable; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +2 +4 +5 +~~END~~ + + +-- Begin transaction name -> commit transaction name +begin transaction txn1; +insert into TxnTable values(8); +commit transaction txn1; +select c1 from TxnTable; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +2 +4 +5 +8 +~~END~~ + + +-- Begin transaction name -> rollback transaction name +begin transaction txn1; +insert into TxnTable values(9); +rollback transaction txn1; +select c1 from TxnTable; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +2 +4 +5 +8 +~~END~~ + + +-- Begin tran name -> commit tran name +begin tran txn1; +insert into TxnTable values(10); +commit tran txn1; +select c1 from TxnTable; +Go +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +2 +4 +5 +8 +10 +~~END~~ + + +-- Begin tran name -> rollback tran name +begin tran txn1; +insert into TxnTable values(10); +rollback tran txn1; +select c1 from TxnTable; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +2 +4 +5 +8 +10 +~~END~~ + +truncate table TxnTable; +GO + +-- save tran name -> rollback tran name +begin transaction txn1; +insert into TxnTable values(1); +save transaction sp1; +select @@trancount; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + +insert into TxnTable values(2); +save tran sp2; +insert into TxnTable values(3); +save tran sp2; +select @@trancount; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + +insert into TxnTable values(4); +select c1 from TxnTable; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +2 +3 +4 +~~END~~ + +rollback tran sp2; +select @@trancount; +GO +~~START~~ +int +1 +~~END~~ + +select c1 from TxnTable; +GO +~~START~~ +int +1 +2 +3 +~~END~~ + +rollback tran sp2; +select @@trancount; +GO +~~START~~ +int +1 +~~END~~ + +select c1 from TxnTable; +GO +~~START~~ +int +1 +2 +~~END~~ + +rollback tran sp1; +select @@trancount; +GO +~~START~~ +int +1 +~~END~~ + +select c1 from TxnTable; +GO +~~START~~ +int +1 +~~END~~ + +rollback tran txn1; +select @@trancount; +GO +~~START~~ +int +0 +~~END~~ + +select c1 from TxnTable; +GO +~~START~~ +int +~~END~~ + + +-- begin transaction name -> save transaction name -> rollback tran name +-- Rollback whole transaction +begin transaction txn1; +insert into TxnTable values(1); +save transaction sp1; +begin transaction txn1; +insert into TxnTable values(2); +save transaction sp1; +insert into TxnTable values(3); +select @@trancount; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +2 +~~END~~ + +rollback tran txn1; +select @@trancount; +GO +~~START~~ +int +0 +~~END~~ + +select c1 from TxnTable; +GO +~~START~~ +int +~~END~~ + + +-- begin transaction -> save transaction name -> rollback to savepoint +-- commit transaction +begin transaction txn1; +insert into TxnTable values(1); +save transaction sp1; +insert into TxnTable values(2); +select c1 from TxnTable; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +2 +~~END~~ + +rollback tran sp1; +commit transaction; +select c1 from TxnTable; +GO +~~START~~ +int +1 +~~END~~ + + + + + + + diff --git a/test/JDBC/expected/babel_typecode.out b/test/JDBC/expected/babel_typecode.out new file mode 100644 index 0000000000..d445af8cd6 --- /dev/null +++ b/test/JDBC/expected/babel_typecode.out @@ -0,0 +1,40 @@ +-- test typecode list sys table +SELECT pg_namespace, pg_typname, tsql_typname, type_family_priority, priority, sql_variant_hdr_size FROM sys.babelfish_typecode_list() ORDER BY priority ASC; +GO +~~START~~ +text#!#text#!#text#!#smallint#!#smallint#!#smallint +sys#!#sql_variant#!#sql_variant#!#1#!#1#!#1 +sys#!#datetimeoffset#!#datetimeoffset#!#2#!#2#!#2 +sys#!#datetime2#!#datetime2#!#2#!#3#!#2 +sys#!#datetime#!#datetime#!#2#!#4#!#1 +sys#!#smalldatetime#!#smalldatetime#!#2#!#5#!#1 +pg_catalog#!#date#!#date#!#2#!#6#!#1 +pg_catalog#!#time#!#time#!#2#!#7#!#2 +pg_catalog#!#float8#!#float#!#3#!#8#!#1 +pg_catalog#!#float4#!#real#!#3#!#9#!#1 +pg_catalog#!#numeric#!#numeric#!#4#!#10#!#3 +sys#!#money#!#money#!#4#!#11#!#1 +sys#!#smallmoney#!#smallmoney#!#4#!#12#!#1 +pg_catalog#!#int8#!#bigint#!#4#!#13#!#1 +pg_catalog#!#int4#!#int#!#4#!#14#!#1 +pg_catalog#!#int2#!#smallint#!#4#!#15#!#1 +sys#!#tinyint#!#tinyint#!#4#!#16#!#1 +sys#!#bit#!#bit#!#4#!#17#!#1 +sys#!#nvarchar#!#nvarchar#!#5#!#18#!#5 +sys#!#nchar#!#nchar#!#5#!#19#!#5 +sys#!#varchar#!#varchar#!#5#!#20#!#5 +sys#!#bpchar#!#char#!#5#!#21#!#5 +sys#!#varbinary#!#varbinary#!#6#!#22#!#3 +sys#!#binary#!#binary#!#6#!#23#!#3 +sys#!#uniqueidentifier#!#uniqueidentifier#!#7#!#24#!#1 +pg_catalog#!#text#!#text#!#5#!#25#!#5 +sys#!#ntext#!#ntext#!#5#!#26#!#5 +sys#!#image#!#image#!#5#!#27#!#5 +pg_catalog#!#xml#!#xml#!#5#!#28#!#5 +pg_catalog#!#bpchar#!#char#!#5#!#29#!#5 +sys#!#decimal#!#decimal#!#5#!#30#!#5 +sys#!#sysname#!#sysname#!#5#!#31#!#5 +sys#!#rowversion#!#timestamp#!#8#!#32#!#3 +sys#!#timestamp#!#timestamp#!#8#!#33#!#3 +~~END~~ + diff --git a/test/JDBC/expected/babel_uniqueidentifier.out b/test/JDBC/expected/babel_uniqueidentifier.out new file mode 100644 index 0000000000..69b28dae7e --- /dev/null +++ b/test/JDBC/expected/babel_uniqueidentifier.out @@ -0,0 +1,323 @@ +create table t1 (a uniqueidentifier, b uniqueidentifier, c uniqueidentifier, primary key(a)); +GO + +insert into t1(a) values ('6F9619FF-8B86-D011-B42D-00C04FC964FF'); +GO +~~ROW COUNT: 1~~ + + +insert into t1(a) values ('6F9619FF-8B86-D011-B42D-00C04FC964FF'); -- trigger error +GO +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "t1_pkey")~~ + + +select * from t1; +GO +~~START~~ +uniqueidentifier#!#uniqueidentifier#!#uniqueidentifier +6F9619FF-8B86-D011-B42D-00C04FC964FF#!##!# +~~END~~ + + +insert into t1 values ('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', newid(), newid()); +GO +~~ROW COUNT: 1~~ + + +select * from t1 where a = '6F9619FF-8B86-D011-B42D-00C04FC964FF'; -- test PK +GO +~~START~~ +uniqueidentifier#!#uniqueidentifier#!#uniqueidentifier +6F9619FF-8B86-D011-B42D-00C04FC964FF#!##!# +~~END~~ + + +select count(*) from t1 where a = '6F9619FF-8B86-D011-B42D-00C04FC964FF'; +GO +~~START~~ +int +1 +~~END~~ + +select count(*) from t1 where a > '6F9619FF-8B86-D011-B42D-00C04FC964FF'; +GO +~~START~~ +int +1 +~~END~~ + +select count(*) from t1 where a >= '6F9619FF-8B86-D011-B42D-00C04FC964FF'; +GO +~~START~~ +int +2 +~~END~~ + +select count(*) from t1 where a < 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'; +GO +~~START~~ +int +1 +~~END~~ + +select count(*) from t1 where a <= 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'; +GO +~~START~~ +int +2 +~~END~~ + +select count(*) from t1 where a <> 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'; +GO +~~START~~ +int +1 +~~END~~ + + +-- newid's value could not be verified +insert into t1 values (newid(), newid(), newid()); +insert into t1 values (newid(), newid(), newid()); +insert into t1 values (newid(), newid(), newid()); +select count(a) from t1; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +5 +~~END~~ + + +create table t2 (a uniqueidentifier, b uniqueidentifier, c uniqueidentifier, primary key(a)); +insert into t2 select * from t1 order by a; +select count(distinct a) from t2; +GO +~~ROW COUNT: 5~~ + +~~START~~ +int +5 +~~END~~ + + +-- test index (need more data) +create table t3 ( a uniqueidentifier, b uniqueidentifier); +GO +-- create inital distinct values +insert into t3 values (newid(), newid()); +insert into t3 values (newid(), newid()); +insert into t3 values (newid(), newid()); +insert into t3 values (newid(), newid()); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +create index t3_a on t3 (a); +GO + +create index t3_b on t3 (b); +GO + +-- test truncate feature of uniqueidentifier_in +create table t4 ( a uniqueidentifier); +GO + +insert into t4 values ('6F9619FF-8B86-D011-B42D-00C04FC964FF'); +GO +~~ROW COUNT: 1~~ + + +insert into t4 values ('6F9619FF-8B86-D011-B42D-00C04FC964FFwrong'); -- characters exceeding are truncated +GO +~~ROW COUNT: 1~~ + + +insert into t4 values ('{6F9619FF-8B86-D011-B42D-00C04FC964FF}'); -- with braces +GO +~~ROW COUNT: 1~~ + + +insert into t4 values ('{6F9619FF-8B86-D011-B42D-00C04FC964FFwrong'); -- error due to no matching brace +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type uuid: "{6F9619FF-8B86-D011-B42D-00C04FC964FFwrong")~~ + + +insert into t4 values ('6F9619FF-8B86-D011-B42D-00C04FC964FF}'); -- single brace at the end are truncated +GO +~~ROW COUNT: 1~~ + + +select * from t4; +GO +~~START~~ +uniqueidentifier +6F9619FF-8B86-D011-B42D-00C04FC964FF +6F9619FF-8B86-D011-B42D-00C04FC964FF +6F9619FF-8B86-D011-B42D-00C04FC964FF +6F9619FF-8B86-D011-B42D-00C04FC964FF +~~END~~ + + +select set_config('enable_seqscan','off','false'); +GO +~~START~~ +text +off +~~END~~ + + +select set_config('enable_bitmapscan','off','false'); +GO +~~START~~ +text +off +~~END~~ + + +select set_config('search_path','sys, public','true'); +GO +~~START~~ +text +sys, public +~~END~~ + + +select name, setting from pg_settings where name in ('enable_seqscan', 'enable_bitmapscan'); +GO +~~START~~ +text#!#text +enable_bitmapscan#!#off +enable_seqscan#!#off +~~END~~ + +select * from t3 where a = 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'; -- test btree index +GO +~~START~~ +uniqueidentifier#!#uniqueidentifier +~~END~~ + +select * from t3 where b = 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'; -- test hash index +GO +~~START~~ +uniqueidentifier#!#uniqueidentifier +~~END~~ + + +-- assignment cast, should have same behavior as normal insert +create table t5 ( a uniqueidentifier); +insert into t5 values (cast('6F9619FF-8B86-D011-B42D-00C04FC964FF' as varchar(50))); +GO +~~ROW COUNT: 1~~ + +insert into t5 values (cast('6F9619FF-8B86-D011-B42D-00C04FC964FFwrong' as varchar(50))); -- characters exceeding are truncated +GO +~~ROW COUNT: 1~~ + +insert into t5 values (cast('{6F9619FF-8B86-D011-B42D-00C04FC964FF}' as varchar(50))); -- with braces +GO +~~ROW COUNT: 1~~ + +insert into t5 values (cast('{6F9619FF-8B86-D011-B42D-00C04FC964FFwrong' as varchar(50))); -- error due to no matching brace +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type uuid: "{6F9619FF-8B86-D011-B42D-00C04FC964FFwrong")~~ + +insert into t5 values (cast('6F9619FF-8B86-D011-B42D-00C04FC964FF}' as varchar(50))); -- single brace at the end are truncated +GO +~~ROW COUNT: 1~~ + +insert into t5 values (cast('6F9619FF-8B86-D011-B42D-00C04FC964FF' as nvarchar(50))); +GO +~~ROW COUNT: 1~~ + +insert into t5 values (cast('6F9619FF-8B86-D011-B42D-00C04FC964FFwrong' as nvarchar(50))); -- characters exceeding are truncated +GO +~~ROW COUNT: 1~~ + +insert into t5 values (cast('{6F9619FF-8B86-D011-B42D-00C04FC964FF}' as nvarchar(50))); -- with braces +GO +~~ROW COUNT: 1~~ + +insert into t5 values (cast('{6F9619FF-8B86-D011-B42D-00C04FC964FFwrong' as nvarchar(50))); -- error due to no matching brace +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type uuid: "{6F9619FF-8B86-D011-B42D-00C04FC964FFwrong")~~ + +insert into t5 values (cast('6F9619FF-8B86-D011-B42D-00C04FC964FF}' as nvarchar(50))); -- single brace at the end are truncated +GO +~~ROW COUNT: 1~~ + + +-- error cases, implicit cast not supported +select * from t5 where a = cast('6F9619FF-8B86-D011-B42D-00C04FC964FF' as varchar(50)); +GO +~~START~~ +uniqueidentifier +6F9619FF-8B86-D011-B42D-00C04FC964FF +6F9619FF-8B86-D011-B42D-00C04FC964FF +6F9619FF-8B86-D011-B42D-00C04FC964FF +6F9619FF-8B86-D011-B42D-00C04FC964FF +6F9619FF-8B86-D011-B42D-00C04FC964FF +6F9619FF-8B86-D011-B42D-00C04FC964FF +6F9619FF-8B86-D011-B42D-00C04FC964FF +6F9619FF-8B86-D011-B42D-00C04FC964FF +~~END~~ + +select * from t5 where a = cast('6F9619FF-8B86-D011-B42D-00C04FC964FF' as nvarchar(50)); +GO +~~START~~ +uniqueidentifier +6F9619FF-8B86-D011-B42D-00C04FC964FF +6F9619FF-8B86-D011-B42D-00C04FC964FF +6F9619FF-8B86-D011-B42D-00C04FC964FF +6F9619FF-8B86-D011-B42D-00C04FC964FF +6F9619FF-8B86-D011-B42D-00C04FC964FF +6F9619FF-8B86-D011-B42D-00C04FC964FF +6F9619FF-8B86-D011-B42D-00C04FC964FF +6F9619FF-8B86-D011-B42D-00C04FC964FF +~~END~~ + + +select set_config('enable_seqscan','on','false'); +GO +~~START~~ +text +on +~~END~~ + + +select set_config('enable_bitmapscan','on','false'); +GO +~~START~~ +text +on +~~END~~ + + +drop table t1; +GO +drop table t2; +GO +drop table t3; +GO +drop table t4; +GO +drop table t5; +GO diff --git a/contrib/babelfishpg_tsql/sql/test/babel_219.sql b/test/JDBC/input/babel_219.sql similarity index 59% rename from contrib/babelfishpg_tsql/sql/test/babel_219.sql rename to test/JDBC/input/babel_219.sql index 77dc7ca3e5..cd28a91d93 100644 --- a/contrib/babelfishpg_tsql/sql/test/babel_219.sql +++ b/test/JDBC/input/babel_219.sql @@ -1,35 +1,36 @@ -- This test should be run without installing the babelfishpg_tsql extension -- BABEL-219 test a domain named varchar in schema other than sys -- is not affected by the fix of BABEL-219 -create domain public.varchar as pg_catalog.varchar(2) check (char_length(value) < 1); -select cast('a' as public.varchar); -- throw error -select cast('' as public.varchar); +select cast('' as varchar); +GO select cast('a' as varchar); -- pg_catalog.varchar should work +GO -show search_path; -- Explicitly add pg_catalog to tail of search_path, -- to force varchar default to public.varchar -select set_config('search_path', current_setting('search_path') || ', pg_catalog', false); +select set_config('search_path', current_setting('search_path') + ', pg_catalog', false); +GO -- Set tsql dialet so the fix for BABEL-219 can kick in -SET babelfishpg_tsql.sql_dialect = 'tsql'; select cast('a' as varchar); -- varchar default to public.varchar. should fail exactly the same way as explicitly specifying public.varchar +GO select cast('' as varchar); -- varchar default to public.varchar. should pass +GO create table t1(col varchar); insert into t1 (col) select 'a'; -- fail insert into t1 (col) select ''; -- pass -select * from t1; +select * from t1 ORDER BY col; +GO + -- verify behavior of public.varchar is unchanged in tsql dialect -select cast('a' as public.varchar); -- fail -select cast('' as public.varchar); -- pass -create table t2(col public.varchar); -insert into t1 (col) select 'a'; -- fail -insert into t1 (col) select ''; -- pass -select * from t1; +create table t2(col varchar); +GO +insert into t2 (col) select 'a'; -- fail +insert into t2 (col) select ''; -- pass +select * from t2 ORDER BY col; +GO -- Clean up drop table t1; +GO drop table t2; -set babelfishpg_tsql.sql_dialect = 'postgres'; --- Reset search_path -set search_path to "$user", public; -show search_path; +GO diff --git a/contrib/babelfishpg_tsql/sql/test/babel_collation.sql b/test/JDBC/input/babel_collection.sql similarity index 58% rename from contrib/babelfishpg_tsql/sql/test/babel_collation.sql rename to test/JDBC/input/babel_collection.sql index 3434e5c18f..6ab8f3f091 100644 --- a/contrib/babelfishpg_tsql/sql/test/babel_collation.sql +++ b/test/JDBC/input/babel_collection.sql @@ -1,8 +1,6 @@ -- nvarchar is not supported in PG create table testing1(col nvarchar(60)); -- expect this to fail in the Postgres dialect - -CREATE EXTENSION IF NOT EXISTS "babelfishpg_tsql" CASCADE; -set babelfishpg_tsql.sql_dialect = "tsql"; +GO -- check the babelfish version select cast( @@ -11,175 +9,221 @@ select cast( THEN 'valid' else 'invalid' end as sys.varchar(20)); - +GO -- nvarchar is supported in tsql dialect -create table testing1(col nvarchar(60)); insert into testing1 (col) select N'Muffler'; insert into testing1 (col) select N'Mülle'; insert into testing1 (col) select N'MX Systems'; insert into testing1 (col) select N'Magic'; select * from testing1 order by col; +GO -- test case insensitive collation create table testing2 (col varchar(20) collate SQL_Latin1_General_CP1_CI_AS); +GO insert into testing2 values ('JONES'); insert into testing2 values ('jones'); insert into testing2 values ('Jones'); insert into testing2 values ('JoNes'); insert into testing2 values ('JoNés'); +GO select * from testing2 where col collate BBF_Unicode_General_CS_AS = 'JoNes'; +GO select * from testing2 where col collate BBF_Unicode_General_CI_AS = 'JoNes'; +GO select * from testing2 where col collate BBF_Unicode_General_CI_AI = 'JoNes'; +GO select * from testing2 where col collate BBF_Unicode_General_CS_AI = 'JoNes'; +GO -- test case insensitivity for default collation create table testing3 (c1 varchar(20), c2 char(20), c3 nvarchar(20)); -reset babelfishpg_tsql.sql_dialect; -\d testing3 -set babelfishpg_tsql.sql_dialect = "tsql"; +GO + insert into testing3 values ('JONES','JONES','JONES'); insert into testing3 values ('JoneS','JoneS','JoneS'); insert into testing3 values ('jOnes','jOnes','jOnes'); +GO select c1 from testing3 where c1='jones'; +GO select c2 from testing3 where c2='jones'; +GO select c3 from testing3 where c3='jones'; +GO -- test LIKE to ILIKE transformation create table testing4 (c1 varchar(20), c2 char(20), c3 nvarchar(20)); create index c1_idx on testing4 (c1); +GO insert into testing4 values ('JONES','JONES','JONES'); insert into testing4 values ('JoneS','JoneS','JoneS'); insert into testing4 values ('jOnes','jOnes','jOnes'); insert into testing4 values ('abcD','AbcD','ABCd'); insert into testing4 values ('äbĆD','äḃcD','äƀCd'); +GO -- set enable_seqscan doesn't work from the TSQL dialect, so switch -- dialects, disable sequential scan so we see some index-based plans, -- then switch back to the TSQL dialect -- -reset babelfishpg_tsql.sql_dialect; -set enable_seqscan = false; -set babelfishpg_tsql.sql_dialect = "tsql"; +select set_config('enable_seqscan','off','false'); +GO + +SET babelfish_showplan_all ON; +GO -- test that like is case-insenstive select c1 from testing4 where c1 LIKE 'jones'; -- this gets converted to '=' -explain (costs false) select c1 from testing4 where c1 LIKE 'jones'; +GO + select c1 from testing4 where c1 LIKE 'Jon%'; -explain (costs false) select c1 from testing4 where c1 LIKE 'Jon%'; +GO + select c1 from testing4 where c1 LIKE 'jone_'; -explain (costs false) select c1 from testing4 where c1 LIKE 'jone_'; +GO + select c1 from testing4 where c1 LIKE '_one_'; -explain (costs false) select c1 from testing4 where c1 LIKE '_one_'; +GO + select c1 from testing4 where c1 LIKE '%on%s'; -explain (costs false) select c1 from testing4 where c1 LIKE '%on%s'; +GO + -- test that like is accent-senstive for CI_AS collation select c1 from testing4 where c1 LIKE 'ab%'; +GO select c1 from testing4 where c1 LIKE 'äb%'; +GO select c1 from testing4 where c1 LIKE 'äḃĆ_'; +GO + -- test not like select c1 from testing4 where c1 NOT LIKE 'jones'; -explain (costs false) select c1 from testing4 where c1 NOT LIKE 'jones'; +GO + select c1 from testing4 where c1 NOT LIKE 'jone%'; -explain (costs false) select c1 from testing4 where c1 NOT LIKE 'jone%'; +GO + select c1 from testing4 where c1 NOT LIKE 'ä%'; -explain (costs false) select c1 from testing4 where c1 NOT LIKE 'ä%'; --- test escape function and wildcard literal -select c1 from testing4 where c1 LIKE E'\_ones'; -explain (costs false) select c1 from testing4 where c1 LIKE E'\_ones'; -select c1 from testing4 where c1 LIKE E'\%ones'; -explain (costs false) select c1 from testing4 where c1 LIKE E'\%ones'; +GO + + -- wild card literals are transformed to equal select c1 from testing4 where c1 LIKE '\%ones'; -explain(costs false) select c1 from testing4 where c1 LIKE '\%ones'; +GO + select c1 from testing4 where c1 LIKE '\_ones'; -explain(costs false) select c1 from testing4 where c1 LIKE '\_ones'; +GO + +SET babelfish_showplan_all OFF; +GO -- test combining with other string functions select c1 from testing4 where c1 LIKE lower('_ones'); +GO select c1 from testing4 where c1 LIKE upper('_ones'); +GO select c1 from testing4 where c1 LIKE concat('_on','_s'); +GO select c1 from testing4 where c1 LIKE concat('a','%d'); +GO select c1 from testing4 where c1 NOT LIKE lower('%s'); +GO -- test sub-queries Select * from testing4 where c1 LIKE (select c1 from testing4 where c1 LIKE 'AbcD'); +GO Select * from testing4 where c2 NOT LIKE (select c2 from testing4 where c2 NOT LIKE 'jo%' AND c2 NOT LIKE 'ä%'); +GO Select * from testing4 where c3 LIKE (select c3 from testing4 where c3 NOT LIKE'jo%' AND c3 NOT LIKE 'ä%'); +GO with p1 as (select c1 from testing4 where c1 LIKE '__Ć_'), p2 as (select c3 from testing4 where c3 LIKE 'äƀ__') select * from p1 union all select * from p2; +GO -- test case expression -select c1,(case c1 LIKE 'j%' when true then 1 when false then 2 end) from testing4; select c2,(case when c2 LIKE '_bc%' then 1 when c2 LIKE 'jon%' then 2 when c3 LIKE 'ä%' then 3 end) from testing4; +GO -- test that LIKE transformation is applied only for CI_AS column create table testing5(c1 varchar(20) COLLATE SQL_Latin1_General_CP1_CS_AS); +GO insert into testing5 values ('JONES'); insert into testing5 values ('JoneS'); insert into testing5 values ('abcD'); insert into testing5 values ('äbĆD'); +GO + select * from testing5 where c1 LIKE 'jo%'; -- does not use the transformation -explain(costs false) select * from testing5 where c1 LIKE 'jo%'; +GO +SET babelfish_showplan_all ON; +GO +select * from testing5 where c1 LIKE 'jo%'; +GO +SET babelfish_showplan_all OFF; +GO select * from testing5 where c1 NOT LIKE 'j%'; +GO select * from testing5 where c1 LIKE 'AB%'; +GO --- test explicitly specify collation as CI_AS, like transformation is also applied. -SELECT 'JONES' like 'jo%'; -SELECT 'JONES' COLLATE SQL_Latin1_General_CP1_CI_AS like 'jo%' ; - --- test when pattern is empty string or NULL -SELECT 'JONES' like ''; -SELECT 'JONES' like NULL; SELECT * from testing5 where c1 like ''; -explain (costs false) SELECT * from testing5 where c1 like ''; +GO +SET babelfish_showplan_all ON; +GO +SELECT * from testing5 where c1 like ''; +GO +SET babelfish_showplan_all OFF; +GO +SELECT * from testing5 where c1 like NULL; +GO +SET babelfish_showplan_all ON; +GO SELECT * from testing5 where c1 like NULL; -explain (costs false) SELECT * from testing5 where c1 like NULL; +GO +SET babelfish_showplan_all OFF; +GO SELECT * FROM testing5 where c1 COLLATE French_CI_AS like 'jo%' ; -explain (costs false) SELECT * FROM testing5 where c1 COLLATE French_CI_AS like 'jo%' ; +GO +SET babelfish_showplan_all ON; +GO +SELECT * FROM testing5 where c1 COLLATE French_CI_AS like 'jo%' ; +GO +SET babelfish_showplan_all OFF; +GO SELECT * FROM testing5 where c1 COLLATE Chinese_PRC_CI_AS like 'jo%' ; -explain (costs false) SELECT * FROM testing5 where c1 COLLATE Chinese_PRC_CI_AS like 'jo%' ; - --- tsql collations -alter table testing1 alter column col nvarchar(60) collate Arabic_CS_AS; -alter table testing1 alter column col nvarchar(60) collate Chinese_PRC_CS_AS; -alter table testing1 alter column col nvarchar(60) collate Cyrillic_General_CS_AS; -alter table testing1 alter column col nvarchar(60) collate French_CS_AS; -alter table testing1 alter column col nvarchar(60) collate Korean_Wansung_CS_AS; -alter table testing1 alter column col nvarchar(60) collate Traditional_Spanish_CS_AS; -alter table testing1 alter column col nvarchar(60) collate Modern_Spanish_CS_AS; -alter table testing1 alter column col nvarchar(60) collate SQL_Latin1_General_CP1_CS_AS; -alter table testing1 alter column col nvarchar(60) collate SQL_Latin1_General_CP1_CI_AS; -alter table testing1 alter column col nvarchar(60) collate Traditional_Spanish_CS_AS; -alter table testing1 alter column col nvarchar(60) collate Thai_CS_AS; -alter table testing1 alter column col nvarchar(60) collate Turkish_CS_AS; -alter table testing1 alter column col nvarchar(60) collate Ukrainian_CS_AS; -alter table testing1 alter column col nvarchar(60) collate Vietnamese_CS_AS; -alter table testing1 alter column col nvarchar(60) collate Finnish_Swedish_CS_AS; +GO +SET babelfish_showplan_all ON; +GO +SELECT * FROM testing5 where c1 COLLATE Chinese_PRC_CI_AS like 'jo%' ; +GO +SET babelfish_showplan_all OFF; +GO + -- expect different result order from previous select select * from testing1 order by col; - +GO -- test expression level collate, expect the same result order select * from testing1 order by col collate Finnish_Swedish_CS_AS; - +GO -- test catalog -select * from sys.fn_helpcollations(); - --- test the TYPE keyword is only required in postgres dialect, but not in tsql dialect -alter table testing1 alter column col varchar(60) collate Finnish_Swedish_CS_AS; -alter table testing1 alter column col TYPE varchar(60) collate Finnish_Swedish_CS_AS; -SELECT set_config('babelfishpg_tsql.sql_dialect', 'postgres', false); -alter table testing1 alter column col varchar(60) collate sys.Finnish_Swedish_CS_AS; -alter table testing1 alter column col TYPE varchar(60) collate sys.Finnish_Swedish_CS_AS; -SELECT set_config('babelfishpg_tsql.sql_dialect', 'tsql', false); +select * from sys.fn_helpcollations() order by name; +GO +SELECT set_config('babelfishpg_tsql.sql_dialect', 'tsql', false); +GO -- test collation list sys table SELECT collation_name, l1_priority, l2_priority, l3_priority, l4_priority, l5_priority FROM sys.babelfish_collation_list() order by collation_name; - +GO -- clean up drop table testing1; +GO drop table testing2; +GO drop table testing3; +GO drop table testing4; +GO drop table testing5; +GO \ No newline at end of file diff --git a/contrib/babelfishpg_tsql/sql/test/babel_datatype.sql b/test/JDBC/input/babel_datatype.sql similarity index 70% rename from contrib/babelfishpg_tsql/sql/test/babel_datatype.sql rename to test/JDBC/input/babel_datatype.sql index 35a1743ca3..14bfb4bacf 100644 --- a/contrib/babelfishpg_tsql/sql/test/babel_datatype.sql +++ b/test/JDBC/input/babel_datatype.sql @@ -1,805 +1,1084 @@ -CREATE EXTENSION IF NOT EXISTS "babelfishpg_tsql" CASCADE; - -- The default scale is 2 in PG. select CAST('$100,123.4567' AS money); +GO -- Currency symbol followed by number without being quoted is not recognized -- as Money in postgres dialect. select CAST($100123.4567 AS money); +GO -- Scale changes to the sql server default 4 in tsql dialect -- Currency symbol followed by number without being quoted is recognized -- as Money type in tsql dialect. -set babelfishpg_tsql.sql_dialect = "tsql"; select CAST($100123.4567 AS money); +GO select CAST($100123. AS money); +GO select CAST($.4567 AS money); +GO select CAST('$100,123.4567' AS money); +GO -- Test numeric types with brackets create table testing1 (a [tinyint]); +GO drop table testing1; +GO create table testing1 (a [smallint]); +GO drop table testing1; +GO create table testing1 (a [int]); +GO drop table testing1; +GO create table testing1 (a [bigint]); +GO drop table testing1; +GO create table testing1 (a [real]); +GO drop table testing1; +GO create table testing1 (a [float]); +GO drop table testing1; +GO --- Comma separated format without quote is not allowed in sql server -select CAST($100,123.4567 AS money); -- Smallmoney in tsql dialect select CAST($100123.4567 AS smallmoney); +GO select CAST('$100,123.4567' AS smallmoney); --- Comma separated format without quote is not allowed in sql server -select CAST($100,123.4567 AS smallmoney); +GO create table testing1(mon money, smon smallmoney); +GO insert into testing1 (mon, smon) values ('$100,123.4567', '$123.9999'); insert into testing1 (mon, smon) values ($100123.4567, $123.9999); +GO select * from testing1; +GO select avg(CAST(mon AS numeric(38,4))), avg(CAST(smon AS numeric(38,4))) from testing1; +GO select mon+smon as total from testing1; +GO -- Comma separated format without quote is not allowed in sql server insert into testing1 (mon, smon) values ($100,123.4567, $123.9999); +GO -- Test other allowed currency symbols with/without quote select CAST(€100.123 AS money); +GO select CAST('€100.123' AS money); +GO select CAST(¢100.123 AS money); +GO select CAST(£100.123 AS money); +GO select CAST('£100.123' AS money); +GO select CAST(¤100.123 AS money); +GO select CAST(¥100.123 AS money); +GO select CAST(৲100.123 AS money); +GO select CAST(৳100.123 AS money); +GO select CAST(฿100.123 AS money); +GO select CAST(៛100.123 AS money); +GO select CAST(₠100.123 AS money); +GO select CAST(₡100.123 AS money); +GO select CAST(₢100.123 AS money); +GO select CAST(₣100.123 AS money); +GO select CAST(₤100.123 AS money); +GO select CAST(₥100.123 AS money); +GO select CAST(₦100.123 AS money); +GO select CAST(₧100.123 AS money); +GO select CAST(₨100.123 AS money); +GO select CAST(₩100.123 AS money); +GO select CAST(₪100.123 AS money); +GO select CAST(₫100.123 AS money); +GO select CAST(₭100.123 AS money); +GO select CAST(₮100.123 AS money); +GO select CAST(₯100.123 AS money); +GO select CAST(₰100.123 AS money); +GO select CAST(₱100.123 AS money); +GO select CAST(﷼100.123 AS money); +GO select CAST(﹩100.123 AS money); +GO select CAST($100.123 AS money); +GO select CAST(¢100.123 AS money); +GO select CAST(£100.123 AS money); +GO select CAST(¥100.123 AS money); +GO select CAST('¥100.123' AS money); +GO select CAST(₩100.123 AS money); +GO -- Test unsupoorted currency symbol -select CAST(←100.123 AS money); select CAST('←100.123' AS money); +GO -- Test that space is allowed between currency symbol and number, this is -- a TSQL behavior select CAST($ 123.5 AS money); +GO select CAST('$ 123.5' AS money); +GO -- Test inexact result mutliply/divide money with money, to match -- SQL Server behavior select CAST(100 AS money)/CAST(339 AS money)*CAST(10000 AS money); +GO -- Test postgres dialect -- Test currency symbol without quote is not allowed in postgres dialect -reset babelfishpg_tsql.sql_dialect; select CAST(€100.123 AS money); +GO -- Test exact result multiply/divide money with money in postgres dialect select CAST(100 AS money)/CAST(339 AS money)*CAST(10000 AS money); +GO -- Clean up drop table testing1; +GO + --- BABEL-109 test no more not unique operator error caused by fixeddeciaml -select CAST(2 AS numeric) > 1; -select CAST(2 AS decimal) > 1; - --- Test that numeric > int and fixeddecimal > int is different -select CAST(2.00001 AS numeric) > 2; -select CAST(2.00001 AS sys.fixeddecimal) > 2; - --- test TSQL Money (based on fixeddecimal) cross datatype operators -set babelfishpg_tsql.sql_dialect = "tsql"; -select CAST(2 AS money) > 1; -select CAST(2 AS money) > CAST(1 AS int); -select CAST(2 AS money) > CAST(1 AS int2); -select CAST(2 AS money) > CAST(1 AS int4); -select CAST(2 AS money) > CAST(1 AS numeric); -select CAST(2 AS money) > CAST(1 AS decimal); - -select CAST(2 AS money) >= 1; -select CAST(2 AS money) >= CAST(1 AS int); -select CAST(2 AS money) >= CAST(1 AS int2); -select CAST(2 AS money) >= CAST(1 AS int4); -select CAST(2 AS money) >= CAST(1 AS numeric); -select CAST(2 AS money) >= CAST(1 AS decimal); - -select CAST(2 AS money) < 1; -select CAST(2 AS money) < CAST(1 AS int); -select CAST(2 AS money) < CAST(1 AS int2); -select CAST(2 AS money) < CAST(1 AS int4); -select CAST(2 AS money) < CAST(1 AS numeric); -select CAST(2 AS money) < CAST(1 AS decimal); - -select CAST(2 AS money) <= 1; -select CAST(2 AS money) <= CAST(1 AS int); -select CAST(2 AS money) <= CAST(1 AS int2); -select CAST(2 AS money) <= CAST(1 AS int4); -select CAST(2 AS money) <= CAST(1 AS numeric); -select CAST(2 AS money) <= CAST(1 AS decimal); - -select CAST(2 AS money) <> 1; -select CAST(2 AS money) <> CAST(1 AS int); -select CAST(2 AS money) <> CAST(1 AS int2); -select CAST(2 AS money) <> CAST(1 AS int4); -select CAST(2 AS money) <> CAST(1 AS numeric); -select CAST(2 AS money) <> CAST(1 AS decimal); select CAST(2 AS money) + 1; +GO select CAST(2 AS money) + CAST(1 AS int); +GO select CAST(2 AS money) + CAST(1 AS int2); +GO select CAST(2 AS money) + CAST(1 AS int4); +GO select CAST(2 AS money) + CAST(1 AS numeric); +GO select CAST(2 AS money) + CAST(1 AS decimal); +GO select CAST(2 AS money) - 1; +GO select CAST(2 AS money) - CAST(1 AS int); +GO select CAST(2 AS money) - CAST(1 AS int2); +GO select CAST(2 AS money) - CAST(1 AS int4); +GO select CAST(2 AS money) - CAST(1 AS numeric); +GO select CAST(2 AS money) - CAST(1 AS decimal); +GO select CAST(2 AS money) * 2; +GO select CAST(2 AS money) * CAST(2 AS int); +GO select CAST(2 AS money) * CAST(2 AS int2); +GO select CAST(2 AS money) * CAST(2 AS int4); +GO select CAST(2 AS money) * CAST(2 AS numeric); +GO select CAST(2 AS money) * CAST(2 AS decimal); +GO select CAST(2 AS money) / 0.5; +GO select CAST(2 AS money) / CAST(2 AS int); +GO select CAST(2 AS money) / CAST(2 AS int2); +GO select CAST(2 AS money) / CAST(2 AS int4); +GO select CAST(2 AS money) / CAST(0.5 AS numeric(4,2)); +GO select CAST(2 AS money) / CAST(0.5 AS decimal(4,2)); +GO -reset babelfishpg_tsql.sql_dialect; - --- Test DATE, DATETIME, DATETIMEOFFSET, DATETIME2 -set babelfishpg_tsql.sql_dialect = "tsql"; -- DATE DATETIME, DATETIMEOFFSET, DATETIME2 and SMALLDATETIME are defined in tsql dialect select CAST('2020-03-15' AS date); +GO select CAST('2020-03-15 09:00:00+8' AS datetimeoffset); +GO select CAST('2020-03-15 09:00:00' AS datetime2); +GO select CAST('2020-03-15 09:00:00' AS smalldatetime); +GO -- test the range of date select CAST('0001-01-01' AS date); +GO select CAST('9999-12-31' AS date); +GO -- test the range of datetime2 select CAST('0001-01-01 12:00:00.12345' AS datetime2); +GO select CAST('9999-12-31 12:00:00.12345' AS datetime2); +GO -- precision select CAST('2020-03-15 09:00:00+8' AS datetimeoffset(7)) ; +GO create table testing1(ts DATETIME, tstz DATETIMEOFFSET(7)); +GO + insert into testing1 (ts, tstz) values ('2020-03-15 09:00:00', '2020-03-15 09:00:00+8'); select * from testing1; drop table testing1; +GO select CAST('2020-03-15 09:00:00' AS datetime2(7)); +GO select CAST('2020-03-15 09:00:00.123456' AS datetime2(3)); +GO select CAST('2020-03-15 09:00:00.123456' AS datetime2(0)); -select CAST('2020-03-15 09:00:00.123456' AS datetime2(-1)); +GO + create table testing1(ts DATETIME, tstz DATETIME2(7)); insert into testing1 (ts, tstz) values ('2020-03-15 09:00:00', '2020-03-15 09:00:00'); select * from testing1; +GO drop table testing1; +GO -- DATETIME, DATETIMEOFFSET, DATETIME2 and SMALLDATETIME are not defined in -- postgres dialect SELECT set_config('babelfishpg_tsql.sql_dialect', 'postgres', false); +GO select CAST('2020-03-15 09:00:00+8' AS datetimeoffset); -create table testing1(ts DATETIME); +GO create table testing1(tstz DATETIMEOFFSET); +GO select CAST('2020-03-15 09:00:00' AS datetime2); -create table testing1(ts SMALLDATETIME); -create table testing1(tstz DATETIME2); +GO -- Test DATETIME, DATETIMEOFFSET, DATETIME2 and SMALLDATETIME can be used as identifier -create table testing1(DATETIME int); -insert into testing1 (DATETIME) values (1); select * from testing1; +GO drop table testing1; +GO create table testing1(DATETIMEOFFSET int); +GO insert into testing1 (DATETIMEOFFSET) values (1); +GO select * from testing1; +GO drop table testing1; +GO create table testing1(DATETIME2 int); +GO insert into testing1 (DATETIME2) values (1); +GO select * from testing1; +GO drop table testing1; +GO create table testing1(SMALLDATETIME int); +GO insert into testing1 (SMALLDATETIME) values (1); +GO select * from testing1; +GO + -set babelfishpg_tsql.sql_dialect = 'tsql'; insert into testing1 (SMALLDATETIME) values (2); +GO select * from testing1; +GO -- Test conversion between DATE and other date/time types select CAST(CAST('2020-03-15' AS date) AS datetime); +GO select CAST(CAST('2020-03-15' AS date) AS smalldatetime); +GO select CAST(CAST('2020-03-15' AS date) AS datetimeoffset(3)); +GO select CAST(CAST('2020-03-15' AS date) AS datetime2(3)); +GO -- Clean up -reset babelfishpg_tsql.sql_dialect; drop table testing1; +GO -- Test SYS.NCHAR, SYS.NVARCHAR and SYS.VARCHAR -- nchar is already available in postgres dialect select CAST('£' AS nchar(1)); +GO -- nvarchar is not available in postgres dialect select CAST('£' AS nvarchar); +GO -- both are available in tsql dialect -set babelfishpg_tsql.sql_dialect = 'tsql'; select CAST('£' AS nchar(2)); +GO select CAST('£' AS nvarchar(2)); +GO -- multi-byte character doesn't fit in nchar(1) in tsql if it -- would require a UTF16-surrogate-pair on output select CAST('£' AS char(1)); -- allowed +GO select CAST('£' AS sys.nchar(1)); -- allowed +GO select CAST('£' AS sys.nvarchar(1)); -- allowed +GO select CAST('£' AS sys.varchar(1)); -- allowed +GO -- Check that things work the same in postgres dialect -reset babelfishpg_tsql.sql_dialect; select CAST('£' AS char(1)); +GO select CAST('£' AS sys.nchar(1)); +GO select CAST('£' AS sys.nvarchar(1)); +GO select CAST('£' AS sys.varchar(1)); -set babelfishpg_tsql.sql_dialect = 'tsql'; +GO -- truncate input on explicit cast select CAST('ab' AS char(1)); +GO select CAST('ab' AS nchar(1)); +GO select CAST('ab' AS nvarchar(1)); +GO select CAST('ab' AS sys.varchar(1)); +GO -- default length of nchar/char is 1 in tsql (and pg) create table testing1(col nchar); -reset babelfishpg_tsql.sql_dialect; -\d testing1; -set babelfishpg_tsql.sql_dialect = "tsql"; +GO +SELECT * FROM testing1; +GO + -- check length at insert insert into testing1 (col) select 'a'; insert into testing1 (col) select '£'; insert into testing1 (col) select 'ab'; +GO + -- space is automatically truncated insert into testing1 (col) select 'c '; select * from testing1; +GO -- default length of nvarchar in tsql is 1 create table testing2(col nvarchar); +GO insert into testing2 (col) select 'a'; insert into testing2 (col) select '£'; insert into testing2 (col) select 'ab'; +GO + -- space is automatically truncated insert into testing2 (col) select 'c '; select * from testing2; +GO -- default length of varchar in tsql is 1 create table testing4(col sys.varchar); +GO insert into testing4 (col) select 'a'; insert into testing4 (col) select '£'; insert into testing4 (col) select 'ab'; +GO -- space is automatically truncated insert into testing4 (col) select 'c '; insert into testing2 (col) select '£ '; select * from testing4; +GO -- test sys.varchar(max) and sys.nvarchar(max) syntax is allowed in tsql dialect select CAST('abcdefghijklmn' AS sys.varchar(max)); +GO select CAST('abcdefghijklmn' AS varchar(max)); +GO select CAST('abcdefghijklmn' AS sys.nvarchar(max)); +GO select CAST('abcdefghijklmn' AS nvarchar(max)); +GO -- test char(max), nchar(max) is invalid syntax in tsql dialect select cast('abc' as char(max)); +GO select cast('abc' as nchar(max)); +GO -- test max can still be used as an identifier create table max (max int); insert into max (max) select 100; select * from max; +GO drop table max; +GO -- test sys.varchar(max) and nvarchar(max) syntax is not allowed in postgres dialect -reset babelfishpg_tsql.sql_dialect; select CAST('abcdefghijklmn' AS sys.varchar(max)); +GO select CAST('abcdefghijklmn' AS varchar(max)); +GO select CAST('abcdefghijklmn' AS sys.nvarchar(max)); +GO select CAST('abcdefghijklmn' AS nvarchar(max)); +GO -- test max max character length is (10 * 1024 * 1024) = 10485760 select CAST('abc' AS varchar(10485761)); +GO select CAST('abc' AS varchar(10485760)); +GO -- test column type nvarchar(max) -set babelfishpg_tsql.sql_dialect = 'tsql'; + create table testing5(col nvarchar(max)); -reset babelfishpg_tsql.sql_dialect; -\d testing5 -set babelfishpg_tsql.sql_dialect = "tsql"; +GO +SELECT * FROM testing5 +GO + insert into testing5 (col) select 'ab'; insert into testing5 (col) select 'abcdefghijklmn'; select * from testing5; +GO ---test COPY command works with sys.nvarchar -COPY public.testing5 (col) FROM stdin; -c -ab -abcdefghijk -\. -select * from testing5; -- [BABEL-220] test varchar(max) as a column drop table testing5; +GO + create table testing5(col varchar(max)); -reset babelfishpg_tsql.sql_dialect; -\d testing5 -set babelfishpg_tsql.sql_dialect = "tsql"; +GO + insert into testing5 (col) select 'ab'; insert into testing5 (col) select 'abcdefghijklmn'; select * from testing5; +GO -- test type modifer persist if babelfishpg_tsql.sql_dialect changes create table testing3(col nvarchar(2)); +GO + insert into testing3 (col) select 'ab'; insert into testing3 (col) select 'a£'; insert into testing3 (col) select 'a😀'; insert into testing3 (col) select 'abc'; +GO -reset babelfishpg_tsql.sql_dialect; insert into testing3 (col) select 'ab'; insert into testing3 (col) select 'a£'; insert into testing3 (col) select 'a😀'; insert into testing3 (col) select 'abc'; +GO + -set babelfishpg_tsql.sql_dialect = 'tsql'; insert into testing3 (col) select 'ab'; insert into testing3 (col) select 'a£'; insert into testing3 (col) select 'a😀'; insert into testing3 (col) select 'abc'; +GO -- test normal create domain works when apg_enable_domain_typmod is enabled -set apg_enable_domain_typmod true; -create domain varchar3 as varchar(3); -select CAST('abc' AS varchar3); -select CAST('ab£' AS varchar3); -select CAST('abcd' AS varchar3); -reset apg_enable_domain_typmod; +select set_config('enable_seqscan','on','true'); +GO +select CAST('abc' AS varchar(3)); +GO +select CAST('ab£' AS varchar(3)); +GO +select CAST('abcd' AS varchar(3)); +GO -- [BABEL-191] test typmod of sys.varchar/nvarchar engages when the input -- is casted multiple times select CAST(CAST('abc' AS text) AS sys.varchar(3)); +GO + select CAST(CAST('abc' AS pg_catalog.varchar(3)) AS sys.varchar(3)); +GO select CAST(CAST('abc' AS text) AS sys.nvarchar(3)); +GO select CAST(CAST('abc' AS text) AS sys.nchar(3)); +GO select CAST(CAST(CAST(CAST('abc' AS text) AS sys.varchar(3)) AS sys.nvarchar(3)) AS sys.nchar(3)); +GO -- test truncation on explicit cast through multiple levels select CAST(CAST(CAST(CAST('abcde' AS text) AS sys.varchar(5)) AS sys.nvarchar(4)) AS sys.nchar(3)); +GO select CAST(CAST(CAST(CAST('abcde' AS text) AS sys.varchar(3)) AS sys.nvarchar(4)) AS sys.nchar(5)); +GO -- test sys.ntext is available select CAST('abc£' AS sys.ntext); +GO -- pg_catalog.text select CAST('abc£' AS text); +GO -- [BABEL-218] test varchar defaults to sys.varchar in tsql dialect -- test default length of sys.varchar is 30 in CAST/CONVERT -- expect the last 'e' to be truncated select cast('abcdefghijklmnopqrstuvwxyzabcde' as varchar); +GO select cast('abcdefghijklmnopqrstuvwxyzabcde' as sys.varchar); +GO select convert(varchar, 'abcdefghijklmnopqrstuvwxyzabcde'); +GO select convert(sys.varchar, 'abcdefghijklmnopqrstuvwxyzabcde'); +GO -- default length of pg_catalog.varchar is unlimited, no truncation in output select cast('abcdefghijklmnopqrstuvwxyzabcde' as pg_catalog.varchar); +GO -- varchar defaults to pg_catalog.varchar in PG dialect -reset babelfishpg_tsql.sql_dialect; select cast('abcdefghijklmnopqrstuvwxyzabcde' as pg_catalog.varchar); -- default length of pg_catalog.varchar is unlimited, no truncation -set babelfishpg_tsql.sql_dialect = 'tsql'; +GO -- [BABEL-255] test nchar defaults to sys.nchar in tsql dialect create table test_nchar (col1 nchar); -reset babelfishpg_tsql.sql_dialect; -\d test_nchar -set babelfishpg_tsql.sql_dialect = "tsql"; +GO + + +SELECT * FROM test_nchar +GO + drop table test_nchar; +GO + -- test nchar defaults to bpchar in pg dialect -reset babelfishpg_tsql.sql_dialect; + create table test_nchar (col1 nchar); -\d test_nchar +GO +SELECT * FROM test_nchar drop table test_nchar; -set babelfishpg_tsql.sql_dialect = 'tsql'; +GO + -- [BABEL-257] test varchar defaults to sys.varchar in new -- database and new schema SELECT current_database(); +GO SELECT set_config('babelfishpg_tsql.sql_dialect', 'postgres', false); -CREATE DATABASE demo; -\c demo -CREATE EXTENSION IF NOT EXISTS "babelfishpg_tsql" CASCADE; --- Reconnect to make sure CLUSTER_COLLATION_OID is initialized -\c postgres -\c demo -set babelfishpg_tsql.sql_dialect = 'tsql'; +GO + + -- Test varchar is mapped to sys.varchar -- Expect truncated output because sys.varchar defaults to sys.varchar(30) in CAST function select cast('abcdefghijklmnopqrstuvwxyzabcde' as varchar); +GO -- Expect non-truncated output because pg_catalog.varchar has unlimited length select cast('abcdefghijklmnopqrstuvwxyzabcde' as pg_catalog.varchar); +GO -- Test bit is mapped to sys.bit -- sys.bit allows numeric input select CAST(1.5 AS bit); +GO -- pg_catalog.bit doesn't allow numeric input select CAST(1.5 AS pg_catalog.bit); +GO -- Test varchar is mapped to sys.varchar in a new schema and a new table CREATE SCHEMA s1; +GO + create table s1.test1 (col varchar); +GO -- Test sys.varchar is created for test1.col, expect an error -- because sys.varchar defaults to sys.varchar(1) insert into s1.test1 values('abc'); insert into s1.test1 values('a'); select * from s1.test1; -drop schema s1 cascade; +GO SELECT set_config('babelfishpg_tsql.sql_dialect', 'postgres', false); -\c regression -drop database demo; -set babelfishpg_tsql.sql_dialect = 'tsql'; +GO + -- test tinyint data type select CAST(100 AS tinyint); +GO select CAST(10 AS tinyint) / CAST(3 AS tinyint); -select CAST(256 AS tinyint); -select CAST((-1) AS tinyint); +GO -- test bit data type, bit defaults to sys.bit in tsql dialect -- test 'true'/'false' input is allowed. 't'/'f' is not allowed. select CAST('true' AS bit); +GO select CAST('True' AS bit); +GO select CAST('TRUE' AS bit); -select CAST('t' AS bit); -select CAST('T' AS bit); +GO select CAST('false' AS bit); +GO select CAST('False' AS bit); +GO select CAST('FALSE' AS bit); -select CAST('f' AS bit); -select CAST('F' AS bit); +GO -- test '1'/'0' select CAST('1' AS bit); +GO select CAST('0' AS bit); +GO select CAST('000' AS bit); +GO select CAST('010' AS bit); +GO -- test 'abc' is not allowed select CAST('abc' AS bit); +GO -- test NULL is allowed select CAST(NULL AS bit); +GO --- bit defaults to pg_catalog.bit in pg dialect -reset babelfishpg_tsql.sql_dialect; -- pg_catalog.bit doesn't recognize 'true' select CAST('true' AS bit); -select CAST('true' AS pg_catalog.bit); +GO select CAST('1' AS bit); -select CAST('1' AS pg_catalog.bit); +GO + -- test numeric and integer input -set babelfishpg_tsql.sql_dialect = 'tsql'; select CAST(1 AS bit); +GO select CAST(2 AS bit); +GO select CAST(0 AS bit); +GO select CAST(000 AS bit); +GO select CAST(0.0 AS bit); +GO select CAST(0.00 AS bit); +GO select CAST(0.5 AS bit); +GO -- test negative operator select CAST(-1 AS bit); +GO select CAST(-0.5 AS bit); +GO -- test int2 int4 int8 input select CAST(CAST(2 AS int2) AS bit); +GO select CAST(CAST(0 AS int2) AS bit); +GO select CAST(CAST(2 AS int4) AS bit); +GO select CAST(CAST(0 AS int4) AS bit); +GO select CAST(CAST(2 AS int8) AS bit); +GO select CAST(CAST(0 AS int8) AS bit); +GO -- test real, double precision input select CAST(CAST(1.5 AS real) AS bit); +GO select CAST(CAST(0.0 AS real) AS bit); +GO select CAST(CAST(1.5 AS double precision) AS bit); +GO select CAST(CAST(0.0 AS double precision) AS bit); +GO -- test decimal, numeric input select CAST(CAST(1.5 AS decimal(4,2)) AS bit); +GO select CAST(CAST(0.0 AS decimal(4,2)) AS bit); +GO select CAST(CAST(1.5 AS numeric(4,2)) AS bit); +GO select CAST(CAST(0.0 AS numeric(4,2)) AS bit); +GO -- test operators of bit create table testing6 (col1 bit, col2 bit); +GO insert into testing6 (col1, col2) select 'true', 'false'; insert into testing6 (col1, col2) select 0, 1; insert into testing6 (col1, col2) select '1', '2'; insert into testing6 (col1, col2) select 0.5, -1.5; select * from testing6; +GO select count(*) from testing6 where col1 = col2; +GO select count(*) from testing6 where col1 <> col2; +GO select count(*) from testing6 where col1 > col2; +GO select count(*) from testing6 where col1 >= col2; +GO select count(*) from testing6 where col1 < col2; +GO select count(*) from testing6 where col1 <= col2; +GO -- test casting of bits to other numeric types select cast(cast (1 as bit) as tinyint); +GO select cast(cast (1 as bit) as smallint); +GO select cast(cast (1 as bit) as int); +GO select cast(cast (1 as bit) as bigint); +GO select cast(cast (1 as bit) as numeric(2,1)); +GO select cast(cast (1 as bit) as money); +GO select cast(cast (1 as bit) as smallmoney); +GO --- test comparisions -select 1 = cast (1 as bit); -- test varbinary is available select cast('abc' as varbinary(3)); +GO -- test not throwing error if input would be truncated select cast('abc' as varbinary(2)); +GO --- test throwing error when not explicit casting -drop table testing6; -create table testing6(col varbinary(2)); -insert into testing6 values(cast('ab' as varchar)); -insert into testing6 values(cast('ab' as varbinary(2))); --- test throwing error if input would be truncated during table insert -insert into testing6 values(cast('abc' as varbinary(3))); select * from testing6; +GO -- test casting varbinary to varchar select cast(cast('a' AS varchar(10)) as varbinary(2)); +GO select cast(cast(cast('a' AS varchar(10)) as varbinary(2)) as varchar(2)); +GO select cast(cast('ab' AS varchar(10)) as varbinary(2)); +GO select cast(cast(cast('ab' AS varchar(10)) as varbinary(2)) as varchar(2)); +GO select cast(cast('abc' AS varchar(10)) as varbinary(2)); +GO select cast(cast(cast('abc' AS varchar(10)) as varbinary(2)) as varchar(2)); +GO -- test casting varbinary to nvarchar select cast(cast('a' AS nvarchar(10)) as varbinary(2)); +GO select cast(cast(cast('a' AS nvarchar(10)) as varbinary(2)) as nvarchar(2)); +GO select cast(cast('ab' AS nvarchar(10)) as varbinary(2)); +GO select cast(cast(cast('ab' AS nvarchar(10)) as varbinary(2)) as nvarchar(2)); +GO select cast(cast('abc' AS nvarchar(10)) as varbinary(2)); +GO select cast(cast(cast('abc' AS nvarchar(10)) as varbinary(2)) as nvarchar(2)); +GO -- test sys.image is available select cast('abc' as image); +GO -- test sys.binary is available select cast('abc' as binary(3)); +GO -- test not throwing error if input would be truncated select cast('abc' as binary(2)); +GO drop table testing6; +GO create table testing6(col binary(2)); +GO -- test throwing error when not explicit casting insert into testing6 values (cast('ab' as varchar)); +GO insert into testing6 values (cast('ab' as binary(2))); +GO -- test throwing error if input would be truncated insert into testing6 values (cast('abc' as binary(3))); +GO -- test null padding extra space for binary type insert into testing6 values (cast('a' as binary(2))); +GO select * from testing6; +GO -- test casting binary to varchar select cast(cast('a' AS varchar(10)) as binary(2)); +GO -- BABEL-1030 select cast(cast(cast('a' AS varchar(10)) as binary(2)) as varchar(2)); +GO select cast(cast('ab' AS varchar(10)) as binary(2)); +GO select cast(cast(cast('ab' AS varchar(10)) as binary(2)) as varchar(2)); +GO select cast(cast('abc' AS varchar(10)) as binary(2)); +GO select cast(cast(cast('abc' AS varchar(10)) as binary(2)) as varchar(2)); +GO -- test casting binary to nvarchar select cast(cast('a' AS nvarchar(10)) as binary(2)); +GO -- BABEL-1030 select cast(cast(cast('a' AS nvarchar(10)) as binary(2)) as nvarchar(2)); +GO select cast(cast('ab' AS nvarchar(10)) as binary(2)); +GO select cast(cast(cast('ab' AS nvarchar(10)) as binary(2)) as nvarchar(2)); +GO select cast(cast('abc' AS nvarchar(10)) as binary(2)); +GO select cast(cast(cast('abc' AS nvarchar(10)) as binary(2)) as nvarchar(2)); +GO -- test varbinary(max) syntax select CAST('010 ' AS varbinary(max)); +GO select CAST('010' AS varbinary(max)); +GO --- test binary(max) is invalid syntax -select cast('abc' as binary(max)); - --- test varbinary(max) as a column -drop table testing6; -create table testing6(col varbinary(max)); -insert into testing6 values ('abc'); -select * from testing6; - --- test binary max length is 8000 -select CAST('010' AS binary(8001)); -- test default length is 1 drop table testing6; +GO create table testing6(col varbinary); +GO insert into testing6 values (cast('a' as varbinary)); -insert into testing6 values (cast('ab' as varbinary)); +GO select * from testing6; +GO drop table testing6; +GO create table testing6(col binary); +GO insert into testing6 values (cast('a' as varbinary)); +GO insert into testing6 values (cast('ab' as varbinary)); +GO select * from testing6; +GO -- test default length of varbinary in cast/convert is 30 -- truncation silently select cast('abcdefghijklmnopqrstuvwxyzabcde' as varbinary); +GO -- no truncation select cast('abcdefghijklmnopqrstuvwxyzabcd' as varbinary); +GO -- truncation silently select convert(varbinary, 'abcdefghijklmnopqrstuvwxyzabcde'); +GO -- no truncation select convert(varbinary, 'abcdefghijklmnopqrstuvwxyzabcd'); +GO -- test escape format '\' is not specially handled for varbinary -- but it is escaped handled for bytea select CAST('\13' AS varbinary(5)); -select CAST('\13' AS bytea); +GO select CAST('\x13' AS varbinary(5)); +GO select CAST('\x13' AS bytea); +GO select CAST('\\' AS varbinary(5)); +GO select CAST('\\' AS bytea); +GO select CAST('\' AS varbinary); -select CAST('\' AS bytea); +GO + -- test NULL pad extra space for binary type, not for varbinary and image select CAST('\\' AS binary(3)); +GO select CAST('\\' AS varbinary(3)); +GO select CAST('\\' AS image); +GO -- [BABEL-254] test integer input is allowed for varbinary select cast(16 as varbinary(4)); +GO select cast(16*16 as varbinary(4)); +GO select cast(16*16*16 as varbinary(4)); +GO select cast(511 as varbinary(4)); +GO -- test truncation to the left if the number input is too large select cast(16*16*16*16 as varbinary(2)); +GO -- test same behavior on table insert drop table testing6; +GO create table testing6 (col varbinary(2)); +GO insert into testing6 values (16); +GO insert into testing6 values (16*16); +GO insert into testing6 values (16*16*16); +GO insert into testing6 values (16*16*16*16); +GO select * from testing6; +GO -- test int2, int4, int8 to varbinary select cast(16*CAST(16 AS int2) as varbinary(2)); +GO select cast(16*CAST(16 AS int4) as varbinary(4)); +GO select cast(16*CAST(16 AS int8) as varbinary(8)); +GO -- test truncation to the left if maxlen is shorter than the input select cast(CAST(16 AS int2) as varbinary(1)); +GO select cast(CAST(16 AS int2) as varbinary(2)); +GO -- test varbinary will only use 2 bytes (the size of the input) rather -- than maxlen select cast(CAST(16 AS int2) as varbinary(3)); +GO select cast(CAST(16 AS int2) as varbinary(4)); +GO select cast(CAST(16 AS int2) as varbinary(8)); +GO select cast(CAST(16 AS int4) as varbinary(1)); +GO select cast(CAST(16 AS int4) as varbinary(2)); +GO select cast(CAST(16 AS int4) as varbinary(3)); +GO select cast(CAST(16 AS int4) as varbinary(4)); +GO select cast(CAST(16 AS int4) as varbinary(8)); +GO select cast(CAST(16 AS int8) as varbinary(1)); +GO select cast(CAST(16 AS int8) as varbinary(2)); +GO select cast(CAST(16 AS int8) as varbinary(3)); +GO select cast(CAST(16 AS int8) as varbinary(4)); +GO select cast(CAST(16 AS int8) as varbinary(8)); +GO -- [BABEL-254] test integer iput is allowed for binary select cast(16 as binary(2)); +GO select cast(16*16 as binary(2)); +GO select cast(16*16*16 as binary(2)); +GO -- test truncation to the left if the number input is too large select cast(16*16*16*16 as binary(2)); +GO -- test same behavior on table insert drop table testing6; +GO create table testing6 (col binary(2)); +GO insert into testing6 values (16); +GO insert into testing6 values (16*16); +GO insert into testing6 values (16*16*16); +GO insert into testing6 values (16*16*16*16); +GO select * from testing6; +GO -- test int2, int4, int8 to binary select cast(16*CAST(16 AS int2) as binary(2)); +GO select cast(16*CAST(16 AS int4) as binary(4)); +GO select cast(16*CAST(16 AS int8) as binary(8)); +GO -- test truncation to the left if maxlen is shorter than the input select cast(CAST(16 AS int2) as binary(1)); +GO select cast(CAST(16 AS int2) as binary(2)); +GO select cast(CAST(16 AS int2) as binary(3)); +GO -- test 0 padding to the left if maxlen is longer than the input select cast(CAST(16 AS int2) as binary(4)); +GO select cast(CAST(16 AS int2) as binary(8)); +GO select cast(CAST(16 AS int4) as binary(1)); +GO select cast(CAST(16 AS int4) as binary(2)); +GO select cast(CAST(16 AS int4) as binary(3)); +GO select cast(CAST(16 AS int4) as binary(4)); +GO -- test 0 padding to the left if maxlen is longer than the input select cast(CAST(16 AS int4) as binary(8)); +GO select cast(CAST(16 AS int8) as binary(1)); +GO select cast(CAST(16 AS int8) as binary(2)); +GO select cast(CAST(16 AS int8) as binary(3)); +GO select cast(CAST(16 AS int8) as binary(4)); +GO select cast(CAST(16 AS int8) as binary(8)); +GO -- test 0 padding to the left if maxlen is longer than the input select cast(CAST(16 AS int8) as binary(10)); +GO -- test casting varbinary to int4 CREATE PROCEDURE cast_varbinary(@val int) AS @@ -808,310 +1087,130 @@ BEGIN PRINT @BinaryVariable PRINT cast(@BinaryVariable as int) END; +GO -call cast_varbinary(16); -call cast_varbinary(16*16); -call cast_varbinary(511); -drop procedure cast_varbinary; - --- test casting varbinary to int4 when the varbinary size is longer than 4 -CREATE PROCEDURE cast_varbinary(@val int) AS -BEGIN - DECLARE @BinaryVariable varbinary(8) = @val - PRINT @BinaryVariable - PRINT cast(@BinaryVariable as int) -END; - -call cast_varbinary(16); -call cast_varbinary(16*16); -drop procedure cast_varbinary; - --- test truncation varbinary to int4 -CREATE PROCEDURE cast_varbinary(@val int) AS -BEGIN - DECLARE @BinaryVariable varbinary(1) = @val - PRINT @BinaryVariable - PRINT cast(@BinaryVariable as int) -END; - -call cast_varbinary(16); -call cast_varbinary(16*16); -drop procedure cast_varbinary; - --- test casting varbinary to int2 -CREATE PROCEDURE cast_varbinary(@val int2) AS -BEGIN - DECLARE @BinaryVariable varbinary(2) = @val - PRINT @BinaryVariable - PRINT cast(@BinaryVariable as int2) -END; - -call cast_varbinary(CAST(16 AS int2)); -call cast_varbinary(CAST(256 AS int2)); -drop procedure cast_varbinary; - --- test truncation varbinary to int2 -CREATE PROCEDURE cast_varbinary(@val int2) AS -BEGIN - DECLARE @BinaryVariable varbinary(1) = @val - PRINT @BinaryVariable - PRINT cast(@BinaryVariable as int2) -END; - -call cast_varbinary(CAST(16 AS int2)); -call cast_varbinary(CAST(256 AS int2)); -drop procedure cast_varbinary; - --- test casting varbinary to int8 -CREATE PROCEDURE cast_varbinary(@val int8) AS -BEGIN - DECLARE @BinaryVariable varbinary(8) = @val - PRINT @BinaryVariable - PRINT cast(@BinaryVariable as int8) -END; - -call cast_varbinary(CAST(16 AS int8)); -call cast_varbinary(16*CAST(16 AS int8)); -drop procedure cast_varbinary; +EXEC cast_varbinary 16; +GO --- test truncation varbinary to int8 -CREATE PROCEDURE cast_varbinary(@val int8) AS -BEGIN - DECLARE @BinaryVariable varbinary(1) = @val - PRINT @BinaryVariable - PRINT cast(@BinaryVariable as int8) -END; - -call cast_varbinary(CAST(16 AS int8)); -call cast_varbinary(16*CAST(16 AS int8)); +EXEC cast_varbinary 511; +GO drop procedure cast_varbinary; - --- test casting binary to int4 -CREATE PROCEDURE cast_binary(@val int) AS -BEGIN - DECLARE @BinaryVariable binary(4) = @val - PRINT @BinaryVariable - PRINT cast(@BinaryVariable as int) -END; - -call cast_binary(16); -call cast_binary(256); -drop procedure cast_binary; - --- test casting binary to int4 when the binary size is greater than 4 -CREATE PROCEDURE cast_binary(@val int) AS -BEGIN - DECLARE @BinaryVariable binary(8) = @val - PRINT @BinaryVariable - PRINT cast(@BinaryVariable as int) -END; - -call cast_binary(16); -call cast_binary(256); -drop procedure cast_binary; - --- test truncation binary to int4 -CREATE PROCEDURE cast_binary(@val int) AS -BEGIN - DECLARE @BinaryVariable binary(1) = @val - PRINT @BinaryVariable - PRINT cast(@BinaryVariable as int) -END; - -call cast_binary(16); -call cast_binary(256); -drop procedure cast_binary; - --- test casting binary to int2 -CREATE PROCEDURE cast_binary(@val int2) AS -BEGIN - DECLARE @BinaryVariable binary(2) = @val - PRINT @BinaryVariable - PRINT cast(@BinaryVariable as int2) -END; - -call cast_binary(CAST(16 AS int2)); -call cast_binary(CAST(256 AS int2)); -drop procedure cast_binary; - --- test casting binary to int2 when the binary size is greater than 2 -CREATE PROCEDURE cast_binary(@val int2) AS -BEGIN - DECLARE @BinaryVariable binary(8) = @val - PRINT @BinaryVariable - PRINT cast(@BinaryVariable as int2) -END; - -call cast_binary(CAST(16 AS int2)); -call cast_binary(CAST(256 AS int2)); -drop procedure cast_binary; - --- test truncation binary to int2 -CREATE PROCEDURE cast_binary(@val int2) AS -BEGIN - DECLARE @BinaryVariable binary(1) = @val - PRINT @BinaryVariable - PRINT cast(@BinaryVariable as int2) -END; - -call cast_binary(CAST(16 AS int2)); -call cast_binary(CAST(256 AS int2)); -drop procedure cast_binary; - --- test casting binary to int8 -CREATE PROCEDURE cast_binary(@val int8) AS -BEGIN - DECLARE @BinaryVariable binary(8) = @val - PRINT @BinaryVariable - PRINT cast(@BinaryVariable as int8) -END; - -call cast_binary(CAST(16 AS int8)); -call cast_binary(CAST(256 AS int8)); -drop procedure cast_binary; - --- test casting binary to int8 when the binary size is greater than 8 -CREATE PROCEDURE cast_binary(@val int8) AS -BEGIN - DECLARE @BinaryVariable binary(12) = @val - PRINT @BinaryVariable - PRINT cast(@BinaryVariable as int8) -END; - -call cast_binary(CAST(16 AS int8)); -call cast_binary(CAST(256 AS int8)); -drop procedure cast_binary; - --- test truncation binary to int8 -CREATE PROCEDURE cast_binary(@val int8) AS -BEGIN - DECLARE @BinaryVariable binary(1) = @val - PRINT @BinaryVariable - PRINT cast(@BinaryVariable as int8) -END; - -call cast_binary(CAST(16 AS int8)); -call cast_binary(CAST(256 AS int8)); -drop procedure cast_binary; +GO -- test real to varbinary select cast(CAST(0.125 AS real) as varbinary(4)); +GO drop table testing6; +GO create table testing6 (col varbinary(4)); +GO insert into testing6 values (CAST(0.125 AS real)); insert into testing6 values (CAST(3.125 AS real)); select * from testing6; +GO -- test truncation rule when input is too long/varbinary length is too short select cast(CAST(0.125 AS real) as varbinary(2)); +GO select cast(CAST(0.125 AS real) as varbinary(4)); - --- test casting varbinary back to real -CREATE PROCEDURE cast_varbinary(@val real) AS -BEGIN - DECLARE @BinaryVariable varbinary(4) = @val - PRINT @BinaryVariable - PRINT cast(@BinaryVariable as real) -END; -call cast_varbinary(0.125); -call cast_varbinary(3.125); -drop procedure cast_varbinary; +GO -- test dobule precision to varbinary select cast(CAST(0.123456789 AS double precision) as varbinary(8)); +GO drop table testing6; +GO create table testing6 (col varbinary(8)); +GO insert into testing6 values (CAST(0.123456789 AS double precision)); insert into testing6 values (CAST(3.123456789 AS double precision)); select * from testing6; +GO -- test truncation rule when input is too long/varbinary length is too short select cast(CAST(0.123456789 AS double precision) as varbinary(2)); +GO select cast(CAST(0.123456789 AS double precision) as varbinary(8)); +GO --- test casting varbinary back to double precision -CREATE PROCEDURE cast_varbinary(@val double precision) AS -BEGIN - DECLARE @BinaryVariable varbinary(8) = @val - PRINT @BinaryVariable - PRINT cast(@BinaryVariable as double precision) -END; -call cast_varbinary(0.123456789); -call cast_varbinary(3.123456789); -drop procedure cast_varbinary; -- test real to binary select cast(CAST(0.125 AS real) as binary(4)); +GO drop table testing6; +GO create table testing6 (col binary(4)); +GO insert into testing6 values (CAST(0.125 AS real)); insert into testing6 values (CAST(3.125 AS real)); select * from testing6; +GO -- test truncation rule when input is too long/binary length is too short select cast(CAST(0.125 AS real) as binary(2)); +GO select cast(CAST(0.125 AS real) as binary(4)); +GO --- test casting binary back to real -CREATE PROCEDURE cast_binary(@val real) AS -BEGIN - DECLARE @BinaryVariable binary(4) = @val - PRINT @BinaryVariable - PRINT cast(@BinaryVariable as real) -END; -call cast_binary(0.125); -call cast_binary(3.125); -drop procedure cast_binary; -- test dobule precision to binary select cast(CAST(0.123456789 AS double precision) as binary(8)); +GO drop table testing6; +GO create table testing6 (col binary(8)); +GO insert into testing6 values (CAST(0.123456789 AS double precision)); insert into testing6 values (CAST(3.123456789 AS double precision)); select * from testing6; +GO -- test truncation rule when input is too long/binary length is too short select cast(CAST(0.123456789 AS double precision) as binary(2)); +GO select cast(CAST(0.123456789 AS double precision) as binary(8)); +GO --- test casting binary back to double precision -CREATE PROCEDURE cast_binary(@val double precision) AS -BEGIN - DECLARE @BinaryVariable binary(8) = @val - PRINT @BinaryVariable - PRINT cast(@BinaryVariable as double precision) -END; -call cast_binary(0.123456789); -call cast_binary(3.123456789); -drop procedure cast_binary; -- sys.sysname select CAST('£' AS sysname); -- allowed +GO select CAST(NULL AS sysname); -- not allowed +GO -- sys.sysname is working in both dialects select CAST('£' AS sys.sysname); -- allowed +GO select CAST(NULL AS sys.sysname); -- not allowed -reset babelfishpg_tsql.sql_dialect; +GO select CAST('£' AS sys.sysname); -- allowed +GO select CAST(NULL AS sys.sysname); -- not allowed +GO + -set babelfishpg_tsql.sql_dialect = 'tsql'; create table test_sysname (col sys.sysname); +GO insert into test_sysname values (repeat('£', 128)); -- allowed +GO insert into test_sysname values (repeat('😀', 128)); -- not allowed due to UTF check -reset babelfishpg_tsql.sql_dialect; +GO insert into test_sysname values (repeat('😀', 128)); -- not allowed due to UTF check +GO -set babelfishpg_tsql.sql_dialect = 'tsql'; -- clean up drop table testing1; +GO drop table testing2; +GO drop table testing3; +GO drop table testing4; +GO drop table testing5; +GO drop table testing6; +GO drop table test_sysname; -reset babelfishpg_tsql.sql_dialect; +GO \ No newline at end of file diff --git a/contrib/babelfishpg_tsql/sql/test/babel_ddl.sql b/test/JDBC/input/babel_ddl.sql similarity index 74% rename from contrib/babelfishpg_tsql/sql/test/babel_ddl.sql rename to test/JDBC/input/babel_ddl.sql index 117269928d..6f7de7381c 100644 --- a/contrib/babelfishpg_tsql/sql/test/babel_ddl.sql +++ b/test/JDBC/input/babel_ddl.sql @@ -1,207 +1,256 @@ -- CLUSTERED INDEX / NONCLUSTERED IDNEX create table t1 ( a int, b int); +GO create nonclustered index t1_idx1 on t1 (a); +GO + create clustered index t1_idx2 on t1(a); +GO create table t2 ( a int, b int, primary key nonclustered (a)); +GO create table t3 ( a int, b int, primary key clustered (a)); +GO create table t4 ( a int, b int, unique nonclustered (a)); +GO create table t5 ( a int, b int, unique clustered (a)); +GO create table t6 ( a int primary key nonclustered, b int); +GO create table t7 ( a int primary key clustered, b int); -create table t8 ( a int unique nonclustered, b int); -create table t9 ( a int unique clustered, b int); - -set babelfishpg_tsql.sql_dialect = "tsql"; - -create index t1_idx1 on t1 (a); -create index t1_idx2 on t1(a); - -create table t2 ( a int, b int, primary key (a)); -create table t3 ( a int, b int, primary key (a)); -create table t4 ( a int, b int, unique (a)); -create table t5 ( a int, b int, unique (a)); +GO -create table t6 ( a int primary key, b int); -create table t7 ( a int primary key, b int); create table t8 ( a int unique not null, b int); +GO create table t9 ( a int unique not null, b int); +GO -- CREATE INDEX ... ON syntax create index t1_idx3 on t1 (a) on [primary]; +GO create index t1_idx4 on t1 (a) on "default"; +GO -- CREATE TABLE WITH ( [,...n]) syntax -create table t10 (a int) -with (fillfactor = 90, FILETABLE_COLLATE_FILENAME = database_default); -create table t11 (a int) -with (data_compression = row on partitions (2, 4, 6 to 8)); create table t12 (a int) with (system_versioning = on (history_table = aaa.bbb, data_consistency_check = off)); +GO create table t13 (a int) with (remote_data_archive = on (filter_predicate = null, migration_state = outbound)); +GO create table t14 (a int) with (data_deletion = on (filter_column = a, retention_period = 14 day)); +GO --- CREATE INDEX WHERE... WITH ( [,...n]) syntax -create index t1_idx5 on t1(a) where a is not null -with (pad_index = off, fillfactor = 90, maxdop = 1, sort_in_tempdb = off, max_duration = 2 minutes); -create index t1_idx6 on t1(a) -with (data_compression = page on partitions (2, 4, 6 to 8)); - --- CREATE COLUMNSTORE INDEX -create columnstore index t1_idx7 on t1 (a) with (drop_existing = on); -create clustered columnstore index t1_idx8 on t1 (a) on [primary]; -- CREATE TABLE... WITH FILLFACTOR = num create table t15 (a int primary key with fillfactor=50); +GO -- ALTER TABLE... WITH FILLFACTOR = num create table t16 (a int not null); +GO alter table t16 add primary key (a) with fillfactor=50; +GO -- check property of the index select indexname, indexdef from pg_indexes where tablename like 't_' order by indexname; +GO -- CREATE TABLE(..., { PRIMARY KEY | UNIQUE } ... -- ON { partition_scheme | filegroup | "default" }) syntax -- ^ create table t17(a int, primary key clustered (a) on [PRIMARY]); +GO create table t18(a int, primary key clustered (a) on [PRIMARY]); +GO create table t19(a int, unique clustered (a) on [PRIMARY]); +GO create table t20(a int, unique clustered (a) on [PRIMARY]); +GO -- ALTER TABLE ... ADD [CONSTRAINT ...] DEFAULT ... FOR ... create table t21 (a int, b int); +GO alter table t21 add default 99 for a; +GO insert into t21(b) values (10); +GO select * from t21; +GO -alter table t21 alter a drop default; alter table t21 add constraint dflt11 default 11 for a; +GO insert into t21(b) values (20); +GO select * from t21; +GO -- Invalid default value alter table t21 add default 'test' for a; +GO -- Invalid column alter table t21 add default 99 for c; +GO -- Invalid table alter table t_invalid add default 99 for a; +GO -- ALTER TABLE ... WITH [NO]CHECK ADD CONSTRAINT ... -alter table t21 with check add constraint chk1 check (a > 0); -- add chk1 and enable it -alter table t21 with nocheck add constraint chk2 check (b > 0); -- add chk2 and disable it insert into t21 values (1, 1); +GO -- error, not fulfilling constraint chk1 insert into t21 values (0, 1); +GO -- should pass after CHECK/NOCHECK is fully supported insert into t21 values (1, 0); +GO select * from t21; +GO --- ALTER TABLE ... [NO]CHECK CONSTRAINT ... --- should pass after CHECK/NOCHECK is fully supported -alter table t21 nocheck constraint chk1; -- disable chk1 -alter table t21 check constraint chk2; -- enable chk2 --- CREATE TABLE ... ( a int identity(...) NOT FOR REPLICATION) -create table t22 (a int identity(1,1) NOT FOR REPLICATION); -create table t23 (a int identity(1,1) NOT FOR REPLICATION NOT NULL); -- ROWGUIDCOL syntax support create table t24 (a uniqueidentifier ROWGUIDCOL); +GO create table t25 (a int); +GO alter table t25 add b uniqueidentifier ROWGUIDCOL; +GO -- computed columns -- CREATE TABLE(..., AS -- ^ [ PERSISTED ] ) create table computed_column_t1 (a nvarchar(10), b AS substring(a,1,3) UNIQUE NOT NULL); +GO insert into computed_column_t1 values('abcd'); +GO select * from computed_column_t1; +GO -- test whether other constraints are working with computed columns insert into computed_column_t1 values('abcd'); -- throws error +GO -- check PERSISTED keyword -- should be able to use columns from left and right in the expression create table computed_column_t2 (a int, b AS (a + c) / 4 PERSISTED, c int); +GO insert into computed_column_t2 (a,c) values (12, 12); +GO select * from computed_column_t2; +GO -- should throw error - order matters create table computed_column_error (a int, b AS a/4 NOT NULL PERSISTED); +GO -- should throw error if postgres syntax is used in TSQL dialect create table computed_column_error (a int, b numeric generated always as (a/4) stored); +GO -- should throw error if there is any error in computed column expression create table computed_column_error (a nvarchar(10), b AS non_existant_function(a,1,3) UNIQUE NOT NULL); - +GO -- should throw error in case of nested computed columns create table computed_column_error (a int, b as c, c as a); +GO create table computed_column_error (a int, b as b + 1); +GO -- in case of multiple computed column, the entire statement should be rolled -- back even when the last one throws error create table computed_column_error (a int, b as a, c as b); +GO select * from computed_column_error; +GO -- ALTER TABLE... ADD AS -- ^ [ PERSISTED ] ) alter table computed_column_t1 add c int; +GO alter table computed_column_t1 add d as c / 4; +GO insert into computed_column_t1(a, c) VALUES ('efgh', 12); +GO select * from computed_column_t1; +GO --should thow error in case of nested computed columns - alter table computed_column_t1 add e as d; - alter table computed_column_t1 add e as e + 1; +alter table computed_column_t1 add e as d; +GO +alter table computed_column_t1 add e as e + 1; +GO -- should throw error if any of the dependant columns is modified or dropped. alter table computed_column_t1 drop column a; +GO alter table computed_column_t1 alter column a varchar; +GO -- should throw error as rand is non-deterministic alter table computed_column_t1 add e as rand() persisted; +GO -- but rand[seed] should succeed alter table computed_column_t1 add e as rand(1) persisted; +GO -- should throw error in postgres dialect select set_config('babelfishpg_tsql.sql_dialect', 'postgres', null); +GO create table computed_column_error (a int, b AS (a/4) PERSISTED NOT NULL); +GO -- since we're in postgres dialect, also check the table definition whether -- the computed column got resolved to correct datatype -\d computed_column_t1 +SELECT * FROM computed_column_t1 +GO -set babelfishpg_tsql.sql_dialect = "tsql"; drop table t1; +GO drop table t2; +GO drop table t3; +GO drop table t4; +GO drop table t5; +GO drop table t6; +GO drop table t7; +GO drop table t8; +GO drop table t9; -drop table t10; -drop table t11; +GO drop table t12; +GO drop table t13; +GO drop table t14; +GO drop table t15; +GO drop table t16; +GO drop table t17; +GO drop table t18; +GO drop table t19; +GO drop table t20; +GO drop table t21; -drop table t22; -drop table t23; +GO drop table t24; +GO drop table t25; +GO drop table computed_column_t1; +GO drop table computed_column_t2; +GO \ No newline at end of file diff --git a/contrib/babelfishpg_tsql/sql/test/babel_delete.sql b/test/JDBC/input/babel_delete1.sql similarity index 86% rename from contrib/babelfishpg_tsql/sql/test/babel_delete.sql rename to test/JDBC/input/babel_delete1.sql index e4e33a1fd2..0d14e68030 100644 --- a/contrib/babelfishpg_tsql/sql/test/babel_delete.sql +++ b/test/JDBC/input/babel_delete1.sql @@ -1,20 +1,10 @@ --- --- Tests for DELETE clause --- - -CREATE EXTENSION IF NOT EXISTS "babelfishpg_tsql"; - --- Negative cases when using postgres dialect - -RESET babelfishpg_tsql.sql_dialect; -SHOW babelfishpg_tsql.sql_dialect; - CREATE TABLE delete_test_tbl ( age int, fname char(10), lname char(10), city nchar(20) ); +GO INSERT INTO delete_test_tbl(age, fname, lname, city) VALUES (50, 'fname1', 'lname1', 'london'), (34, 'fname2', 'lname2', 'paris'), @@ -27,32 +17,34 @@ VALUES (50, 'fname1', 'lname1', 'london'), (61, 'fname9', 'lname9', 'shanghai'), (29, 'fname10', 'lname10', 'mumbai'); -SELECT * FROM delete_test_tbl; - -\set ON_ERROR_STOP 0 -DELETE delete_test_tbl; - --- Positive cases when using tsql dialect -SET babelfishpg_tsql.sql_dialect = "tsql"; -SHOW babelfishpg_tsql.sql_dialect; -\set ON_ERROR_STOP 1 +SELECT * FROM delete_test_tbl ORDER BY age DESC, city ASC; +GO -- Prove that a user may delete rows from a table without using the FROM clause -SELECT * FROM delete_test_tbl; +SELECT * FROM delete_test_tbl ORDER BY age DESC, city ASC; +GO -- Test that that WHERE clause can be used without FROM DELETE delete_test_tbl WHERE city='hong kong'; -SELECT * FROM delete_test_tbl; +GO +SELECT * FROM delete_test_tbl ORDER BY age DESC, city ASC; +GO DELETE delete_test_tbl WHERE age > 50; -SELECT * FROM delete_test_tbl; +GO +SELECT * FROM delete_test_tbl ORDER BY age DESC, city ASC; +GO DELETE delete_test_tbl WHERE fname IN ('fname1', 'fname2'); -SELECT * FROM delete_test_tbl; +GO +SELECT * FROM delete_test_tbl ORDER BY age DESC, city ASC; +GO -- Test that DELETE works without any other clauses DELETE delete_test_tbl; -SELECT * FROM delete_test_tbl; +GO +SELECT * FROM delete_test_tbl ORDER BY age DESC, city ASC; +GO -- Test delete for joined table CREATE TABLE delete_test_tbl2 ( @@ -61,6 +53,7 @@ CREATE TABLE delete_test_tbl2 ( lname char(10), city nchar(20) ); +GO INSERT INTO delete_test_tbl2(age, fname, lname, city) VALUES (50, 'fname1', 'lname1', 'london'), @@ -73,11 +66,13 @@ VALUES (50, 'fname1', 'lname1', 'london'), (19, 'fname8', 'lname8', 'hong kong'), (61, 'fname9', 'lname9', 'shanghai'), (29, 'fname10', 'lname10', 'mumbai'); +GO CREATE TABLE delete_test_tbl3 ( year int, lname char(10), ); +GO INSERT INTO delete_test_tbl3(year, lname) VALUES (51, 'lname1'), @@ -85,20 +80,26 @@ VALUES (51, 'lname1'), (25, 'lname8'), (95, 'lname9'), (36, 'lname10'); +GO CREATE TABLE delete_test_tbl4 ( lname char(10), city char(10), ); +GO INSERT INTO delete_test_tbl4(lname, city) VALUES ('lname8','london'), ('lname9','tokyo'), ('lname10','mumbai'); +GO SELECT * FROM delete_test_tbl2 ORDER BY lname; +GO SELECT * FROM delete_test_tbl3 ORDER BY lname; +GO SELECT * FROM delete_test_tbl4 ORDER BY lname; +GO DELETE delete_test_tbl2 @@ -108,6 +109,7 @@ ON t2.lname = t3.lname WHERE year > 50; SELECT * FROM delete_test_tbl2 ORDER BY lname; +GO DELETE delete_test_tbl2 FROM delete_test_tbl3 t3 @@ -116,6 +118,7 @@ ON t2.lname = t3.lname WHERE t3.year < 30 AND t2.age > 40; SELECT * FROM delete_test_tbl2 ORDER BY lname; +GO -- delete with outer join on multiple tables DELETE delete_test_tbl2 @@ -127,6 +130,7 @@ ON t2.lname = t3.lname WHERE t4.city = 'mumbai'; SELECT * FROM delete_test_tbl2 ORDER BY lname; +GO -- delete when target table not shown in JoinExpr DELETE delete_test_tbl2 @@ -136,6 +140,7 @@ ON t3.lname = t4.lname WHERE t4.city = 'mumbai'; SELECT * FROM delete_test_tbl2 ORDER BY lname; +GO -- delete with self join DELETE delete_test_tbl3 @@ -144,6 +149,7 @@ INNER JOIN delete_test_tbl3 t2 on t1.lname = t2.lname; SELECT * FROM delete_test_tbl3 ORDER BY lname; +GO DELETE delete_test_tbl2 FROM delete_test_tbl2 c @@ -154,6 +160,7 @@ JOIN (SELECT lname, city, age from delete_test_tbl2) a on a.city = c.city; SELECT * FROM delete_test_tbl2 ORDER BY lname; +GO DELETE delete_test_tbl4 FROM @@ -163,8 +170,13 @@ JOIN on a.lname = b.lname; SELECT * FROM delete_test_tbl4 ORDER BY lname; +GO DROP TABLE delete_test_tbl; +GO DROP TABLE delete_test_tbl2; +GO DROP TABLE delete_test_tbl3; +GO DROP TABLE delete_test_tbl4; +GO \ No newline at end of file diff --git a/test/JDBC/input/babel_emoji.sql b/test/JDBC/input/babel_emoji.sql new file mode 100644 index 0000000000..99862149d0 --- /dev/null +++ b/test/JDBC/input/babel_emoji.sql @@ -0,0 +1,77 @@ +-- Test SYS.NCHAR, SYS.NVARCHAR and SYS.VARCHAR +-- nchar is already available in postgres dialect +select CAST('£' AS nchar(1)); +GO +-- nvarchar is not available in postgres dialect +select CAST('£' AS nvarchar); +GO + +-- both are available in tsql dialect +select CAST('£' AS nchar(2)); +GO +select CAST('£' AS nvarchar(2)); +GO + +-- multi-byte character doesn't fit in nchar(1) in tsql if it +-- would require a UTF16-surrogate-pair on output +select CAST('£' AS char(1)); -- allowed +GO +select CAST('£' AS sys.nchar(1)); -- allowed +GO +select CAST('£' AS sys.nvarchar(1)); -- allowed +GO +select CAST('£' AS sys.varchar(1)); -- allowed +GO + +select CAST('😀' AS char(1)); -- not allowed TODO: fix BABEL-3543 +GO +select CAST('😀' AS sys.varchar(1)); -- not allowed TODO: fix BABEL-3543 +GO + +-- Check that things work the same in postgres dialect +select CAST('£' AS char(1)); +GO +select CAST('£' AS sys.nchar(1)); +GO +select CAST('£' AS sys.nvarchar(1)); +GO +select CAST('£' AS sys.varchar(1)); +GO +select CAST('😀' AS char(1)); +GO + + +-- test normal create domain works when apg_enable_domain_typmod is enabled +-- set apg_enable_domain_typmod true; +create TYPE varchar3 FROM varchar(3); +select CAST('ab£' AS varchar3); +GO +select CAST('ab😀' AS varchar3); --not allowed TODO: fix BABEL-3543 +GO + +-- don't allow surrogate pairs to exceed max length +select CAST('😀b' AS char(1)); -- not allowed TODO: fix BABEL-3543 +GO +select CAST('😀b' AS sys.varchar(1)); -- not allowed TODO: fix BABEL-3543 +GO + +-- default length of nchar/char is 1 in tsql (and pg) +create table testing_1(col nchar); +GO + +SELECT * FROM information_schema.columns WHERE table_name = 'testing_1' +GO + +-- default length of varchar in tsql is 1 +create table testing_4(col sys.varchar); +insert into testing_4 (col) select '😀'; -- not allowed TODO: fix BABEL-3543 +GO + +select * from testing_4; +GO + + +drop table testing_1; +GO +drop table testing_4; +GO \ No newline at end of file diff --git a/contrib/babelfishpg_tsql/sql/test/babel_function.sql b/test/JDBC/input/babel_function.sql similarity index 50% rename from contrib/babelfishpg_tsql/sql/test/babel_function.sql rename to test/JDBC/input/babel_function.sql index 0fbab970a5..88cb0b0834 100644 --- a/contrib/babelfishpg_tsql/sql/test/babel_function.sql +++ b/test/JDBC/input/babel_function.sql @@ -1,36 +1,16 @@ --- tsql stype create function/procedure is not supported in postgres dialect -CREATE FUNCTION hi_func("@message" varchar(20)) RETURNS VOID AS BEGIN PRINT @message END; -CREATE PROCEDURE hi_proc("@message" varchar(20)) AS BEGIN PRINT @message END; - -set babelfishpg_tsql.sql_dialect = "tsql"; --- it's supported in tsql dialect -CREATE FUNCTION hi_func("@message" varchar(20)) RETURNS VOID AS BEGIN PRINT @message END; -CREATE PROCEDURE hi_proc("@message" varchar(20)) AS BEGIN PRINT @message END; --- PROC is also supported in tsql dialect -create proc proc_1 as print 'Hello World from Babel'; --- BABEL-219 typmod/length of sys.varchar works correctly in procudure parameter -call hi_proc('Hello World'); -call proc_1(); - --- clean up -drop function hi_func; -drop procedure hi_proc; -drop proc proc_1; - --- test executing pltsql function in postgres dialect -reset babelfishpg_tsql.sql_dialect; - -CREATE OR REPLACE FUNCTION test_func() RETURNS int AS $$ +CREATE FUNCTION test_func() +RETURNS INT +AS BEGIN - DECLARE @a int = 1; - RETURN @a + DECLARE @a int = 1; + RETURN @a; END; -$$ LANGUAGE pltsql; +GO -- should be able execute a pltsql function in postgres dialect -show babelfishpg_tsql.sql_dialect; select test_func(); -show babelfishpg_tsql.sql_dialect; +GO + -- test executing pltsql trigger in postgres dialect CREATE TABLE employees( @@ -38,305 +18,401 @@ CREATE TABLE employees( first_name VARCHAR(40) NOT NULL, last_name VARCHAR(40) NOT NULL ); +GO CREATE TABLE employee_audits ( id SERIAL PRIMARY KEY, employee_id INT NOT NULL, last_name VARCHAR(40) NOT NULL ); +GO -CREATE OR REPLACE FUNCTION log_last_name_changes() RETURNS trigger AS $$ -BEGIN - IF NEW.last_name <> OLD.last_name THEN - INSERT INTO employee_audits(employee_id,last_name) - VALUES(OLD.id,OLD.last_name); - END IF; - RETURN NEW; -END; -$$ LANGUAGE plpgsql; - -CREATE TRIGGER last_name_changes -BEFORE UPDATE -ON employees -FOR EACH ROW -EXECUTE PROCEDURE log_last_name_changes(); INSERT INTO employees (first_name, last_name) VALUES ('A', 'B'); INSERT INTO employees (first_name, last_name) VALUES ('C', 'D'); SELECT * FROM employees; -show babelfishpg_tsql.sql_dialect; +GO + UPDATE employees SET last_name = 'E' WHERE ID = 2; -show babelfishpg_tsql.sql_dialect; +GO + SELECT * FROM employees; +GO SELECT * FROM employee_audits; +GO --- test executing a plpgsql function in tsql dialect -CREATE OR REPLACE FUNCTION test_increment(i integer) RETURNS integer AS $$ -BEGIN - RETURN i + "1"; -END; -$$ LANGUAGE plpgsql; +-- cleanup +drop function test_func; +GO +drop table employees; +GO +drop table employee_audits; +GO -CREATE OR REPLACE FUNCTION test_increment1(i integer) RETURNS integer AS $$ -BEGIN - RETURN i + CAST(n'1' AS varchar); -END; -$$ LANGUAGE plpgsql; - --- test that sql_dialect is restored even when the function has error in it -set babelfishpg_tsql.sql_dialect = "tsql"; -show babelfishpg_tsql.sql_dialect; -select test_increment(1); -show babelfishpg_tsql.sql_dialect; -select test_increment1(1); -show babelfishpg_tsql.sql_dialect; - --- test OBJECT_NAME function -select OBJECT_NAME('sys.columns'::regclass::Oid::int); -select OBJECT_NAME('boolin'::regproc::Oid::int); -select OBJECT_NAME('int4'::regtype::Oid::int); -select OBJECT_NAME(1); --- test SYSDATETIME function --- Returns of type datetime2 -select pg_typeof(SYSDATETIME()); --- test GETDATE function --- Returns of type datetime -select pg_typeof(GETDATE()); --- test current_timestamp function -select pg_typeof(current_timestamp); --- test calling with parenthesis, should fail -select current_timestamp(); +select OBJECT_NAME(1); +GO + -- test CONVERT function -- Conversion between varchar and date/time/datetime select CONVERT(varchar(30), CAST('2017-08-25' AS date), 102); +GO select CONVERT(varchar(30), CAST('13:01:59' AS time), 8); +GO select CONVERT(varchar(30), CAST('13:01:59' AS time), 22); +GO select CONVERT(varchar(30), CAST('13:01:59' AS time), 22); +GO select CONVERT(varchar(30), CAST('2017-08-25 13:01:59' AS datetime), 100); +GO select CONVERT(varchar(30), CAST('2017-08-25 13:01:59' AS datetime), 109); +GO select CONVERT(date, '08/25/2017', 101); +GO select CONVERT(time, '12:01:59', 101); +GO select CONVERT(datetime, '2017-08-25 01:01:59PM', 120); +GO select CONVERT(varchar, CONVERT(datetime2(7), '9999-12-31 23:59:59.9999999')); +GO -- Conversion from float to varchar -select CONVERT(varchar(30), 11234561231231.234::float, 0); -select CONVERT(varchar(30), 11234561231231.234::float, 1); -select CONVERT(varchar(30), 11234561231231.234::float, 2); -select CONVERT(varchar(30), 11234561231231.234::float, 3); +select CONVERT(varchar(30), CAST(11234561231231.234 AS float), 1); +GO +select CONVERT(varchar(30), CAST(11234561231231.234 AS float), 2); +GO +select CONVERT(varchar(30), CAST(11234561231231.234 AS float), 3); +GO -- Conversion from money to varchar select CONVERT(varchar(10), CAST(4936.56 AS MONEY), 0); +GO select CONVERT(varchar(10), CAST(4936.56 AS MONEY), 1); +GO select CONVERT(varchar(10), CAST(4936.56 AS MONEY), 2); +GO select CONVERT(varchar(10), CAST(-4936.56 AS MONEY), 0); -- Floor conversion to smallint, int, bigint SELECT CONVERT(int, 99.9); +GO SELECT CONVERT(smallint, 99.9); +GO SELECT CONVERT(bigint, 99.9); +GO SELECT CONVERT(int, -99.9); +GO SELECT CONVERT(int, '99'); +GO SELECT CONVERT(int, CAST(99.9 AS double precision)); +GO SELECT CONVERT(int, CAST(99.9 AS real)); +GO -- test TRY_CONVERT function -- Conversion between different types and varchar select TRY_CONVERT(varchar(30), CAST('2017-08-25' AS date), 102); +GO select TRY_CONVERT(varchar(30), CAST('13:01:59' AS time), 8); +GO select TRY_CONVERT(varchar(30), CAST('13:01:59' AS time), 22); +GO select TRY_CONVERT(varchar(30), CAST('2017-08-25 13:01:59' AS datetime), 109); -select TRY_CONVERT(varchar(30), 11234561231231.234::float, 0); -select TRY_CONVERT(varchar(30), 11234561231231.234::float, 1); +GO +select TRY_CONVERT(varchar(30), CAST('11234561231231.234' AS float), 0); +GO +select TRY_CONVERT(varchar(30), CAST('11234561231231.234'AS float), 1); +GO select TRY_CONVERT(varchar(10), CAST(4936.56 AS MONEY), 0); +GO -- Wrong conversions that return NULL select TRY_CONVERT(date, 123); +GO select TRY_CONVERT(time, 123); +GO select TRY_CONVERT(datetime, 123); +GO select TRY_CONVERT(money, 'asdf'); - --- test PARSE function --- Conversion from string to date/time/datetime -select PARSE('2017-08-25' AS date); -select PARSE('2017-08-25' AS date USING 'Cs-CZ'); -select PARSE('08/25/2017' AS date USING 'en-US'); -select PARSE('25/08/2017' AS date USING 'de-DE'); -select PARSE('13:01:59' AS time); -select PARSE('13:01:59' AS time USING 'en-US'); -select PARSE('13:01:59' AS time USING 'zh-CN'); -select PARSE('2017-08-25 13:01:59' AS datetime); -select PARSE('2017-08-25 13:01:59' AS datetime USING 'zh-CN'); -select PARSE('12:01:59' AS time); -select PARSE('2017-08-25 01:01:59PM' AS datetime); - --- Test if unnecessary culture arg given -select PARSE('123' AS int USING 'de-DE'); +GO -- test TRY_PARSE function -- Expect null return on error -- Conversion from string to date/time/datetime select TRY_PARSE('2017-08-25' AS date); -select TRY_PARSE('2017-08-25' AS date USING 'Cs-CZ'); -select TRY_PARSE('789' AS date USING 'en-US'); -select TRY_PARSE('asdf' AS date USING 'de-DE'); -select TRY_PARSE('13:01:59' AS time); -select TRY_PARSE('asdf' AS time USING 'en-US'); -select TRY_PARSE('13-12-21' AS time USING 'zh-CN'); +GO + select TRY_PARSE('2017-08-25 13:01:59' AS datetime); -select TRY_PARSE('20asdf17' AS datetime USING 'de-DE'); +GO -- Wrong conversions that return NULL select TRY_PARSE('asdf' AS numeric(3,2)); +GO select TRY_PARSE('123' AS datetime2); +GO select TRY_PARSE('asdf' AS MONEY); -select TRY_PARSE('asdf' AS int USING 'de-DE'); +GO -- test serverproperty() function -- invalid property name, should reutnr NULL -select serverproperty(n'invalid property'); +select serverproperty(N'invalid property'); +GO -- valid supported properties -select serverproperty(n'collation'); -select serverproperty(n'collationId'); -select serverproperty(n'IsSingleUser'); -select serverproperty(n'ServerName'); +select serverproperty(N'collation'); +GO +select serverproperty(N'IsSingleUser'); +GO -- test ISDATE function -- test valid argument SELECT ISDATE('12/26/2016'); +GO SELECT ISDATE('12-26-2016'); +GO SELECT ISDATE('12.26.2016'); +GO SELECT ISDATE('2016-12-26 23:30:05.523456'); +GO -- test invalid argument SELECT ISDATE('02/30/2016'); +GO SELECT ISDATE('12/32/2016'); +GO SELECT ISDATE('1995-10-1a'); +GO SELECT ISDATE(NULL); +GO -- test DATEFROMPARTS function -- test valid arguments select datefromparts(2020,12,31); +GO -- test invalid arguments, should fail select datefromparts(2020, 2, 30); +GO select datefromparts(2020, 13, 1); +GO select datefromparts(-4, 3, 150); +GO select datefromparts(10, 55, 10.1); +GO select datefromparts('2020', 55, 100.1); +GO -- test DATETIMEFROMPARTS function -- test valid arguments select datetimefromparts(2016, 12, 26, 23, 30, 5, 32); +GO select datetimefromparts(2016.0, 12, 26, 23, 30, 5, 32); +GO select datetimefromparts(2016.1, 12, 26, 23, 30, 5, 32); +GO select datetimefromparts(2016, 12, 26.99, 23, 30, 5, 32); +GO select datetimefromparts(2016, 12.90, 26, 23, 30, 5, 32); +GO -- test invalid arguments select datetimefromparts(2016, 2, 30, 23, 30, 5, 32); +GO select datetimefromparts(2016, 12, 26, 23, 30, 5); +GO select datetimefromparts(2016, 12, 26, 23, 30, 5, NULL); +GO -- test DATEPART function -- test all valid datepart arguments -select datepart(year, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(yyyy, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(yy, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(quarter, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(qq, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(q, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(month, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(mm, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(m, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(dayofyear, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(dy, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(day, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(dd, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(d, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(week, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(wk, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(ww, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(weekday, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(dw, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(hour, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(hh, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(minute, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(n, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(second, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(ss, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(s, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(millisecond, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(ms, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(microsecond, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(mcs, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(nanosecond, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(ns, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(tzoffset, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(tz, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(iso_week, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(isowk, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datepart(isoww, '2016-12-26 23:30:05.523456+8'::datetimeoffset); +SELECT DATEPART(YEAR, CAST('2016-12-26 23:30:05.523456 -08:00' AS DATETIMEOFFSET)); +GO +select datepart(yyyy, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(yy, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(quarter, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(qq, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(qq, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(q, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(month, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(mm, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(m, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(dayofyear, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(dy, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(day, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(dd, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(d,CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(week, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(wk, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(ww, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(weekday, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(dw, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(hour, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(hh, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(minute, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(n, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(second, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(ss, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(s, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(millisecond, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(ms, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(microsecond, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(mcs,CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(nanosecond, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(ns, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(tzoffset, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(tz, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(iso_week, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(isowk, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datepart(isoww, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO -- test different types of date/time arguments -select datepart(month, '2016-12-26 23:30:05.523'::sys.datetime); -select datepart(quarter, '2016-12-26 23:30:05.523456'::datetime2); -select datepart(hour, '2016-12-26 23:30:05'::smalldatetime); -select datepart(dayofyear, '2016-12-26'::date); -select datepart(second, '04:12:34.876543'::time); +select datepart(month, CAST('2016-12-26 23:30:05.523'AS sys.datetime)); +GO +select datepart(quarter, CAST('2016-12-26 23:30:05.523456'AS datetime2)); +GO +select datepart(hour, CAST('2016-12-26 23:30:05'AS smalldatetime)); +GO +select datepart(dayofyear,CAST('2016-12-26'AS date)); +GO +select datepart(second,CAST ('04:12:34.876543'AS time)); +GO -- test edge cases: try to get datepart that does not exist in the argument select datepart(year, cast('12:10:30.123' as time)); +GO select datepart(yyyy, cast('12:10:30.123' as time)); +GO select datepart(yy, cast('12:10:30.123' as time)); +GO select datepart(quarter, cast('12:10:30.123' as time)); +GO select datepart(qq, cast('12:10:30.123' as time)); +GO select datepart(q, cast('12:10:30.123' as time)); +GO select datepart(month, cast('12:10:30.123' as time)); +GO select datepart(mm, cast('12:10:30.123' as time)); +GO select datepart(m, cast('12:10:30.123' as time)); +GO select datepart(dayofyear, cast('12:10:30.123' as time)); +GO select datepart(dy, cast('12:10:30.123' as time)); +GO select datepart(y, cast('12:10:30.123' as time)); +GO select datepart(day, cast('12:10:30.123' as time)); +GO select datepart(dd, cast('12:10:30.123' as time)); +GO select datepart(d, cast('12:10:30.123' as time)); +GO select datepart(week, cast('12:10:30.123' as time)); +GO select datepart(wk, cast('12:10:30.123' as time)); +GO select datepart(ww, cast('12:10:30.123' as time)); +GO select datepart(weekday, cast('12:10:30.123' as time)); +GO select datepart(dw, cast('12:10:30.123' as time)); +GO select datepart(tzoffset, cast('12:10:30.123' as time)); +GO select datepart(tz, cast('12:10:30.123' as time)); +GO select datepart(iso_week, cast('12:10:30.123' as time)); +GO select datepart(isowk, cast('12:10:30.123' as time)); +GO select datepart(isoww, cast('12:10:30.123' as time)); +GO select datepart(hour, cast('2016-12-26' as date)); +GO select datepart(hh, cast('2016-12-26' as date)); +GO select datepart(minute, cast('2016-12-26' as date)); +GO select datepart(n, cast('2016-12-26' as date)); +GO select datepart(second, cast('2016-12-26' as date)); +GO select datepart(ss, cast('2016-12-26' as date)); +GO select datepart(s, cast('2016-12-26' as date)); +GO select datepart(millisecond, cast('2016-12-26' as date)); +GO select datepart(ms, cast('2016-12-26' as date)); +GO select datepart(microsecond, cast('2016-12-26' as date)); +GO select datepart(mcs, cast('2016-12-26' as date)); +GO select datepart(nanosecond, cast('2016-12-26' as date)); +GO select datepart(ns, cast('2016-12-26' as date)); +GO -- test invalid interval, expect error select datepart(invalid_interval, cast('2016-12-26 23:30:05.523456' as date)); +GO select datepart(invalidinterval, cast('12:10:30.123' as time)); +GO -- test DATENAME function -select datename(year, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datename(dd, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datename(weekday, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datename(dw, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datename(month, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datename(mm, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datename(m, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select datename(isowk, '2016-12-26 23:30:05.523456+8'::datetimeoffset); +SELECT DATENAME(year, CAST('2016-12-26 23:30:05.523456+8' AS datetimeoffset)); +GO +select datename(dd, CAST('2016-12-26 23:30:05.523456+8' AS datetimeoffset)); +GO +select datename(weekday, CAST('2016-12-26 23:30:05.523456+8' AS datetimeoffset)); +GO +select datename(dw, CAST('2016-12-26 23:30:05.523456+8' AS datetimeoffset)); +GO +select datename(month, CAST('2016-12-26 23:30:05.523456+8' AS datetimeoffset)); +GO +select datename(mm, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datename(m, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO +select datename(isowk, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset)); +GO -- test invalid argument, expect error select datename(invalid_interval, cast('2016-12-26 23:30:05.523456' as date)); +GO -- test DATEFIRST option, together DATEPART function -- This shows the return value for the week and weekday datepart for '2007-04-21' for each SET DATEFIRST argument. @@ -350,228 +426,356 @@ select datename(invalid_interval, cast('2016-12-26 23:30:05.523456' as date)); -- 6 17 1 -- 7 16 7 select @@datefirst; +GO set datefirst 1; -select datepart(week, '2007-04-21'::date), datepart(weekday, '2007-04-21'::date); +select datepart(week, CAST('2007-04-21'AS date)), datepart(weekday, CAST('2007-04-21'AS date)); +GO + set datefirst 2; -select datepart(week, '2007-04-21'::date), datepart(weekday, '2007-04-21'::date); +select datepart(week, CAST('2007-04-21'AS date)), datepart(weekday, CAST('2007-04-21'AS date)); +GO set datefirst 3; -select datepart(week, '2007-04-21'::date), datepart(weekday, '2007-04-21'::date); +select datepart(week, CAST('2007-04-21'AS date)), datepart(weekday, CAST('2007-04-21'AS date)); +GO set datefirst 4; -select datepart(week, '2007-04-21'::date), datepart(weekday, '2007-04-21'::date); +select datepart(week, CAST('2007-04-21'AS date)), datepart(weekday, CAST('2007-04-21'AS date)); +GO set datefirst 5; -select datepart(week, '2007-04-21'::date), datepart(weekday, '2007-04-21'::date); +select datepart(week, CAST('2007-04-21'AS date)), datepart(weekday, CAST('2007-04-21'AS date)); +GO set datefirst 6; -select datepart(week, '2007-04-21'::date), datepart(weekday, '2007-04-21'::date); +select datepart(week, CAST('2007-04-21'AS date)), datepart(weekday, CAST('2007-04-21'AS date)); +GO set datefirst 7; -select datepart(week, '2007-04-21'::date), datepart(weekday, '2007-04-21'::date); +select datepart(week, CAST('2007-04-21'AS date)), datepart(weekday, CAST('2007-04-21'AS date)); +GO -- test edge case: date within the week of Jan. 1st -select datepart(week, '2007-01-01'::date), datepart(weekday, '2007-01-01'::date); -select datepart(week, '2007-01-02'::date), datepart(weekday, '2007-01-02'::date); -select datepart(week, '2007-01-03'::date), datepart(weekday, '2007-01-03'::date); -select datepart(week, '2007-01-04'::date), datepart(weekday, '2007-01-04'::date); -select datepart(week, '2007-01-05'::date), datepart(weekday, '2007-01-05'::date); -select datepart(week, '2007-01-06'::date), datepart(weekday, '2007-01-06'::date); +select datepart(week, CAST('2007-01-01'AS date)), datepart(weekday, CAST('2007-01-01'AS date)); +GO +select datepart(week, CAST('2007-01-02'AS date)), datepart(weekday, CAST('2007-01-02'AS date)); +GO +select datepart(week, CAST('2007-01-03'AS date)), datepart(weekday, CAST('2007-01-03'AS date)); +GO +select datepart(week, CAST('2007-01-04'AS date)), datepart(weekday, CAST('2007-01-04'AS date)); +GO +select datepart(week, CAST('2007-01-05'AS date)), datepart(weekday, CAST('2007-01-05'AS date)); +GO +select datepart(week, CAST('2007-01-06'AS date)), datepart(weekday, CAST('2007-01-06'AS date)); +GO -- test edge case: date just outside the week of Jan. 1st -select datepart(week, '2007-01-07'::date), datepart(weekday, '2007-01-07'::date); +select datepart(week, CAST('2007-01-07'AS date)), datepart(weekday, CAST('2007-01-07'AS date)); +GO -- test DATEDIFF function -select datediff(year, '2037-03-01 23:30:05.523'::sys.datetime, '2036-02-28 23:30:05.523'::sys.datetime); -select datediff(quarter, '2037-03-01 23:30:05.523'::sys.datetime, '2036-02-28 23:30:05.523'::sys.datetime); -select datediff(month, '2037-03-01 23:30:05.523'::sys.datetime, '2036-02-28 23:30:05.523'::sys.datetime); -select datediff(dayofyear, '2037-03-01 23:30:05.523'::sys.datetime, '2036-02-28 23:30:05.523'::sys.datetime); -select datediff(day, '2037-03-01 23:30:05.523'::sys.datetime, '2036-02-28 23:30:05.523'::sys.datetime); -select datediff(week, '2037-03-01 23:30:05.523'::sys.datetime, '2036-02-28 23:30:05.523'::sys.datetime); -select datediff(hour, '2037-03-01 23:30:05.523'::sys.datetime, '2036-02-28 23:30:05.523'::sys.datetime); -select datediff(minute, '2037-03-01 23:30:05.523'::sys.datetime, '2036-02-28 23:30:05.523'::sys.datetime); -select datediff(second, '2037-03-01 23:30:05.523'::sys.datetime, '2036-02-28 23:30:05.523'::sys.datetime); -select datediff(millisecond, '2036-02-28 01:23:45.234'::sys.datetime, '2036-02-28 01:23:45.123'::sys.datetime); -select datediff(microsecond, '2036-02-28 01:23:45.234'::sys.datetime, '2036-02-28 01:23:45.123'::sys.datetime); -select datediff(nanosecond, '2036-02-28 01:23:45.234'::sys.datetime, '2036-02-28 01:23:45.123'::sys.datetime); +select datediff(year, CAST('2037-03-01 23:30:05.523'AS sys.datetime), CAST('2036-02-28 23:30:05.523'AS sys.datetime)); +GO +select datediff(quarter, CAST('2037-03-01 23:30:05.523'AS sys.datetime), CAST('2036-02-28 23:30:05.523'AS sys.datetime)); +GO +select datediff(month, CAST('2037-03-01 23:30:05.523'AS sys.datetime), CAST('2036-02-28 23:30:05.523'AS sys.datetime)); +GO +select datediff(dayofyear, CAST('2037-03-01 23:30:05.523'AS sys.datetime), CAST('2036-02-28 23:30:05.523'AS sys.datetime)); +GO +select datediff(day, CAST('2037-03-01 23:30:05.523'AS sys.datetime), CAST('2036-02-28 23:30:05.523'AS sys.datetime)); +GO +select datediff(week,CAST('2037-03-01 23:30:05.523'AS sys.datetime),CAST('2036-02-28 23:30:05.523'AS sys.datetime)); +GO +select datediff(hour, CAST('2037-03-01 23:30:05.523'AS sys.datetime), CAST('2036-02-28 23:30:05.523'AS sys.datetime)); +GO +select datediff(minute,CAST('2037-03-01 23:30:05.523'AS sys.datetime), CAST('2036-02-28 23:30:05.523'AS sys.datetime)); +GO +select datediff(second, CAST('2037-03-01 23:30:05.523'AS sys.datetime), CAST('2036-02-28 23:30:05.523'AS sys.datetime)); +GO +select datediff(millisecond, CAST('2036-02-28 01:23:45.234'AS sys.datetime), CAST('2036-02-28 01:23:45.123'AS sys.datetime)); +GO +select datediff(microsecond, CAST('2036-02-28 01:23:45.234'AS sys.datetime), CAST('2036-02-28 01:23:45.123'AS sys.datetime)); +GO +select datediff(nanosecond, CAST('2036-02-28 01:23:45.234'AS sys.datetime), CAST('2036-02-28 01:23:45.123'AS sys.datetime)); +GO -- test different types of date/time arguments -select datediff(minute, '2016-12-26 23:30:05.523456+8'::datetimeoffset, '2016-12-31 23:30:05.523456+8'::datetimeoffset); -select datediff(quarter, '2016-12-26 23:30:05.523456'::datetime2, '2018-08-31 23:30:05.523456'::datetime2); -select datediff(hour, '2016-12-26 23:30:05'::smalldatetime, '2016-12-28 21:29:05'::smalldatetime); -select datediff(year, '2037-03-01'::date, '2036-02-28'::date); +select datediff(minute, CAST('2016-12-26 23:30:05.523456+8'AS datetimeoffset), CAST('2016-12-31 23:30:05.523456+8'AS datetimeoffset)); +GO +select datediff(quarter,CAST('2016-12-26 23:30:05.523456'AS datetime2), CAST('2018-08-31 23:30:05.523456'AS datetime2)); +GO +select datediff(hour, CAST('2016-12-26 23:30:05'AS smalldatetime), CAST('2016-12-28 21:29:05'AS smalldatetime)); +GO +select datediff(year, CAST('2037-03-01'AS date), CAST('2036-02-28'AS date)); +GO -- test DATEADD function -select dateadd(year, 2, '20060830'::datetime); -select dateadd(quarter, 2, '20060830'::datetime); -select dateadd(month, 1, '20060831'::datetime); -select dateadd(dayofyear, 2, '20060830'::datetime); -select dateadd(day, 2, '20060830'::datetime); -select dateadd(week, 2, '20060830'::datetime); -select dateadd(weekday, 2, '20060830'::datetime); -select dateadd(hour, 2, '20060830'::datetime); -select dateadd(minute, 2, '20060830'::datetime); -select dateadd(second, 2, '20060830'::datetime); -select dateadd(millisecond, 123, '20060830'::datetime); -select dateadd(microsecond, 123456, '20060830'::datetime); -select dateadd(nanosecond, 123456, '20060830'::datetime); +select dateadd(year, 2, '20060830'); +GO +select dateadd(quarter, 2, '20060830'); +GO +select dateadd(month, 1, '20060831'); +GO +select dateadd(dayofyear, 2, '20060830'); +GO +select dateadd(day, 2, '20060830'); +GO +select dateadd(week, 2, '20060830'); +GO +select dateadd(weekday, 2, '20060830'); +GO +select dateadd(hour, 2, '20060830'); +GO +select dateadd(minute, 2, '20060830'); +GO +select dateadd(second, 2, '20060830'); +GO +select dateadd(millisecond, 123, '20060830'); +GO -- test different types of date/time arguments -select dateadd(hour, 2, '23:12:34.876543'::time); -select dateadd(quarter, 3, '2037-03-01'::date); -select dateadd(minute, 70, '2016-12-26 23:30:05.523456+8'::datetimeoffset); -select dateadd(month, 2, '2016-12-26 23:30:05.523456'::datetime2); -select dateadd(second, 56, '2016-12-26 23:30:05'::smalldatetime); +select dateadd(quarter, 3, '2037-03-01'); +GO +select dateadd(second, 56, '2016-12-26 23:30:05'); +GO -- test negative argument -select dateadd(year, -2, '20060830'::datetime); -select dateadd(month, -20, '2016-12-26 23:30:05.523456'::datetime2); -select dateadd(hour, -2, '01:12:34.876543'::time); -select dateadd(minute, -70, '2016-12-26 00:30:05.523456+8'::datetimeoffset); -select dateadd(second, -56, '2016-12-26 00:00:55'::smalldatetime); --- test return type -select pg_typeof(dateadd(hour, -2, '01:12:34.876543'::time)); -select pg_typeof(dateadd(second, -56, '2016-12-26 00:00:55'::smalldatetime)); -select pg_typeof(dateadd(year, -2, '20060830'::datetime)); -select pg_typeof(dateadd(month, -20, '2016-12-26 23:30:05.523456'::datetime2)); -select pg_typeof(dateadd(minute, -70, '2016-12-26 00:30:05.523456+8'::datetimeoffset)); --- test illegal usage -select dateadd(minute, 2, '2037-03-01'::date); -select dateadd(day, 4, '04:12:34.876543'::time); +select dateadd(year, -2, CAST('20060830'AS datetime)); +GO +select dateadd(month, -20, CAST('2016-12-26 23:30:05.523456' AS datetime2)); +GO +select dateadd(hour, -2, CAST('01:12:34.876543' AS time)); +GO +select dateadd(minute, -70, CAST('2016-12-26 00:30:05.523456+8' AS datetimeoffset)); +GO + -- test using variables, instead of constants, for the second parameter create table dateadd_table(a int, b datetime); -insert into dateadd_table values(1, '2020-10-29'::datetime); +GO +insert into dateadd_table values(1, CAST('2020-10-29' AS datetime)); select * from dateadd_table; -update dateadd_table set b = dateadd(dd, a, '2020-10-30'::datetime); +GO +update dateadd_table set b = dateadd(dd, a, CAST('2020-10-30' AS datetime)); +GO select * from dateadd_table; -create procedure dateadd_procedure as -begin - declare @d int = 1 - update dateadd_table set b = dateadd(dd, @d, CAST('2020-10-31' AS datetime)) -end; -call dateadd_procedure(); +GO select * from dateadd_table; +GO -- test CHARINDEX function select CHARINDEX('hello', 'hello world'); +GO select CHARINDEX('hello ', 'hello world'); +GO select CHARINDEX('hello world', 'hello'); +GO -- test NULL input select CHARINDEX(NULL, NULL); +GO select CHARINDEX(NULL, 'string'); +GO select CHARINDEX('pattern', NULL); +GO select CHARINDEX('pattern', 'string', NULL); +GO -- test start_location parameter select CHARINDEX('hello', 'hello world', -1); +GO select CHARINDEX('hello', 'hello world', 0); +GO select CHARINDEX('hello', 'hello world', 1); +GO select CHARINDEX('hello', 'hello world', 2); +GO select CHARINDEX('world', 'hello world', 6); +GO select CHARINDEX('world', 'hello world', 7); +GO select CHARINDEX('world', 'hello world', 8); +GO select CHARINDEX('is', 'This is a string'); +GO select CHARINDEX('is', 'This is a string', 4); +GO -- test STUFF function -select STUFF(n'abcdef', 2, 3, n'ijklmn'); +select STUFF(N'abcdef', 2, 3, N'ijklmn'); +GO select STUFF(N' abcdef', 2, 3, N'ijklmn '); +GO select STUFF(N'abcdef', 2, 3, N' ijklmn '); +GO select STUFF(N'abcdef', 2, 3, N'ijklmn '); +GO -- test corner cases -- when start is negative or zero or longer than expr, return NULL -select STUFF(n'abcdef', -1, 3, n'ijklmn'); -select STUFF(n'abcdef', 0, 3, n'ijklmn'); -select STUFF(n'abcdef', 7, 3, n'ijklmn'); +select STUFF(N'abcdef', -1, 3, N'ijklmn'); +GO +select STUFF(N'abcdef', 0, 3, N'ijklmn'); +GO +select STUFF(N'abcdef', 7, 3, N'ijklmn'); +GO -- when length is negative, return NULL -select STUFF(n'abcdef', 2, -3, n'ijklmn'); +select STUFF(N'abcdef', 2, -3, N'ijklmn'); +GO -- when length is zero, just insert without deleting -select STUFF(n'abcdef', 2, 0, n'ijklmn'); +select STUFF(N'abcdef', 2, 0, N'ijklmn'); +GO -- when length is longer than expr, delete up to the last character in expr -select STUFF(n'abcdef', 2, 7, n'ijklmn'); +select STUFF(N'abcdef', 2, 7, N'ijklmn'); +GO -- when replace_expr is NULL, just delete without inserting -select STUFF(n'abcdef', 2, 3, NULL); +select STUFF(N'abcdef', 2, 3, NULL); +GO -- when argument are type unknown select STUFF('abcdef', 2, 3, 'ijklmn'); -select STUFF('abcdef', 2, 3, n'ijklmn'); -select STUFF(n'abcdef', 2, 3, 'ijklmn'); +GO +select STUFF('abcdef', 2, 3, N'ijklmn'); +GO +select STUFF(N'abcdef', 2, 3, 'ijklmn'); +GO -- when argument are type text SELECT STUFF(CAST('abcdef' as text), 2, 3, CAST('ijklmn' as text)); +GO SELECT STUFF(CAST('abcdef' as text), 2, 3, 'ijklmn'); +GO SELECT STUFF('abcdef', 2, 3, CAST('ijklmn' as text)); +GO -- when argument are type sys.varchar SELECT STUFF(CAST('abcdef' as sys.varchar), 2, 3, CAST('ijklmn' as sys.varchar)); +GO SELECT STUFF('abcdef', 2, 3, CAST('ijklmn' as sys.varchar)); +GO SELECT STUFF(CAST('abcdef' as sys.varchar), 2, 3, 'ijklmn'); +GO -- test ROUND function -- test rounding to the left of decimal point select ROUND(748.58, -1); +GO select ROUND(748.58, -2); +GO select ROUND(748.58, -3); +GO select ROUND(748.58, -4); +GO select ROUND(-648.1234, -2); +GO select ROUND(-648.1234, -3); +GO select ROUND(-1548.1234, -3); +GO select ROUND(-1548.1234, -4); +GO -- test NULL input select ROUND(NULL, -3); +GO select ROUND(748.58, NULL); +GO -- test rounding SELECT ROUND(123.9994, 3); +GO SELECT ROUND(123.9995, 3); +GO SELECT ROUND(123.4545, 2); +GO SELECT ROUND(123.45, -2); +GO -- test function parameter, i.e. truncation when not NULL or 0 SELECT ROUND(150.75, 0); +GO SELECT ROUND(150.75, 0, 0); +GO SELECT ROUND(150.75, 0, NULL); +GO SELECT ROUND(150.75, 0, 1); +GO -- test negative numbers SELECT ROUND(-150.49, 0); +GO SELECT ROUND(-150.75, 0); +GO SELECT ROUND(-150.49, 0, 1); +GO SELECT ROUND(-150.75, 0, 1); +GO -- test SELECT ROUND(col, ) create table t1 (col numeric(4,2)); +GO insert into t1 values (64.24); insert into t1 values (79.65); insert into t1 values (NULL); +GO select ROUND(col, 3) from t1; +GO select ROUND(col, 2) from t1; +GO select ROUND(col, 1) from t1; +GO select ROUND(col, 0) from t1; +GO select ROUND(col, -1) from t1; +GO select ROUND(col, -2) from t1; +GO select ROUND(col, -3) from t1; +GO select ROUND(col, 1, 1) from t1; +GO drop table t1; +GO -- test DAY function select DAY(CAST('2016-12-26 23:30:05.523456+8' AS datetimeoffset)); +GO select DAY(CAST('2016-12-26 23:30:05.523456' AS datetime2)); +GO select DAY(CAST('2016-12-26 23:30:05' AS smalldatetime)); +GO select DAY(CAST('04:12:34.876543' AS time)); +GO select DAY(CAST('2037-03-01' AS date)); +GO select DAY(CAST('2037-03-01 23:30:05.523' AS sys.datetime)); +GO -- test MONTH function -select MONTH('2016-12-26 23:30:05.523456+8'::datetimeoffset); -select MONTH('2016-12-26 23:30:05.523456'::datetime2); -select MONTH('2016-12-26 23:30:05'::smalldatetime); -select MONTH('04:12:34.876543'::time); -select MONTH('2037-03-01'::date); -select MONTH('2037-03-01 23:30:05.523'::sys.datetime); +SELECT MONTH(CAST('2016-12-26 23:30:05.523456-08:00' AS datetimeoffset)); +GO +select MONTH(CAST('2016-12-26 23:30:05.523456' AS datetime2)); +GO +select MONTH(CAST('2016-12-26 23:30:05'AS smalldatetime)); +GO +select MONTH(CAST('04:12:34.876543' AS time)); +GO +select MONTH(CAST('2037-03-01' AS date)); +GO +select MONTH(CAST('2037-03-01 23:30:05.523' AS sys.datetime)); +GO -- test YEAR function -select YEAR('2016-12-26 23:30:05.523456+8'::datetimeoffset); -select YEAR('2016-12-26 23:30:05.523456'::datetime2); -select YEAR('2016-12-26 23:30:05'::smalldatetime); -select YEAR('04:12:34.876543'::time); -select YEAR('2037-03-01'::date); -select YEAR('2037-03-01 23:30:05.523'::sys.datetime); +select YEAR(CAST('2016-12-26 23:30:05.523456+8' AS datetimeoffset)); +GO +select YEAR(CAST('2016-12-26 23:30:05.523456' AS datetime2)); +GO +select YEAR(CAST('2016-12-26 23:30:05' AS smalldatetime)); +GO +select YEAR(CAST('04:12:34.876543' AS time)); +GO +select YEAR(CAST('2037-03-01' AS date)); +GO +select YEAR(CAST('2037-03-01 23:30:05.523' AS sys.datetime)); +GO -- test SPACE function select SPACE(NULL); +GO select SPACE(2); +GO select LEN(SPACE(5)); +GO select DATALENGTH(SPACE(5)); +GO -- test COUNT and COUNT_BIG aggregate function CREATE TABLE t2(a int, b int); +GO INSERT INTO t2 VALUES(1, 100); INSERT INTO t2 VALUES(2, 200); INSERT INTO t2 VALUES(NULL, 300); INSERT INTO t2 VALUES(2, 400); +GO CREATE TABLE t3(a varchar(255), b varchar(255),c int); +GO INSERT INTO t3 VALUES('xyz', 'a',1); INSERT INTO t3 VALUES('xyz', 'b',1); INSERT INTO t3 VALUES('abc', 'a',2); @@ -579,112 +783,114 @@ INSERT INTO t3 VALUES('abc', 'b',2); INSERT INTO t3 VALUES('efg', 'a',3); INSERT INTO t3 VALUES('efg', 'b',3); INSERT INTO t3 VALUES(NULL, NULL, 1); +GO -- Aggregation Function Syntax -- COUNT[_BIG] ( { [ [ ALL | DISTINCT ] expression ] | * } ) -- should return all rows - 4 SELECT COUNT(*) from t2; -SELECT pg_typeof(COUNT(*)) from t2; +GO SELECT COUNT_BIG(*) from t2; -SELECT pg_typeof(COUNT_BIG(*)) from t2; +GO -- should return all rows where a is not NULL - 3 SELECT COUNT(a) from t2; -SELECT pg_typeof(COUNT(a)) from t2; +GO SELECT COUNT_BIG(a) from t2; -SELECT pg_typeof(COUNT_BIG(a)) from t2; +GO -- should return all rows where a is not NULL - 3 SELECT COUNT(ALL a) from t2; -SELECT pg_typeof(COUNT(ALL a)) from t2; +GO SELECT COUNT_BIG(ALL a) from t2; -SELECT pg_typeof(COUNT_BIG(ALL a)) from t2; +GO -- should return all rows where a is distinct - 2 SELECT COUNT(DISTINCT a) from t2; -SELECT pg_typeof(COUNT(DISTINCT a)) from t2; +GO SELECT COUNT_BIG(DISTINCT a) from t2; -SELECT pg_typeof(COUNT_BIG(DISTINCT a)) from t2; +GO -- Analytic Function Syntax -- COUNT[_BIG] ( [ ALL ] { expression | * } ) OVER ( [ ] ) -SELECT pg_typeof(COUNT(*) OVER (PARTITION BY a)) from t2; -SELECT pg_typeof(COUNT_BIG(*) OVER (PARTITION BY a)) from t2; -SELECT pg_typeof(COUNT(a) OVER (PARTITION BY a)) from t2; -SELECT pg_typeof(COUNT_BIG(a) OVER (PARTITION BY a)) from t2; -SELECT pg_typeof(COUNT(ALL a) OVER (PARTITION BY a)) from t2; -SELECT pg_typeof(COUNT_BIG(ALL a) OVER (PARTITION BY a)) from t2; SELECT COUNT(*) from t3; +GO SELECT a, b, COUNT(*) OVER () from t3; +GO -- The result for order by is different in sql server because we have -- an ordering issue for null type (JIRA: BABEL-788) SELECT a, b, COUNT(*) OVER (ORDER BY a) from t3; +GO SELECT a, b, COUNT(*) OVER (ORDER BY a DESC) from t3; +GO SELECT a, b, COUNT(*) OVER(PARTITION BY a) from t3; +GO SELECT a, b, COUNT(*) OVER(PARTITION BY a ORDER BY b) from t3; +GO SELECT a, b, COUNT(*) OVER(PARTITION BY a ORDER BY b ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING) from t3; +GO SELECT COUNT_BIG(*) from t3; +GO SELECT a, b, COUNT_BIG(*) OVER () from t3; +GO SELECT a, b, COUNT_BIG(*) OVER (ORDER BY a) from t3; +GO SELECT a, b, COUNT_BIG(*) OVER (ORDER BY a DESC) from t3; +GO SELECT a, b, COUNT_BIG(*) OVER(PARTITION BY a) from t3; +GO SELECT a, b, COUNT_BIG(*) OVER(PARTITION BY a ORDER BY b) from t3; +GO SELECT a, b, COUNT_BIG(*) OVER(PARTITION BY a ORDER BY b ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING) from t3; +GO -- COUNT(*) takes no parameters and does not support the use of DISTINC, expect error -SELECT COUNT(DISTINCT *) from t3; -SELECT COUNT(ALL *) from t3; DROP TABLE t2; +GO DROP TABLE t3; +GO -- clean up -drop function test_func; -drop table employees; -drop table employee_audits; -drop function log_last_name_changes; -drop function test_increment; -drop function test_increment1; drop table dateadd_table; -drop procedure dateadd_procedure; +GO -- test inline table-valued functions -- simple case create function itvf1 (@number int) returns table as return (select 1 as a, 2 as b); +GO select * from itvf1(5); +GO -- should fail because column names are not specified create function itvf2 (@number int) returns table as return (select 1, 2); +GO -- select from a table create table example_table(name text, age int); +GO insert into example_table values('hello', 3); +GO -- should have 'a' and 'b' as result column names create function itvf3 (@number int) returns table as return (select name as a, age as b from example_table); +GO select * from itvf3(5); +GO -- test returning multiple rows insert into example_table values('hello1', 4); insert into example_table values('hello2', 5); insert into example_table values('hello3', 6); select * from itvf3(5); +GO --- invoke a function -create function itvf4 (@number int) returns table as -return (select sys.serverproperty(N'collation') as property1, sys.serverproperty(N'IsSingleUser') as property2); -select * from itvf4(5); - --- case where the return table has only one column - Postgres considers these as --- scalar functions -create or replace function itvf5 (@number int) returns table as return (select 1 as a); -select * from itvf5(5); -create or replace function itvf6 (@number int) returns table as -return (select sys.serverproperty(N'collation') as property); -select * from itvf6(5); -- complex queries with use of function parameter create table id_name(id int, name text); +GO insert into id_name values(1001, 'adam'); insert into id_name values(1002, 'bob'); insert into id_name values(1003, 'chaz'); insert into id_name values(1004, 'dave'); insert into id_name values(1005, 'ed'); +GO create table id_score(id int, score int); +GO insert into id_score values(1001, 90); insert into id_score values(1001, 70); insert into id_score values(1002, 90); @@ -695,24 +901,15 @@ insert into id_score values(1004, 80); insert into id_score values(1004, 60); insert into id_score values(1005, 80); insert into id_score values(1005, 100); +GO -create function itvf7 (@number int) returns table as return ( -select n.id, n.name as first_name, sum(s.score) as total_score -from id_name as n -join id_score as s -on n.id = s.id -where s.id <= @number -group by n.id, n.name -order by n.id -); - -select * from itvf7(1004); -- test inline table-valued function with table-valued parameter create type tableType as table( a text not null, b int primary key, c int); +GO create function itvf8 (@number int, @tableVar tableType READONLY) returns table as return ( select n.id, n.name as first_name, sum(s.score) as total_score @@ -723,6 +920,7 @@ where s.id <= @number and s.id in (select c from @tableVar) group by n.id, n.name order by n.id ); +GO create procedure itvf8_proc as begin @@ -731,85 +929,42 @@ begin insert into @tableVariable values('hello2', 2, 1002) select * from itvf8(1004, @tableVariable) end; +GO -call itvf8_proc(); +EXEC itvf8_proc; +GO -- test using parameter in projection list create function itvf9(@number int) returns table as return ( select @number as a from id_name ); +GO select * from itvf9(1); - --- test invalid ITVFs --- function does not have RETURN QUERY -create function itvf10(@number int) returns table as BEGIN select * from id_name END; --- function has more than one RETURN QUERY -create function itvf11(@number int) returns table as -BEGIN - return select * from id_name - return select id from id_name -END; - --- test creating ITVF in a transaction and rollback - should still work as --- normal despite the function validator's modification of the pg_proc entry -begin transaction; -create function itvf12(@number int) returns table as return ( -select @number as a from id_name -); -rollback; -select * from itvf12(1); - --- "AS" keyword is optional in TSQL function -\tsql on -create function babel651_f() returns int -begin - return 1 -end -go -create table babel651_t(a int); -go -create function babel651_itvf() returns table - return (select * from babel651_t) -go -create function babel651_mstvf(@i int) returns @tableVar table -( - a text not null -) -begin - insert into @tableVar values('hello1'); -end; -go - -select babel651_f(); -go -select * from babel651_itvf(); -go -select * from babel651_mstvf(1); -go -\tsql off +GO -- clean up drop function itvf1; +GO drop table example_table; +GO drop function itvf3; -drop function itvf4; -drop function itvf5; -drop function itvf6; +GO drop table id_name; +GO drop table id_score; -drop function itvf7; +GO drop procedure itvf8_proc; +GO drop function itvf8; +GO drop type tableType; +GO drop function itvf9; -drop table babel651_t; -drop function babel651_f; -drop function babel651_itvf; -drop function babel651_mstvf; +GO + -- test RETURN not followed by a semicolon -\tsql on create function test_return1(@stringToSplit VARCHAR(MAX)) RETURNS @returnList TABLE([Name] [nvarchar] (500)) AS @@ -866,5 +1021,4 @@ GO select * from test_return4(2); GO drop function test_return4; -GO -\tsql off +GO \ No newline at end of file diff --git a/test/JDBC/input/babel_like.sql b/test/JDBC/input/babel_like.sql new file mode 100644 index 0000000000..f1d99a5900 --- /dev/null +++ b/test/JDBC/input/babel_like.sql @@ -0,0 +1,20 @@ +select relname from pg_class where relname like NULL; +GO +select relname from pg_class where relname like ''; +GO +select relname from pg_class where relname like 'pg\[1:9\]class'; +GO + +select relname from pg_class where relname like 'pg*[1:9*]class' escape '*'; +GO + +select relname from pg_class where relname like NULL; +GO +select relname from pg_class where relname like ''; +GO +select relname from pg_class where relname like 'pg\[1:9\]class'; +GO + + +select relname from pg_class where relname like 'pg*[1:9*]class' escape '*'; +GO diff --git a/test/JDBC/input/babel_select_distinct_top.sql b/test/JDBC/input/babel_select_distinct_top.sql new file mode 100644 index 0000000000..5277efccb7 --- /dev/null +++ b/test/JDBC/input/babel_select_distinct_top.sql @@ -0,0 +1,19 @@ +create table babel_select_distinct_top (a int); +GO +insert into babel_select_distinct_top values (3), (1), (2), (2), (1); +GO +select * from babel_select_distinct_top ORDER BY a ASC; +GO +select distinct a from babel_select_distinct_top order by a; +GO +select distinct top(2) a from babel_select_distinct_top order by a; +GO +select * from (select distinct top(2) a from babel_select_distinct_top order by a) b; +GO +select (select distinct top(1) a from babel_select_distinct_top order by a); +GO +select 'foo' where (select distinct top(1) a from babel_select_distinct_top order by a) = 1; +GO +-- Clean up +drop table babel_select_distinct_top; +GO \ No newline at end of file diff --git a/test/JDBC/input/babel_set_command.sql b/test/JDBC/input/babel_set_command.sql new file mode 100644 index 0000000000..8575e8b8ee --- /dev/null +++ b/test/JDBC/input/babel_set_command.sql @@ -0,0 +1,38 @@ +-- Simple SET +DECLARE @lc_messages VARCHAR(20); +SELECT @lc_messages = 'fr_FR.utf8'; +SELECT @lc_messages; +GO + +-- Inside transaction with commit +BEGIN TRANSACTION; + DECLARE @lc_messages VARCHAR(20); +SELECT @lc_messages = 'fr_FR.utf8'; +COMMIT TRANSACTION; +SELECT @lc_messages; +SET @lc_messages = NULL; +GO +-- Inside transaction with rollback +DECLARE @lc_messages VARCHAR(20); +SET @lc_messages = 'fr_FR.utf8'; +BEGIN TRANSACTION; + SET @lc_messages = 'fr_FR.utf8'; +ROLLBACK TRANSACTION; +SELECT @lc_messages; +SET @lc_messages = NULL; +GO + +-- Inside transaction with rollback to savepoint +DECLARE @lc_messages VARCHAR(20); +SET @lc_messages = 'en_GB.utf8'; +BEGIN TRANSACTION; + SET @lc_messages = 'en_GB.utf8'; + SAVE TRANSACTION SP1; + SET @lc_messages = 'fr_FR.utf8'; + SELECT @lc_messages; + ROLLBACK TRANSACTION SP1; + SELECT @lc_messages; +ROLLBACK TRANSACTION; +SELECT @lc_messages; +SET @lc_messages = NULL; +GO \ No newline at end of file diff --git a/contrib/babelfishpg_tsql/expected/test/babel_table_type.out b/test/JDBC/input/babel_table_type.sql similarity index 57% rename from contrib/babelfishpg_tsql/expected/test/babel_table_type.out rename to test/JDBC/input/babel_table_type.sql index 4e0d2d8f22..32a4d30ab1 100644 --- a/contrib/babelfishpg_tsql/expected/test/babel_table_type.out +++ b/test/JDBC/input/babel_table_type.sql @@ -1,85 +1,28 @@ -CREATE USER my_test_user; -GRANT CREATE ON DATABASE contrib_regression TO my_test_user; -GRANT CREATE ON SCHEMA public TO PUBLIC; -SET SESSION AUTHORIZATION my_test_user; -- table type is only supported in tsql dialect CREATE TYPE tableType AS table( a text not null, b int primary key, c int); -ERROR: syntax error at or near "table" -LINE 1: CREATE TYPE tableType AS table( - ^ -set babelfishpg_tsql.sql_dialect = 'tsql'; -\tsql ON --- table type supports all CREATE TABLE element lists -CREATE TYPE tableType AS table( - a text not null, - b int primary key, - c int); -GO + -- a table with the same name is created select * from tableType; GO - a | b | c ----+---+--- -(0 rows) --- create type with same name, should fail -CREATE TYPE tableType as (d int, e int); -GO -ERROR: type "tabletype" already exists --- create table with same name, should succeed --- TODO: BABEL-689: Postgres doesn't support this yet, because CREATE TABLE will automatically --- create a composite type as well, which will cause name collision -CREATE TABLE tableType(d int, e int); -GO -ERROR: relation "tabletype" already exists -- dropping the table should fail, as it depends on the table type DROP TABLE tableType; GO -ERROR: cannot drop table tabletype because type tabletype requires it -HINT: You can drop type tabletype instead. + -- dropping the table type should drop the table as well DROP TYPE tableType; GO -SELECT * FROM tableType; -GO -ERROR: relation "tabletype" does not exist -LINE 1: SELECT * FROM tableType; - ^ --- creating index (other than primary and unique keys) during table type creation is not --- yet supported --- TODO: BABEL-688: fully support TSQL CREATE TABLE syntax -CREATE TYPE tableType AS table( - a text not null, - b int primary key, - c int, - d int index idx1 nonclustered, - index idx2(c), - index idx3(e), - e varchar); -GO -ERROR: syntax error at or near "index" -LINE 5: d int index idx1 nonclustered, - ^ --- test dotted prefixes of the table type name --- allowed to have one dotted prefix -CREATE TYPE public.tableType AS table(a int, b int); -GO -DROP TYPE public.tableType; -GO --- not allowed to have more than one dotted prefix -CREATE TYPE postgres.public.tableType AS table(a int, b int); -GO -ERROR: The type name 'postgres.public.tabletype' contains more than the maximum number of prefixes. The maximum is 1. -LINE 1: CREATE TYPE postgres.public.tableType AS table(a int, b int)... - ^ + + CREATE TYPE tableType AS table( a text not null, b int primary key, c int); GO + -- test declaring variables with table type create procedure table_var_procedure as begin @@ -89,15 +32,11 @@ begin select count(*) from @b; end; GO -CALL table_var_procedure(); +EXEC table_var_procedure; GO - count -------- - 1 -(1 row) - DROP PROCEDURE table_var_procedure; GO + -- test declaring table variable without table type, and doing DMLs create procedure table_var_procedure as begin @@ -109,15 +48,11 @@ begin select * from @tableVar; end; GO -CALL table_var_procedure(); +EXEC table_var_procedure; GO - a | b ----+------ - 1 | 1000 -(1 row) - DROP PROCEDURE table_var_procedure; GO + -- test declaring table variable with whitespace before column definition create procedure table_var_procedure as begin @@ -129,40 +64,12 @@ begin select * from @tableVar1 t1 join @tableVar2 t2 on t1.a = t2.c; end; GO -CALL table_var_procedure(); +EXEC table_var_procedure; GO - a | b | c | d ----+-----+---+--- - 1 | 100 | 1 | a -(1 row) - DROP PROCEDURE table_var_procedure; GO --- test MERGE on table variables --- TODO: BABEL-877 Support MERGE -/* -create procedure merge_proc as -begin - declare @tv1 table(a int); - insert into @tv1 values (200); - - declare @tv2 table(b int); - insert into @tv2 values (100); - insert into @tv2 values (200); - merge into @tv1 using @tv2 on a=b - when not matched then insert (a) values(b) - when matched then update set a = a + b; - select * from @tv1; -end; -GO -CALL merge_proc(); -GO --- result should have two rows, 400 and 100. -DROP PROCEDURE merge_proc; -GO -*/ -- test declaring a variable whose name is already used - should throw error create procedure dup_var_name_procedure as begin @@ -170,10 +77,9 @@ begin declare @a tableType; end; GO -ERROR: duplicate declaration -CONTEXT: compilation of PL/tsql function "dup_var_name_procedure" near line 0 + -- test declaring a variable whose name is already used as table name - should work -create table @test_table (d int); +create table test_table (d int); GO create procedure dup_var_name_procedure as begin @@ -182,17 +88,13 @@ begin select * from @test_table; end; GO -call dup_var_name_procedure(); +EXEC dup_var_name_procedure; GO - a | b | c ---------+---+----- - hello1 | 1 | 100 -(1 row) - drop procedure dup_var_name_procedure; GO -drop table @test_table; +drop table test_table; GO + -- test assigning to table variables, should not be allowed create table test_table(a int, b int); GO @@ -204,47 +106,7 @@ begin set @tableVar = test_table; end; GO -ERROR: unrecognized dtype: 3 -LINE 3: set @tableVar = test_table; - ^ -QUERY: begin - declare @tableVar table (a int, b int); - set @tableVar = test_table; -end; --- test selecting into table variables, should not be allowed -create procedure select_into_proc as -begin - declare @tableVar table (a int, b int); - select * into @tableVar from test_table; -end; -GO -ERROR: syntax error near '@tableVar' at line 3 and character position 15 -LINE 3: select * into @tableVar from test_table; - ^ -QUERY: begin - declare @tableVar table (a int, b int); - select * into @tableVar from test_table; -end; - --- test truncating table variables, should not be allowed -create procedure truncate_proc as -begin - declare @tableVar table (a int, b int); - insert into @tableVar values(1, 2); - truncate table @tableVar; - select * from @tableVar; -end; -GO -ERROR: syntax error near '@tableVar' at line 4 and character position 16 -LINE 4: truncate table @tableVar; - ^ -QUERY: begin - declare @tableVar table (a int, b int); - insert into @tableVar values(1, 2); - truncate table @tableVar; - select * from @tableVar; -end; -- test JOIN on table variables, on both sides create procedure join_proc1 as @@ -254,14 +116,11 @@ begin select * from test_table t inner join @tableVar tv on t.a = tv.a; end; GO -CALL join_proc1(); +EXEC join_proc1; GO - a | b | a | b | c ----+----+---+---+--- - 1 | 10 | 1 | 2 | 3 -(1 row) - DROP PROCEDURE join_proc1; +GO + create procedure join_proc2 as begin declare @tableVar table (a int, b int, c int); @@ -269,31 +128,11 @@ begin select * from @tableVar tv inner join test_table t on tv.a = t.a; end; GO -CALL join_proc2(); +EXEC join_proc2; GO - a | b | c | a | b ----+---+---+---+---- - 1 | 2 | 3 | 1 | 10 -(1 row) - DROP PROCEDURE join_proc2; GO --- test altering table variables, should not be allowed -create procedure alter_proc as -begin - declare @tableVar table (a int); - alter table @tableVar add b int; - select * from @tableVar; -end; -GO -ERROR: syntax error near '@tableVar' at line 3 and character position 13 -LINE 3: alter table @tableVar add b int; - ^ -QUERY: begin - declare @tableVar table (a int); - alter table @tableVar add b int; - select * from @tableVar; -end; + -- test using the same variables as source and target create procedure source_target_proc as @@ -306,37 +145,11 @@ begin select * from @tv; end; GO -CALL source_target_proc(); -GO - a ---- - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 -(8 rows) - -DROP PROCEDURE source_target_proc; +EXEC source_target_proc; GO --- test multiple '@' characters in table variable name --- TODO: BABEL-476 Support variable name with multiple '@' characters -/* -create procedure nameing_proc as -begin - declare @@@tv@1@@@ as table(a int); - insert @@@tv@1@@@ values(1); - select * from @@@tv@1@@@; -end; -GO -CALL naming_proc(); -GO -DROP PROCEDURE naming_proc; +DROP PROCEDURE source_target_proc; GO -*/ + -- test nested functions using table variables with the same name, each should -- have its own variable create function inner_func() returns int as @@ -362,13 +175,9 @@ end; GO select outer_func(); GO - outer_func ------------- - 2 -(1 row) - DROP FUNCTION outer_func; GO + -- test calling a function with table variables in a loop, each should have its -- own variable create procedure loop_func_proc as @@ -385,17 +194,14 @@ begin select @result; end; GO -call loop_func_proc(); +EXEC loop_func_proc; GO - @result ---------- - 5 -(1 row) - DROP PROCEDURE loop_func_proc; GO + DROP FUNCTION inner_func; GO + -- test declaring the same variable in a loop - should not have any error, and -- should all refer to the same underlying table create procedure loop_proc as @@ -416,15 +222,11 @@ begin select @result; end; GO -call loop_proc() +EXEC loop_proc GO - @result ---------- - 15 -(1 row) - DROP PROCEDURE loop_proc; GO + -- test using table variables in CTE, both in with clause and in main query create procedure cte_proc as begin @@ -436,15 +238,11 @@ begin WITH t1 (a) AS (SELECT a FROM @tablevar1) SELECT * FROM @tablevar2 t2 JOIN t1 ON t2.a = t1.a; end; GO -call cte_proc() +EXEC cte_proc GO - a | b | c | a ---------+---+-----+-------- - hello1 | 1 | 100 | hello1 -(1 row) - DROP PROCEDURE cte_proc; GO + -- BABEL-894: test PLtsql_expr->tsql_tablevars is initialized to NIL so that it -- won't cause seg faults when looked up during execution. One place missed -- earlier is when parsing the SET command. @@ -453,10 +251,11 @@ begin set datefirst 7; end; GO -call pl_set_proc() +EXEC pl_set_proc GO DROP PROCEDURE pl_set_proc; GO + -- test select from multiple table variables create procedure select_multi_tablevars as begin @@ -468,16 +267,11 @@ begin select * from @tablevar1, @tablevar2; end; GO -call select_multi_tablevars() +EXEC select_multi_tablevars GO - a | b | c | a | b | c ---------+---+-----+--------+---+----- - hello1 | 1 | 100 | hello1 | 1 | 100 - hello1 | 1 | 100 | hello2 | 2 | 200 -(2 rows) - DROP PROCEDURE select_multi_tablevars; GO + -- test select from table and table variable create procedure select_table_tablevar as begin @@ -486,15 +280,11 @@ begin select * from test_table, @tablevar; end; GO -call select_table_tablevar() +EXEC select_table_tablevar GO - a | b | a | b | c ----+----+--------+---+----- - 1 | 10 | hello1 | 1 | 100 -(1 row) - DROP PROCEDURE select_table_tablevar; GO + -- test table-valued parameters -- if no READONLY behind table-valued param: report error create function error_func(@tableVar tableType) returns int as @@ -502,14 +292,12 @@ begin return 1; end GO -ERROR: The table-valued parameter "@tablevar" must be declared with the READONLY option. -- if READONLY on other param type: report error create function error_func(@a int, @b int READONLY) returns int as begin return 1; end GO -ERROR: The parameter "@b" can not be declared READONLY since it is not a table-valued parameter. -- correct syntax create function tvp_func(@tableVar tableType READONLY) returns int as begin @@ -520,22 +308,6 @@ end GO -- test passing in a table variable whose type is different from what the function wants -- TODO: BABEL-899: error message should be "Operand type clash: table is incompatible with tableType" -create procedure error_proc as -begin - declare @tableVar as table (a text, b int, c int); - insert into @tableVar values('hello1', 1, 100); - select tvp_func(@tableVar); -end; -GO -call error_proc() -GO -ERROR: The function tvp_func is found but cannot be used. Possibly due to datatype mismatch and implicit casting is not allowed. -LINE 1: select tvp_func("@tableVar") - ^ -QUERY: select tvp_func("@tableVar") -CONTEXT: PL/tsql function error_proc() line 4 at SQL statement -DROP PROCEDURE error_proc; -GO create procedure tvp_proc as begin declare @tableVar tableType; @@ -543,13 +315,8 @@ begin select tvp_func(@tableVar); end; GO -call tvp_proc() +EXEC tvp_proc GO - tvp_func ----------- - 1 -(1 row) - DROP PROCEDURE tvp_proc; GO DROP FUNCTION tvp_func; @@ -575,19 +342,15 @@ begin select multi_tvp_func(@v1, @v2); end; GO -call multi_tvp_proc() +EXEC multi_tvp_proc GO - multi_tvp_func ----------------- - 1 -(1 row) - DROP PROCEDURE multi_tvp_proc; GO DROP FUNCTION multi_tvp_func; GO DROP TYPE tableType1; GO + -- test multi-statement table-valued functions create function mstvf(@i int) returns @tableVar table ( @@ -603,12 +366,6 @@ end; GO select * from mstvf(1); GO - a | b | c ---------+---+----- - hello1 | 1 | 100 - hello2 | 2 | 200 -(2 rows) - DROP FUNCTION mstvf; GO -- test mstvf whose return table has only one column @@ -623,11 +380,6 @@ end; GO select * from mstvf_one_col(1); GO - a --------- - hello1 -(1 row) - DROP FUNCTION mstvf_one_col; GO -- test mstvf whose return table has only one column @@ -643,11 +395,6 @@ end; GO select * from mstvf_return(1); GO - a --------- - hello2 -(1 row) - DROP FUNCTION mstvf_return; GO -- test mstvf's with same names in different schemas @@ -675,18 +422,8 @@ end; GO select * from mstvf_schema(1); GO - name ------------ - test_name -(1 row) - select * from test_schema.mstvf_schema(1); GO - name1 ------------- - test_name1 -(1 row) - drop function mstvf_schema; GO drop function test_schema.mstvf_schema; @@ -709,22 +446,11 @@ end; GO select * from mstvf_constraints(1); GO - name | id ------------+---- - test_name | 1 -(1 row) - drop function mstvf_constraints; GO + -- cleanup DROP TYPE tableType; GO DROP TABLE test_table; -GO -\tsql OFF -reset babelfishpg_tsql.sql_dialect; -RESET SESSION AUTHORIZATION; --- if we are able to drop the user, then it means that all the underlying tables --- of table variables have been dropped because they depend on the user. -REVOKE CREATE ON DATABASE contrib_regression FROM my_test_user; -DROP USER my_test_user; +GO \ No newline at end of file diff --git a/contrib/babelfishpg_tsql/sql/test/babel_transaction.sql b/test/JDBC/input/babel_transaction.sql similarity index 81% rename from contrib/babelfishpg_tsql/sql/test/babel_transaction.sql rename to test/JDBC/input/babel_transaction.sql index dfa0264ca5..c04554fb7a 100644 --- a/contrib/babelfishpg_tsql/sql/test/babel_transaction.sql +++ b/test/JDBC/input/babel_transaction.sql @@ -1,152 +1,147 @@ -SET babelfishpg_tsql.sql_dialect = 'tsql'; - --- setup -drop table TxnTable; create table TxnTable(c1 int); +GO -- Begin transaction -> commit transaction begin transaction; select @@trancount; +GO begin transaction; select @@trancount; -set transaction isolation level read committed; -show transaction_isolation; -show default_transaction_isolation; +GO insert into TxnTable values(1); commit transaction; select @@trancount; +GO commit transaction; select @@trancount; +GO select c1 from TxnTable; +GO -- Begin transaction -> rollback transaction begin transaction; insert into TxnTable values(2); rollback transaction; select c1 from TxnTable; +GO -- Begin tran -> commit tran begin tran; insert into TxnTable values(2); commit tran; select c1 from TxnTable; +GO -- Begin tran -> rollback tran begin tran; select @@trancount; begin tran; set transaction isolation level read uncommitted; -show transaction_isolation; -show default_transaction_isolation; insert into TxnTable values(3); select @@trancount; rollback tran; select @@trancount; select c1 from TxnTable; +GO -set transaction isolation level repeatable read; -show transaction_isolation; -show default_transaction_isolation; -- Begin transaction -> commit begin transaction; insert into TxnTable values(4); commit; select c1 from TxnTable; +GO -- Begin transaction -> commit work begin transaction; insert into TxnTable values(5); commit work; select c1 from TxnTable; +GO -- Begin transaction -> rollback begin transaction; insert into TxnTable values(6); rollback; select c1 from TxnTable; +GO -- Begin transaction -> rollback work begin transaction; insert into TxnTable values(7); rollback work; select c1 from TxnTable; +GO -- Begin transaction name -> commit transaction name begin transaction txn1; insert into TxnTable values(8); commit transaction txn1; select c1 from TxnTable; +GO -- Begin transaction name -> rollback transaction name begin transaction txn1; insert into TxnTable values(9); rollback transaction txn1; select c1 from TxnTable; +GO -- Begin tran name -> commit tran name begin tran txn1; insert into TxnTable values(10); commit tran txn1; select c1 from TxnTable; +Go -- Begin tran name -> rollback tran name begin tran txn1; insert into TxnTable values(10); rollback tran txn1; select c1 from TxnTable; - +GO truncate table TxnTable; +GO -- save tran name -> rollback tran name -set transaction isolation level snapshot; -show transaction_isolation; -show default_transaction_isolation; begin transaction txn1; insert into TxnTable values(1); save transaction sp1; select @@trancount; +GO insert into TxnTable values(2); save tran sp2; insert into TxnTable values(3); save tran sp2; select @@trancount; +GO insert into TxnTable values(4); select c1 from TxnTable; +GO rollback tran sp2; select @@trancount; +GO select c1 from TxnTable; +GO rollback tran sp2; select @@trancount; +GO select c1 from TxnTable; +GO rollback tran sp1; select @@trancount; +GO select c1 from TxnTable; +GO rollback tran txn1; select @@trancount; +GO select c1 from TxnTable; - --- begin transaction name -> save transaction name -> rollback to first --- savepoint -begin transaction txn1; -insert into TxnTable values(1); -save transaction sp1; -insert into TxnTable values(2); -save transaction sp2; -insert into TxnTable values(3); -save transaction sp3; -insert into TxnTable values(4); -rollback tran sp1; -rollback tran sp1; -rollback tran; -select c1 from TxnTable; +GO -- begin transaction name -> save transaction name -> rollback tran name -- Rollback whole transaction -set transaction isolation level serializable; -show transaction_isolation; -show default_transaction_isolation; begin transaction txn1; insert into TxnTable values(1); save transaction sp1; @@ -155,9 +150,12 @@ insert into TxnTable values(2); save transaction sp1; insert into TxnTable values(3); select @@trancount; +GO rollback tran txn1; select @@trancount; +GO select c1 from TxnTable; +GO -- begin transaction -> save transaction name -> rollback to savepoint -- commit transaction @@ -166,9 +164,11 @@ insert into TxnTable values(1); save transaction sp1; insert into TxnTable values(2); select c1 from TxnTable; +GO rollback tran sp1; commit transaction; select c1 from TxnTable; +GO -- begin transaction -> save transaction name -> rollback to savepoint -- save transaction name -> commit transaction @@ -221,4 +221,4 @@ rollback transaction txn2; rollback; drop table TxnTable; -reset babelfish_pg_tsql.sql_dialect; +reset babelfish_pg_tsql.sql_dialect; \ No newline at end of file diff --git a/contrib/babelfishpg_tsql/sql/test/babel_typecode.sql b/test/JDBC/input/babel_typecode.sql similarity index 75% rename from contrib/babelfishpg_tsql/sql/test/babel_typecode.sql rename to test/JDBC/input/babel_typecode.sql index e9e3cf6357..5ccce4e085 100644 --- a/contrib/babelfishpg_tsql/sql/test/babel_typecode.sql +++ b/test/JDBC/input/babel_typecode.sql @@ -1,4 +1,3 @@ -SET babelfishpg_tsql.sql_dialect = 'tsql'; - -- test typecode list sys table -SELECT pg_namespace, pg_typname, tsql_typname, type_family_priority, priority, sql_variant_hdr_size FROM sys.babelfish_typecode_list(); +SELECT pg_namespace, pg_typname, tsql_typname, type_family_priority, priority, sql_variant_hdr_size FROM sys.babelfish_typecode_list() ORDER BY priority ASC; +GO \ No newline at end of file diff --git a/contrib/babelfishpg_tsql/sql/test/babel_uniqueidentifier.sql b/test/JDBC/input/babel_uniqueidentifier.sql similarity index 81% rename from contrib/babelfishpg_tsql/sql/test/babel_uniqueidentifier.sql rename to test/JDBC/input/babel_uniqueidentifier.sql index b7d385de1d..90fd42e1d9 100644 --- a/contrib/babelfishpg_tsql/sql/test/babel_uniqueidentifier.sql +++ b/test/JDBC/input/babel_uniqueidentifier.sql @@ -1,82 +1,142 @@ -SET babelfishpg_tsql.sql_dialect = 'tsql'; - create table t1 (a uniqueidentifier, b uniqueidentifier, c uniqueidentifier, primary key(a)); +GO + insert into t1(a) values ('6F9619FF-8B86-D011-B42D-00C04FC964FF'); +GO + insert into t1(a) values ('6F9619FF-8B86-D011-B42D-00C04FC964FF'); -- trigger error +GO + select * from t1; +GO insert into t1 values ('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', newid(), newid()); +GO -explain (costs off) select * from t1 where a = '6F9619FF-8B86-D011-B42D-00C04FC964FF'; -- test PK +select * from t1 where a = '6F9619FF-8B86-D011-B42D-00C04FC964FF'; -- test PK +GO select count(*) from t1 where a = '6F9619FF-8B86-D011-B42D-00C04FC964FF'; +GO select count(*) from t1 where a > '6F9619FF-8B86-D011-B42D-00C04FC964FF'; +GO select count(*) from t1 where a >= '6F9619FF-8B86-D011-B42D-00C04FC964FF'; +GO select count(*) from t1 where a < 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'; +GO select count(*) from t1 where a <= 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'; +GO select count(*) from t1 where a <> 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'; +GO -- newid's value could not be verified insert into t1 values (newid(), newid(), newid()); insert into t1 values (newid(), newid(), newid()); insert into t1 values (newid(), newid(), newid()); select count(a) from t1; +GO -create table t2 (like t1); +create table t2 (a uniqueidentifier, b uniqueidentifier, c uniqueidentifier, primary key(a)); insert into t2 select * from t1 order by a; select count(distinct a) from t2; +GO -- test index (need more data) create table t3 ( a uniqueidentifier, b uniqueidentifier); +GO -- create inital distinct values insert into t3 values (newid(), newid()); insert into t3 values (newid(), newid()); insert into t3 values (newid(), newid()); insert into t3 values (newid(), newid()); +GO -create index t3_a on t3 using btree (a); -create index t3_b on t3 using hash (b); +create index t3_a on t3 (a); +GO + +create index t3_b on t3 (b); +GO -- test truncate feature of uniqueidentifier_in create table t4 ( a uniqueidentifier); +GO + insert into t4 values ('6F9619FF-8B86-D011-B42D-00C04FC964FF'); +GO + insert into t4 values ('6F9619FF-8B86-D011-B42D-00C04FC964FFwrong'); -- characters exceeding are truncated +GO + insert into t4 values ('{6F9619FF-8B86-D011-B42D-00C04FC964FF}'); -- with braces +GO + insert into t4 values ('{6F9619FF-8B86-D011-B42D-00C04FC964FFwrong'); -- error due to no matching brace +GO + insert into t4 values ('6F9619FF-8B86-D011-B42D-00C04FC964FF}'); -- single brace at the end are truncated +GO + select * from t4; +GO + +select set_config('enable_seqscan','off','false'); +GO + +select set_config('enable_bitmapscan','off','false'); +GO + +select set_config('search_path','sys, public','true'); +GO -reset babelfishpg_tsql.sql_dialect; -SET ENABLE_SEQSCAN = OFF; -SET ENABLE_BITMAPSCAN = OFF; -SET SEARCH_PATH = sys, public; select name, setting from pg_settings where name in ('enable_seqscan', 'enable_bitmapscan'); -explain (costs off) select * from t3 where a = 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'; -- test btree index -explain (costs off) select * from t3 where b = 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'; -- test hash index +GO +select * from t3 where a = 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'; -- test btree index +GO +select * from t3 where b = 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'; -- test hash index +GO -- assignment cast, should have same behavior as normal insert -set babelfishpg_tsql.sql_dialect = "tsql"; create table t5 ( a uniqueidentifier); insert into t5 values (cast('6F9619FF-8B86-D011-B42D-00C04FC964FF' as varchar(50))); +GO insert into t5 values (cast('6F9619FF-8B86-D011-B42D-00C04FC964FFwrong' as varchar(50))); -- characters exceeding are truncated +GO insert into t5 values (cast('{6F9619FF-8B86-D011-B42D-00C04FC964FF}' as varchar(50))); -- with braces +GO insert into t5 values (cast('{6F9619FF-8B86-D011-B42D-00C04FC964FFwrong' as varchar(50))); -- error due to no matching brace +GO insert into t5 values (cast('6F9619FF-8B86-D011-B42D-00C04FC964FF}' as varchar(50))); -- single brace at the end are truncated - +GO insert into t5 values (cast('6F9619FF-8B86-D011-B42D-00C04FC964FF' as nvarchar(50))); +GO insert into t5 values (cast('6F9619FF-8B86-D011-B42D-00C04FC964FFwrong' as nvarchar(50))); -- characters exceeding are truncated +GO insert into t5 values (cast('{6F9619FF-8B86-D011-B42D-00C04FC964FF}' as nvarchar(50))); -- with braces +GO insert into t5 values (cast('{6F9619FF-8B86-D011-B42D-00C04FC964FFwrong' as nvarchar(50))); -- error due to no matching brace +GO insert into t5 values (cast('6F9619FF-8B86-D011-B42D-00C04FC964FF}' as nvarchar(50))); -- single brace at the end are truncated +GO -- error cases, implicit cast not supported select * from t5 where a = cast('6F9619FF-8B86-D011-B42D-00C04FC964FF' as varchar(50)); +GO select * from t5 where a = cast('6F9619FF-8B86-D011-B42D-00C04FC964FF' as nvarchar(50)); +GO + +select set_config('enable_seqscan','on','false'); +GO -reset babelfishpg_tsql.sql_dialect; +select set_config('enable_bitmapscan','on','false'); +GO drop table t1; +GO drop table t2; +GO drop table t3; +GO drop table t4; +GO drop table t5; +GO \ No newline at end of file diff --git a/test/python/expected/sql_validation_framework/expected_create.out b/test/python/expected/sql_validation_framework/expected_create.out index 4d4a441636..1bdea4edcb 100644 --- a/test/python/expected/sql_validation_framework/expected_create.out +++ b/test/python/expected/sql_validation_framework/expected_create.out @@ -41,8 +41,6 @@ Could not find tests for function sys.sp_special_columns_precision_helper Could not find tests for function sys.sp_special_columns_scale_helper Could not find tests for function sys.sp_statistics_internal Could not find tests for function sys.sp_tables_internal -Could not find tests for function sys.space -Could not find tests for function sys.stuff Could not find tests for function sys.suser_id_internal Could not find tests for function sys.suser_name_internal Could not find tests for function sys.sysdatetime From 5e6315404c599b6e473c926219b5babf1d6b94a4 Mon Sep 17 00:00:00 2001 From: Aditya Verma <45755382+aadityavermaa@users.noreply.github.com> Date: Thu, 30 Mar 2023 21:10:00 +0530 Subject: [PATCH 037/363] Integrate code coverage steps in dev-tools.sh (#1368) In this change, steps to generate code coverage report are integrated in dev-tools.sh so that developers can use it to get code coverage on their dev-desktops. Task: TES2-12 Signed-off-by: adiityav@amazon.com --- .gitignore | 7 +++++ dev-tools.sh | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/.gitignore b/.gitignore index a63fab7a39..020ce750b9 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,13 @@ *.DS_Store *.o *.so +*.gcno +*.gcda +*.gcov +*.gcov.out +lcov*.info +coverage/ +coverage-html-stamp test/JDBC/Info/ test/JDBC/output/* test/JDBC/target/classes/* diff --git a/dev-tools.sh b/dev-tools.sh index 8bdf35a9a2..1d67e80da7 100755 --- a/dev-tools.sh +++ b/dev-tools.sh @@ -51,6 +51,15 @@ if [ ! $1 ]; then echo "" echo " dumprestore SOURCE_WS [TARGET_WS]" echo " dump SOURCE_WS using pg_dump and restore it on TARGET_WS" + echo "" + echo " initpg_coverage [TARGET_WS]" + echo " same as initpg but with --enable-coverage flag to generate code coverage" + echo "" + echo " build_coverage [TARGET_WS]" + echo " generate code coverage HTML report for all extensions" + echo "" + echo " sum_coverage [TARGET_WS]" + echo " summarize code coverage" exit 0 fi @@ -213,6 +222,60 @@ restore() { fi } +init_lcov(){ + cd $1 + if [ ! -d "./lcov" ]; then + git clone --depth 1 --branch v1.16 https://github.com/linux-test-project/lcov.git + fi + cd lcov + sudo make PREFIX=/usr install + export PATH=$PATH:/usr/bin/lcov + export PATH=$PATH:/usr/bin/gcov + export PATH=$PATH:/usr/bin/genhtml +} + +init_pg_coverage(){ + init_lcov $1 + cd $1/postgresql_modified_for_babelfish + ./configure --prefix=$2/postgres/ --without-readline --without-zlib --enable-coverage --enable-debug --enable-cassert CFLAGS="-ggdb" --with-libxml --with-uuid=ossp --with-icu + make -j 4 + make install + cd contrib && make && sudo make install + sudo cp "/usr/local/lib/libantlr4-runtime.so.4.9.3" $2/postgres/lib/ + init_pghint $1 $2 +} + +build_extension_coverage(){ + cd $1/babelfish_extensions/contrib/$2 + lcov --gcov-tool gcov -q --no-external -c -i -d . -d ./ -o lcov_base.info + lcov --gcov-tool gcov -q --no-external -c -d . -d ./ -o lcov_test.info + rm -rf coverage + genhtml -q --legend -o coverage --title=${2} --ignore-errors source --num-spaces=4 lcov_base.info lcov_test.info + touch coverage-html-stamp + +} + +build_coverage(){ + build_extension_coverage $1 'babelfishpg_money' + build_extension_coverage $1 'babelfishpg_common' + build_extension_coverage $1 'babelfishpg_tds' + build_extension_coverage $1 'babelfishpg_tsql' + echo "" + echo " code coverage report generation completed" + echo " run './dev-tools.sh sum_coverage' to generate summarized code coverage for all extensions" + echo " HTML code coverage report for each extension is located as follows -" + echo " babelfishpg_money: $TARGET_WS/babelfish_extensions/contrib/babelfishpg_money/coverage/index.html" + echo " babelfishpg_common: $TARGET_WS/babelfish_extensions/contrib/babelfishpg_common/coverage/index.html" + echo " babelfishpg_tds: $TARGET_WS/babelfish_extensions/contrib/babelfishpg_tds/coverage/index.html" + echo " babelfishpg_tsql: $TARGET_WS/babelfish_extensions/contrib/babelfishpg_tsql/coverage/index.html" +} + +sum_coverage(){ + cd $1/babelfish_extensions/contrib + lcov -a babelfishpg_tsql/lcov_test.info -a babelfishpg_tds/lcov_test.info -a babelfishpg_common/lcov_test.info -a babelfishpg_money/lcov_test.info -o lcov.info + lcov --list lcov.info +} + if [ "$1" == "initdb" ]; then init_db $TARGET_WS exit 0 @@ -352,4 +415,13 @@ elif [ "$1" == "dumprestore" ]; then restore $SOURCE_WS $TARGET_WS echo "Restored on target workspace ($TARGET_WS)!" exit 0 +elif [ "$1" == "initpg_coverage" ]; then + init_pg_coverage $TARGET_WS $TARGET_WS + exit 0 +elif [ "$1" == "build_coverage" ]; then + build_coverage $TARGET_WS + exit 0 +elif [ "$1" == "sum_coverage" ]; then + sum_coverage $TARGET_WS + exit 0 fi From d0c8b4ce2b861e627aaed14beeb988d678b8e3c7 Mon Sep 17 00:00:00 2001 From: Dipesh Dhameliya Date: Fri, 31 Mar 2023 11:56:33 +0530 Subject: [PATCH 038/363] Extend functionality of dev-tools.sh to run pgindent also (#1375) Extend functionality of dev-tools.sh to run pgindent also Task: No-jira Signed-off-by: Dipesh Dhameliya --- .../exclude_file_from_pgindent | 3 + dev-tools.sh | 69 +++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 contrib/babelfishpg_tsql/exclude_file_from_pgindent diff --git a/contrib/babelfishpg_tsql/exclude_file_from_pgindent b/contrib/babelfishpg_tsql/exclude_file_from_pgindent new file mode 100644 index 0000000000..4347fd169f --- /dev/null +++ b/contrib/babelfishpg_tsql/exclude_file_from_pgindent @@ -0,0 +1,3 @@ +\./antlr/ +\./src/tsqlUnsupportedFeatureHandler\.cpp$ +\./src/tsqlIface\.*/ diff --git a/dev-tools.sh b/dev-tools.sh index 1d67e80da7..d1aa2a15ad 100755 --- a/dev-tools.sh +++ b/dev-tools.sh @@ -60,6 +60,9 @@ if [ ! $1 ]; then echo "" echo " sum_coverage [TARGET_WS]" echo " summarize code coverage" + echo "" + echo " run_pgindent [TARGET_WS]" + echo " run pgindent" exit 0 fi @@ -222,6 +225,68 @@ restore() { fi } +run_pgindent() { + cd $1/postgres/lib + + echo "dumping typedefs for babelfishpg_mpney to /tmp/babelfishpg_money.typedefs.." + objdump -W babelfishpg_money.so | egrep -A3 DW_TAG_typedef | perl -e ' while (<>) { chomp; @flds = split;next unless (1 < @flds);\ + next if $flds[0] ne "DW_AT_name" && $flds[1] ne "DW_AT_name";\ + next if $flds[-1] =~ /^DW_FORM_str/;\ + print $flds[-1],"\n"; }' | sort | uniq > /tmp/babelfishpg_money.typedefs + + echo "dumping typedefs for babelfishpg_common to /tmp/babelfishpg_common.typedefs.." + objdump -W babelfishpg_common.so | egrep -A3 DW_TAG_typedef | perl -e ' while (<>) { chomp; @flds = split;next unless (1 < @flds);\ + next if $flds[0] ne "DW_AT_name" && $flds[1] ne "DW_AT_name";\ + next if $flds[-1] =~ /^DW_FORM_str/;\ + print $flds[-1],"\n"; }' | sort | uniq > /tmp/babelfishpg_common.typedefs + + echo "dumping typedefs for babelfishpg_tds to /tmp/babelfishpg_tds.typedefs.." + objdump -W babelfishpg_tds.so | egrep -A3 DW_TAG_typedef | perl -e ' while (<>) { chomp; @flds = split;next unless (1 < @flds);\ + next if $flds[0] ne "DW_AT_name" && $flds[1] ne "DW_AT_name";\ + next if $flds[-1] =~ /^DW_FORM_str/;\ + print $flds[-1],"\n"; }' | sort | uniq > /tmp/babelfishpg_tds.typedefs + + echo "dumping typedefs for babelfishpg_tsql to /tmp/babelfishpg_tsql.typedefs.." + objdump -W babelfishpg_tsql.so | egrep -A3 DW_TAG_typedef | perl -e ' while (<>) { chomp; @flds = split;next unless (1 < @flds);\ + next if $flds[0] ne "DW_AT_name" && $flds[1] ne "DW_AT_name";\ + next if $flds[-1] =~ /^DW_FORM_str/;\ + print $flds[-1],"\n"; }' | sort | uniq > /tmp/babelfishpg_tsql.typedefs + + cd $1 + echo "Clone and build pg_bsd_indent which is required by pgindent..." + git clone https://git.postgresql.org/git/pg_bsd_indent.git + cd pg_bsd_indent/ + make PG_CONFIG=$1/postgres/bin/pg_config + sudo cp pg_bsd_indent /usr/local/bin + + cd $1/babelfish_extensions + + echo "" + echo "Running pgindent on babelfishpg_money..." + cd contrib/babelfishpg_money + $1/postgresql_modified_for_babelfish/src/tools/pgindent/pgindent --typedefs=/tmp/babelfishpg_money.typedefs + + echo "" + echo "Running pgindent on babelfishpg_common..." + cd ../babelfishpg_common + $1/postgresql_modified_for_babelfish/src/tools/pgindent/pgindent --typedefs=/tmp/babelfishpg_common.typedefs + + echo "" + echo "Running pgindent on babelfishpg_tds..." + cd ../babelfishpg_tds + $1/postgresql_modified_for_babelfish/src/tools/pgindent/pgindent --typedefs=/tmp/babelfishpg_tds.typedefs + + echo "" + echo "Running pgindent on babelfishpg_tsql..." + cd ../babelfishpg_tsql + $1/postgresql_modified_for_babelfish/src/tools/pgindent/pgindent --typedefs=/tmp/babelfishpg_tsql.typedefs --exclude="exclude_file_from_pgindent" + + echo "" + echo "pgindent is ran successfully against $1." + echo "Please re-build all the extensions to make sure that there is no compilation error." + echo "" +} + init_lcov(){ cd $1 if [ ! -d "./lcov" ]; then @@ -415,6 +480,10 @@ elif [ "$1" == "dumprestore" ]; then restore $SOURCE_WS $TARGET_WS echo "Restored on target workspace ($TARGET_WS)!" exit 0 +elif [ "$1" == "run_pgindent" ]; then + init_pg $TARGET_WS $TARGET_WS + build_bbf $TARGET_WS $TARGET_WS + run_pgindent $TARGET_WS elif [ "$1" == "initpg_coverage" ]; then init_pg_coverage $TARGET_WS $TARGET_WS exit 0 From eaa9f31fcd7d78464f897fdad065c7b4ede289f5 Mon Sep 17 00:00:00 2001 From: Ashish Prasad <56514722+hash-16@users.noreply.github.com> Date: Fri, 31 Mar 2023 12:30:05 +0530 Subject: [PATCH 039/363] Optimizing DDL Export Test Framework (#1377) Added two different ways of scripting the objects which can be switched by passing flag to the script according to the input file name. Issues Resolved [BABEL-3969] Signed-off-by: Ashish Prasad pashisht@amazon.com --- test/python/SMO_script.ps1 | 70 ++++++-- test/python/batch_run.py | 5 +- test/python/config.txt | 2 +- .../expected/pyodbc/ddl_all_objects.out | 160 ++++++++++++++++++ test/python/expected/pyodbc/ddl_func_proc.out | 2 - test/python/expected/pyodbc/ddl_views.out | 4 - test/python/input/ddl_all_objects.sql | 124 ++++++++++++++ 7 files changed, 347 insertions(+), 20 deletions(-) create mode 100644 test/python/expected/pyodbc/ddl_all_objects.out create mode 100644 test/python/input/ddl_all_objects.sql diff --git a/test/python/SMO_script.ps1 b/test/python/SMO_script.ps1 index 46f66a30d5..63d213e2d5 100644 --- a/test/python/SMO_script.ps1 +++ b/test/python/SMO_script.ps1 @@ -13,18 +13,26 @@ $SmoServer.ConnectionContext.LoginSecure = $false $SmoServer.ConnectionContext.set_Login($paramsArray[3]) $SmoServer.ConnectionContext.set_Password($paramsArray[4]) $db = $SmoServer.Databases[$paramsArray[2]] +$script_flag = $paramsArray[5] +$schm = "sys" +$dtb = "sysdatabases" +$var_one = "1" -$Objects = $db.Tables -$Objects += $db.Views -$Objects += $db.StoredProcedures -$Objects += $db.UserDefinedFunctions -$Objects += $db.Tables.Indexes -$Objects += $db.Tables.Triggers - -foreach ($CurrentObject in $Objects) -{ - if (-not $CurrentObject.IsSystemObject ) - { + + + +if($script_flag -eq $var_one) +{ + $Objects = $db.Tables + $Objects += $db.Views + $Objects += $db.StoredProcedures + $Objects += $db.UserDefinedFunctions + $Objects += $db.Tables.Indexes + $Objects += $db.Tables.Triggers + foreach ($CurrentObject in $Objects) + { + if (-not $CurrentObject.IsSystemObject ) + { $Scripter = New-Object ('Microsoft.SqlServer.Management.Smo.Scripter') ($SmoServer) $Scripter.Options.DriAll = $True; $Scripter.Options.ScriptSchema = $True; @@ -33,4 +41,42 @@ foreach ($CurrentObject in $Objects) $Scripter.Script($CurrentObject); Write-Output "GO`n" } -} \ No newline at end of file + } + +} +else +{ + $Objects = $db.Tables + $Objects += $db.Views + $Objects += $db.StoredProcedures + $Objects += $db.UserDefinedFunctions + $SubObjects += $db.Tables.Indexes + $SubObjects += $db.Tables.Triggers + foreach ($CurrentObject in $Objects) + { + if ($CurrentObject.schema -ne $schm -and $CurrentObject.schema -ne $dtb -and $CurrentObject.schema -ne $null -and -not $CurrentObject.IsSystemObject ) + { + $Scripter = New-Object ('Microsoft.SqlServer.Management.Smo.Scripter') ($SmoServer) + $Scripter.Options.DriAll = $True; + $Scripter.Options.ScriptSchema = $True; + $Scripter.Options.ScriptData = $False; + $Scripter.Options.NoCollation = $True; + $Scripter.Script($CurrentObject); + Write-Output "GO`n" + } + } + foreach ($CurrentObject in $SubObjects) + { + if (-not $CurrentObject.IsSystemObject ) + { + $Scripter = New-Object ('Microsoft.SqlServer.Management.Smo.Scripter') ($SmoServer) + $Scripter.Options.DriAll = $True; + $Scripter.Options.ScriptSchema = $True; + $Scripter.Options.ScriptData = $False; + $Scripter.Options.NoCollation = $True; + $Scripter.Script($CurrentObject); + Write-Output "GO`n" + } + } + +} diff --git a/test/python/batch_run.py b/test/python/batch_run.py index e42e825b31..de08eb2f10 100644 --- a/test/python/batch_run.py +++ b/test/python/batch_run.py @@ -33,7 +33,10 @@ def batch_run(bbl_cnxn, file_handler, file, logger): f_obj = open(dest, 'a') work_dir = Path.cwd().joinpath("sqltoolsservice") script_path = Path.cwd().joinpath("SMO_script.ps1") - params="?".join([cfg["fileGenerator_URL"],cfg["fileGenerator_port"],cfg["fileGenerator_databaseName"],cfg["fileGenerator_user"],cfg["fileGenerator_password"]]) + script_flag = "0" + if len(filename.split(".")[0]) >= 7 and filename.split(".")[0][:7] == 'ddl_all': + script_flag = "1" + params="?".join([cfg["fileGenerator_URL"],cfg["fileGenerator_port"],cfg["fileGenerator_databaseName"],cfg["fileGenerator_user"],cfg["fileGenerator_password"],script_flag]) args = [] args.append("pwsh -WorkingDirectory {} -File {} {}".format(work_dir,script_path,params)) p=subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,shell=True,text=True) diff --git a/test/python/config.txt b/test/python/config.txt index 792f6283a7..7017ce74e4 100644 --- a/test/python/config.txt +++ b/test/python/config.txt @@ -39,7 +39,7 @@ outputErrorCode = true runIsolationTests = false ############################ ALLOW TO RUN DDL EXPORT TESTS (IF TRUE THEN RUNS ALL THE .SQL FILES WITH PREFIX ddl_ FROM INPUT DIRECTORY OTHERWISE SKIP THEM) ################################################## -ddlExport = false +ddlExport = true ############################ MAX TIME LIMIT FOR SINGLE STEP QUERY EXECUTION IN SECONDS(FOR ISOLATION TESTS ONLY) ############################ stepTimeLimit = 30 diff --git a/test/python/expected/pyodbc/ddl_all_objects.out b/test/python/expected/pyodbc/ddl_all_objects.out new file mode 100644 index 0000000000..29e0d7d419 --- /dev/null +++ b/test/python/expected/pyodbc/ddl_all_objects.out @@ -0,0 +1,160 @@ +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE TABLE [dbo].[babel_1654_vu_prepare_t]( + [id] [int] IDENTITY(1,1) NOT NULL, + [a] [varchar](50) NULL, + [b] [varchar](50) NULL, + CONSTRAINT [babel_1654_vu_prepare_t_pkey] PRIMARY KEY NONCLUSTERED +( + [id] +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +) ON [PRIMARY] + +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE TABLE [dbo].[sys_all_views_table_vu_prepare]( + [a] [int] NULL +) ON [PRIMARY] + +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE TABLE [dbo].[test_datetime]( + [c_time] [time](6) NULL, + [c_date] [date] NULL, + [c_datetime] [datetime] NULL, + [c_datetime2] [datetime2](6) NULL, + [c_datetimeoffset] [datetimeoffset](6) NULL, + [c_smalldatetime] [smalldatetime] NULL +) ON [PRIMARY] + +ALTER TABLE [dbo].[test_datetime] WITH CHECK ADD CONSTRAINT [test_datetime_c_date_check] CHECK (((c_date < '2001-01-01'))) +ALTER TABLE [dbo].[test_datetime] CHECK CONSTRAINT [test_datetime_c_date_check] +ALTER TABLE [dbo].[test_datetime] WITH CHECK ADD CONSTRAINT [test_datetime_c_datetime_check] CHECK (((c_datetime < '2020-10-20 09:00:00'))) +ALTER TABLE [dbo].[test_datetime] CHECK CONSTRAINT [test_datetime_c_datetime_check] +ALTER TABLE [dbo].[test_datetime] WITH CHECK ADD CONSTRAINT [test_datetime_c_datetime2_check] CHECK ((((c_datetime2 < '2020-10-20 09:00:00') AND (c_datetime2 < CAST('2020-10-20 09:00:00' AS datetime2(6)))))) +ALTER TABLE [dbo].[test_datetime] CHECK CONSTRAINT [test_datetime_c_datetime2_check] +ALTER TABLE [dbo].[test_datetime] WITH CHECK ADD CONSTRAINT [test_datetime_c_datetimeoffset_check] CHECK ((((c_datetimeoffset < '2025-12-10 12:32:10 +01:00') AND (c_datetimeoffset < CAST('2025-12-10 12:32:10 +01:00' AS datetimeoffset(4)))))) +ALTER TABLE [dbo].[test_datetime] CHECK CONSTRAINT [test_datetime_c_datetimeoffset_check] +ALTER TABLE [dbo].[test_datetime] WITH CHECK ADD CONSTRAINT [test_datetime_c_smalldatetime_check] CHECK (((c_smalldatetime < '2007-05-08 12:35:00'))) +ALTER TABLE [dbo].[test_datetime] CHECK CONSTRAINT [test_datetime_c_smalldatetime_check] +ALTER TABLE [dbo].[test_datetime] WITH CHECK ADD CONSTRAINT [test_datetime_c_time_check] CHECK ((((c_time < '09:00:00') AND (c_time < CAST('09:00:00' AS time(6)))))) +ALTER TABLE [dbo].[test_datetime] CHECK CONSTRAINT [test_datetime_c_time_check] +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE TABLE [dbo].[test_tsql_collate]( + [c_varchar] [varchar](1) NULL, + [c_char] [char](1) NULL, + [c_nchar] [nchar](1) NULL +) ON [PRIMARY] + +ALTER TABLE [dbo].[test_tsql_collate] WITH CHECK ADD CONSTRAINT [test_tsql_collate_c_char_check] CHECK (((c_char <> (CAST('sflkjasdlkfjf' AS char(7)) COLLATE japanese_ci_as)))) +ALTER TABLE [dbo].[test_tsql_collate] CHECK CONSTRAINT [test_tsql_collate_c_char_check] +ALTER TABLE [dbo].[test_tsql_collate] WITH CHECK ADD CONSTRAINT [test_tsql_collate_c_nchar_check] CHECK (((CAST((c_nchar) AS nchar(7)) <> (CAST(('sflkjasdlkfjf') AS nchar(7)) COLLATE latin1_general_ci_as)))) +ALTER TABLE [dbo].[test_tsql_collate] CHECK CONSTRAINT [test_tsql_collate_c_nchar_check] +ALTER TABLE [dbo].[test_tsql_collate] WITH CHECK ADD CONSTRAINT [test_tsql_collate_c_varchar_check] CHECK (((c_varchar <> (CAST('sflkjasdlkfjf' AS varchar(12)) COLLATE latin1_general_ci_as)))) +ALTER TABLE [dbo].[test_tsql_collate] CHECK CONSTRAINT [test_tsql_collate_c_varchar_check] +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE TABLE [dbo].[test_tsql_const]( + [c_int] [int] NOT NULL, + [c_bit] [bit] NULL, + [c_smallint] [smallint] NULL, + [c_binary] [binary](8) NULL, + [c_varbinary] [varbinary](8) NULL, + CONSTRAINT [test_tsql_const_pkey] PRIMARY KEY NONCLUSTERED +( + [c_int] +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +) ON [PRIMARY] + +ALTER TABLE [dbo].[test_tsql_const] WITH CHECK ADD CONSTRAINT [test_tsql_const_c_binary_check] CHECK (((c_binary > CAST(('0xfe') AS binary(8))))) +ALTER TABLE [dbo].[test_tsql_const] CHECK CONSTRAINT [test_tsql_const_c_binary_check] +ALTER TABLE [dbo].[test_tsql_const] WITH CHECK ADD CONSTRAINT [test_tsql_const_c_bit_check] CHECK (((c_bit <> CAST((1) AS bit)))) +ALTER TABLE [dbo].[test_tsql_const] CHECK CONSTRAINT [test_tsql_const_c_bit_check] +ALTER TABLE [dbo].[test_tsql_const] WITH CHECK ADD CONSTRAINT [test_tsql_const_c_int_check] CHECK (((c_int < 10))) +ALTER TABLE [dbo].[test_tsql_const] CHECK CONSTRAINT [test_tsql_const_c_int_check] +ALTER TABLE [dbo].[test_tsql_const] WITH CHECK ADD CONSTRAINT [test_tsql_const_c_smallint_check] CHECK (((c_smallint < CAST((CAST(('20') AS sql_variant)) AS smallint)))) +ALTER TABLE [dbo].[test_tsql_const] CHECK CONSTRAINT [test_tsql_const_c_smallint_check] +ALTER TABLE [dbo].[test_tsql_const] WITH CHECK ADD CONSTRAINT [test_tsql_const_c_varbinary_check] CHECK (((c_varbinary > CAST('0xfe' AS varbinary(8))))) +ALTER TABLE [dbo].[test_tsql_const] CHECK CONSTRAINT [test_tsql_const_c_varbinary_check] +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE VIEW sys_all_views_select_chk_option_vu_prepare AS +SELECT * FROM sys_all_views_table_vu_prepare +WITH CHECK OPTION +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE VIEW sys_all_views_select_vu_prepare AS +SELECT * FROM sys_all_views_table_vu_prepare +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +create procedure routines_test_nvar(@test_nvar_a nvarchar , @test_nvar_b int = 8) +AS +BEGIN + SELECT @test_nvar_b=8; +END +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +create function routines_fc1(@fc1_a nvarchar) RETURNS nvarchar AS BEGIN return @fc1_a END; +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +create function routines_fc2(@fc2_a varchar) RETURNS varchar AS BEGIN return @fc2_a END; +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +create function routines_fc3(@fc3_a nchar) RETURNS nchar AS BEGIN return @fc3_a END; +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +create function routines_fc4(@fc4_a binary, @fc4_b tinyint, @fc4_c BIGINT, @fc4_d float) RETURNS binary AS BEGIN return @fc4_a END; +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +create function routines_fc5(@fc5_a varbinary) RETURNS varbinary AS BEGIN return @fc5_a END; +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +create function routines_fc6(@fc6_a char) RETURNS char AS BEGIN return @fc6_a END; +GO + +ALTER TABLE [dbo].[babel_1654_vu_prepare_t] ADD CONSTRAINT [babel_1654_vu_prepare_t_pkey] PRIMARY KEY NONCLUSTERED +( + [id] +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +GO + +ALTER TABLE [dbo].[test_tsql_const] ADD CONSTRAINT [test_tsql_const_pkey] PRIMARY KEY NONCLUSTERED +( + [c_int] +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) +GO + +SET ANSI_NULLS ON +SET QUOTED_IDENTIFIER ON +CREATE TRIGGER babel_1654_vu_prepare_trig_t on babel_1654_vu_prepare_t after update as + select COLUMNS_UPDATED(); +ALTER TABLE [dbo].[babel_1654_vu_prepare_t] ENABLE TRIGGER [babel_1654_vu_prepare_trig_t] +GO + diff --git a/test/python/expected/pyodbc/ddl_func_proc.out b/test/python/expected/pyodbc/ddl_func_proc.out index f6a352794a..b1825a2efd 100644 --- a/test/python/expected/pyodbc/ddl_func_proc.out +++ b/test/python/expected/pyodbc/ddl_func_proc.out @@ -203,5 +203,3 @@ ALTER TABLE [dbo].[routines_customers] ADD CONSTRAINT [customers_pkroutines_cus )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) GO -GO - diff --git a/test/python/expected/pyodbc/ddl_views.out b/test/python/expected/pyodbc/ddl_views.out index 4d72388ac8..fc7752d0ef 100644 --- a/test/python/expected/pyodbc/ddl_views.out +++ b/test/python/expected/pyodbc/ddl_views.out @@ -25,7 +25,3 @@ CREATE VIEW sys_all_views_select_vu_prepare AS SELECT * FROM sys_all_views_table_vu_prepare GO -GO - -GO - diff --git a/test/python/input/ddl_all_objects.sql b/test/python/input/ddl_all_objects.sql new file mode 100644 index 0000000000..eef0294e62 --- /dev/null +++ b/test/python/input/ddl_all_objects.sql @@ -0,0 +1,124 @@ +DROP VIEW IF EXISTS sys_all_views_select_vu_prepare +GO +DROP VIEW IF EXISTS sys_all_views_select_chk_option_vu_prepare +GO +DROP TABLE IF EXISTS sys_all_views_table_vu_prepare +GO +DROP TRIGGER IF EXISTS babel_1654_vu_prepare_trig_t +GO +DROP TABLE IF EXISTS babel_1654_vu_prepare_t +GO +drop procedure IF EXISTS routines_test_nvar; +go +drop function IF EXISTS routines_fc1; +go +drop function IF EXISTS routines_fc2; +go +drop function IF EXISTS routines_fc3; +go +drop function IF EXISTS routines_fc4; +go +drop function IF EXISTS routines_fc5; +go +drop function IF EXISTS routines_fc6; +go +DROP TABLE IF EXISTS test_tsql_const +GO +DROP TABLE IF EXISTS test_datetime +GO +DROP TABLE IF EXISTS test_tsql_collate +GO + +Create table test_tsql_const( + c_int int primary key, + c_bit sys.bit check(c_bit <> cast(1 as sys.bit)), + check(c_int < 10), + c_smallint smallint check(c_smallint < cast(cast(CAST('20' AS smallint) as sql_variant) as smallint)), + c_binary binary(8) check(c_binary > cast(0xfe as binary(8))), + c_varbinary varbinary(8) check(c_varbinary > cast(0xfe as varbinary(8))) +) +GO +Create table test_datetime( + c_time time check(cast(c_time as pg_catalog.time) < cast('09:00:00' as time) and c_time < cast('09:00:00' as time(6))), + c_date date check(c_date < cast('2001-01-01' as date)), + c_datetime datetime check(c_datetime < cast('2020-10-20 09:00:00' as datetime)), + c_datetime2 datetime2 check(c_datetime2 < cast('2020-10-20 09:00:00' as datetime2) and c_datetime2 < cast('2020-10-20 09:00:00' as datetime2(6)) ), + c_datetimeoffset datetimeoffset check(c_datetimeoffset < cast('12-10-25 12:32:10 +01:00' as sys.datetimeoffset) and c_datetimeoffset < cast('12-10-25 12:32:10 +01:00' as datetimeoffset(4))), + c_smalldatetime smalldatetime check(c_smalldatetime < cast('2007-05-08 12:35:29.123' AS smalldatetime)), +) +GO +create table test_tsql_collate( + c_varchar varchar check(c_varchar <> cast('sflkjasdlkfjf' as varchar(12)) COLLATE latin1_general_ci_as), + c_char char check(c_char <> cast('sflkjasdlkfjf' as char(7)) COLLATE japanese_ci_as), + c_nchar nchar check(cast(c_nchar as nchar(7)) <> cast('sflkjasdlkfjf' as nchar(7)) COLLATE bbf_unicode_cp1_ci_as), +) +GO + +create procedure routines_test_nvar(@test_nvar_a nvarchar , @test_nvar_b int = 8) +AS +BEGIN + SELECT @test_nvar_b=8; +END +go +create function routines_fc1(@fc1_a nvarchar) RETURNS nvarchar AS BEGIN return @fc1_a END; +go +create function routines_fc2(@fc2_a varchar) RETURNS varchar AS BEGIN return @fc2_a END; +go +create function routines_fc3(@fc3_a nchar) RETURNS nchar AS BEGIN return @fc3_a END; +go +create function routines_fc4(@fc4_a binary, @fc4_b tinyint, @fc4_c BIGINT, @fc4_d float) RETURNS binary AS BEGIN return @fc4_a END; +go +create function routines_fc5(@fc5_a varbinary) RETURNS varbinary AS BEGIN return @fc5_a END; +go +create function routines_fc6(@fc6_a char) RETURNS char AS BEGIN return @fc6_a END; +go + +create table babel_1654_vu_prepare_t ( ID INT IDENTITY (1,1) PRIMARY KEY , a varchar(50), b varchar(50)) +GO + +CREATE TRIGGER babel_1654_vu_prepare_trig_t on babel_1654_vu_prepare_t after update as + select COLUMNS_UPDATED(); +GO + +CREATE TABLE sys_all_views_table_vu_prepare(a int) +GO +CREATE VIEW sys_all_views_select_vu_prepare AS +SELECT * FROM sys_all_views_table_vu_prepare +GO +CREATE VIEW sys_all_views_select_chk_option_vu_prepare AS +SELECT * FROM sys_all_views_table_vu_prepare +WITH CHECK OPTION +GO + +--DROP + +DROP VIEW IF EXISTS sys_all_views_select_vu_prepare +GO +DROP VIEW IF EXISTS sys_all_views_select_chk_option_vu_prepare +GO +DROP TABLE IF EXISTS sys_all_views_table_vu_prepare +GO +DROP TRIGGER IF EXISTS babel_1654_vu_prepare_trig_t +GO +DROP TABLE IF EXISTS babel_1654_vu_prepare_t +GO +drop procedure IF EXISTS routines_test_nvar; +go +drop function IF EXISTS routines_fc1; +go +drop function IF EXISTS routines_fc2; +go +drop function IF EXISTS routines_fc3; +go +drop function IF EXISTS routines_fc4; +go +drop function IF EXISTS routines_fc5; +go +drop function IF EXISTS routines_fc6; +go +DROP TABLE IF EXISTS test_tsql_const +GO +DROP TABLE IF EXISTS test_datetime +GO +DROP TABLE IF EXISTS test_tsql_collate +GO From 1fc09a34637100b7a296bc873fe0185691a49c12 Mon Sep 17 00:00:00 2001 From: pratikzode <73869399+pratikzode@users.noreply.github.com> Date: Mon, 3 Apr 2023 09:17:34 -0700 Subject: [PATCH 040/363] Support DATABASE_PRINCIPAL_ID() T-SQL function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SELECT DATABASE_PRINCIPAL_ID(); Retrieve the ID of the current user. SELECT DATABASE_PRINCIPAL_ID(‘principal_name’); Retrieve the ID of the specific database principal. Modified the file so that when called with NULL as argument it will return NULL and also modified for trailing spaces that will give proper output insted of NULL. Task: BABEL-1199 Signed-off-by: pratikzode --- .../babelfishpg_tsql/sql/sys_functions.sql | 21 ++++++++++++++-- .../babelfishpg_tsql--3.1.0--3.2.0.sql | 20 ++++++++++++++-- test/JDBC/expected/BABEL-1199-vu-verify.out | 24 +++++++++++++++++++ test/JDBC/input/BABEL-1199-vu-verify.sql | 9 +++++++ 4 files changed, 70 insertions(+), 4 deletions(-) diff --git a/contrib/babelfishpg_tsql/sql/sys_functions.sql b/contrib/babelfishpg_tsql/sql/sys_functions.sql index a4a974ab37..3e66e432ec 100644 --- a/contrib/babelfishpg_tsql/sql/sys_functions.sql +++ b/contrib/babelfishpg_tsql/sql/sys_functions.sql @@ -1738,10 +1738,27 @@ CREATE OR REPLACE FUNCTION sys.servername() CREATE OR REPLACE FUNCTION sys.servicename() RETURNS sys.NVARCHAR(128) AS 'babelfishpg_tsql' LANGUAGE C STABLE; + CREATE OR REPLACE FUNCTION sys.database_principal_id(IN user_name sys.sysname DEFAULT NULL) RETURNS OID -AS 'babelfishpg_tsql', 'user_id' -LANGUAGE C IMMUTABLE PARALLEL SAFE; +AS +$$ +BEGIN + -- If user_name is NULL, return the result of USER_ID() + IF user_name IS NULL OR user_name = 'NULL' THEN + RETURN NULL; + END IF; + -- Trim the trailing spaces from user_name + user_name := rtrim(user_name); + -- If user_name is an empty string or contains only spaces, return NULL + IF user_name = '' THEN + RETURN NULL; + END IF; + -- Return the principal_id of the specified user_name + RETURN (SELECT principal_id FROM sys.database_principals WHERE name = user_name); +END; +$$ +LANGUAGE PLPGSQL IMMUTABLE PARALLEL SAFE; -- In tsql @@max_precision represents max precision that server supports -- As of now, we do not support change in max_precision. So, returning default value diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql index 08c21bbe94..8de61cbf0d 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql @@ -443,8 +443,24 @@ CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'json_modify_deprec CREATE OR REPLACE FUNCTION sys.database_principal_id(IN user_name sys.sysname DEFAULT NULL) RETURNS OID -AS 'babelfishpg_tsql', 'user_id' -LANGUAGE C IMMUTABLE PARALLEL SAFE; +AS +$$ +BEGIN + -- If user_name is NULL, return the result of USER_ID() + IF user_name IS NULL OR user_name = 'NULL' THEN + RETURN NULL; + END IF; + -- Trim the trailing spaces from user_name + user_name := rtrim(user_name); + -- If user_name is an empty string or contains only spaces, return NULL + IF user_name = '' THEN + RETURN NULL; + END IF; + -- Return the principal_id of the specified user_name + RETURN (SELECT principal_id FROM sys.database_principals WHERE name = user_name); +END; +$$ +LANGUAGE PLPGSQL IMMUTABLE PARALLEL SAFE; /* * JSON MODIFY diff --git a/test/JDBC/expected/BABEL-1199-vu-verify.out b/test/JDBC/expected/BABEL-1199-vu-verify.out index 34289d1be3..227e00b955 100644 --- a/test/JDBC/expected/BABEL-1199-vu-verify.out +++ b/test/JDBC/expected/BABEL-1199-vu-verify.out @@ -78,3 +78,27 @@ nvarchar roletest ~~END~~ + +SELECT (DATABASE_PRINCIPAL_ID(NULL)); +GO +~~START~~ +int + +~~END~~ + + +SELECT user_name(DATABASE_PRINCIPAL_ID('db_owner ')); +GO +~~START~~ +nvarchar +db_owner +~~END~~ + + +SELECT DATABASE_PRINCIPAL_ID('NULL') +GO +~~START~~ +int + +~~END~~ + diff --git a/test/JDBC/input/BABEL-1199-vu-verify.sql b/test/JDBC/input/BABEL-1199-vu-verify.sql index bce78b94e1..6f6cd9b8ee 100644 --- a/test/JDBC/input/BABEL-1199-vu-verify.sql +++ b/test/JDBC/input/BABEL-1199-vu-verify.sql @@ -27,4 +27,13 @@ SELECT user_name(DATABASE_PRINCIPAL_ID('testuser')); GO SELECT user_name(DATABASE_PRINCIPAL_ID('roletest')); +GO + +SELECT (DATABASE_PRINCIPAL_ID(NULL)); +GO + +SELECT user_name(DATABASE_PRINCIPAL_ID('db_owner ')); +GO + +SELECT DATABASE_PRINCIPAL_ID('NULL') GO \ No newline at end of file From 0f2ca9dfb3e7d656f896ee60b25af605da382b63 Mon Sep 17 00:00:00 2001 From: Zhibai Date: Mon, 3 Apr 2023 13:00:32 -0700 Subject: [PATCH 041/363] In CTE Null first order behavior is not correct (#1382) * Solve the bug in CTE Null first order behavior is not correct Previously we add the Null first check after analyze, and in that case it'll miss to add the Null first tag to the sort clause for a CTE query change the place adding Null first tag to the place sortClause is initialized Signed-off-by: Zhibai Song Task: BABEL-3991 --- contrib/babelfishpg_tsql/src/hooks.c | 16 +++ contrib/babelfishpg_tsql/src/pl_handler.c | 50 -------- test/JDBC/expected/BABEL-2903.out | 2 +- test/JDBC/expected/babel_function.out | 56 ++++----- test/JDBC/expected/babel_orderby.out | 118 ++++++++++++++++++ .../expected/table-variable-vu-verify.out | 2 +- 6 files changed, 164 insertions(+), 80 deletions(-) create mode 100644 test/JDBC/expected/babel_orderby.out diff --git a/contrib/babelfishpg_tsql/src/hooks.c b/contrib/babelfishpg_tsql/src/hooks.c index bdcd1098d2..3809cedbec 100644 --- a/contrib/babelfishpg_tsql/src/hooks.c +++ b/contrib/babelfishpg_tsql/src/hooks.c @@ -105,6 +105,7 @@ static inline bool is_identifier_char(char c); static int find_attr_by_name_from_relation(Relation rd, const char *attname, bool sysColOK); static void modify_insert_stmt(InsertStmt *stmt, Oid relid); static void modify_RangeTblFunction_tupdesc(char *funcname, Node *expr, TupleDesc *tupdesc); +static void sort_nulls_first(SortGroupClause * sortcl, bool reverse); /***************************************** * Commands Hooks @@ -188,6 +189,7 @@ static validate_var_datatype_scale_hook_type prev_validate_var_datatype_scale_ho static modify_RangeTblFunction_tupdesc_hook_type prev_modify_RangeTblFunction_tupdesc_hook = NULL; static fill_missing_values_in_copyfrom_hook_type prev_fill_missing_values_in_copyfrom_hook = NULL; static check_rowcount_hook_type prev_check_rowcount_hook = NULL; +static sortby_nulls_hook_type prev_sortby_nulls_hook = NULL; /***************************************** * Install / Uninstall @@ -298,6 +300,9 @@ InstallExtendedHooks(void) fill_missing_values_in_copyfrom_hook = fill_missing_values_in_copyfrom; prev_check_rowcount_hook = check_rowcount_hook; check_rowcount_hook = bbf_check_rowcount_hook; + + prev_sortby_nulls_hook = sortby_nulls_hook; + sortby_nulls_hook = sort_nulls_first; } void @@ -342,6 +347,7 @@ UninstallExtendedHooks(void) modify_RangeTblFunction_tupdesc_hook = prev_modify_RangeTblFunction_tupdesc_hook; fill_missing_values_in_copyfrom_hook = prev_fill_missing_values_in_copyfrom_hook; check_rowcount_hook = prev_check_rowcount_hook; + sortby_nulls_hook = prev_sortby_nulls_hook; } /***************************************** @@ -3630,3 +3636,13 @@ bbf_check_rowcount_hook(int es_processed) else return false; } + +static void +sort_nulls_first(SortGroupClause * sortcl, bool reverse) +{ + if (sql_dialect == SQL_DIALECT_TSQL) + { + /* Tsql NULLS FIRST is default for ASC; other way for DESC */ + sortcl->nulls_first = !reverse; + } +} \ No newline at end of file diff --git a/contrib/babelfishpg_tsql/src/pl_handler.c b/contrib/babelfishpg_tsql/src/pl_handler.c index 7fd9ec26a4..c8d5cdb932 100644 --- a/contrib/babelfishpg_tsql/src/pl_handler.c +++ b/contrib/babelfishpg_tsql/src/pl_handler.c @@ -743,51 +743,6 @@ pltsql_pre_parse_analyze(ParseState *pstate, RawStmt *parseTree) } } -/* Unlike PG, T-SQL treats null values as the lowest possible values. - * So we need to set nulls_first for ASC order and nulls_last for DESC order. - */ -static inline void -pltsql_set_nulls_first(Query *query) -{ - ListCell *lc = NULL; - Node *node = NULL; - SortGroupClause *sgc = NULL; - char *opname = NULL; - RangeTblEntry *rte = NULL; - - /* check subqueries */ - foreach(lc, query->rtable) - { - node = lfirst(lc); - if (node->type != T_RangeTblEntry) - continue; - - rte = (RangeTblEntry *) node; - if (rte->rtekind == RTE_SUBQUERY && rte->subquery && rte->subquery->commandType == CMD_SELECT) - pltsql_set_nulls_first(rte->subquery); - } - - if (!query->sortClause) - return; - - foreach(lc, query->sortClause) - { - node = lfirst(lc); - if (node->type != T_SortGroupClause) - continue; - - sgc = (SortGroupClause *) node; - opname = get_opname(sgc->sortop); - - if (!opname) - continue; - else if (strcmp(opname, ">") == 0) - sgc->nulls_first = false; - else if (strcmp(opname, "<") == 0) - sgc->nulls_first = true; - } -} - static void pltsql_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate) { @@ -1173,7 +1128,6 @@ pltsql_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate) } } - pltsql_set_nulls_first(q); } } } @@ -1204,10 +1158,6 @@ pltsql_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate) } } } - else if (query->commandType == CMD_SELECT) - { - pltsql_set_nulls_first(query); - } } /* diff --git a/test/JDBC/expected/BABEL-2903.out b/test/JDBC/expected/BABEL-2903.out index 2b5c437661..67b96940fc 100644 --- a/test/JDBC/expected/BABEL-2903.out +++ b/test/JDBC/expected/BABEL-2903.out @@ -74,7 +74,7 @@ Query Text: EXEC babel_2903_outer_proc @a, @b InitPlan 1 (returns $0) -> Limit (cost=49.55..49.55 rows=1 width=8) -> Sort (cost=49.55..55.20 rows=2260 width=8) - Sort Key: babel_2903_t1.b + Sort Key: babel_2903_t1.b NULLS FIRST -> Seq Scan on babel_2903_t1 (cost=0.00..38.25 rows=2260 width=8) Query Text: insert into babel_2903_t1 values ("@b", "@b"); -> Insert on babel_2903_t1 (cost=0.00..0.01 rows=0 width=0) diff --git a/test/JDBC/expected/babel_function.out b/test/JDBC/expected/babel_function.out index c58c0a80e5..aa012b1833 100644 --- a/test/JDBC/expected/babel_function.out +++ b/test/JDBC/expected/babel_function.out @@ -2426,26 +2426,26 @@ SELECT a, b, COUNT(*) OVER (ORDER BY a) from t3; GO ~~START~~ varchar#!#varchar#!#int -abc#!#b#!#2 -abc#!#a#!#2 -efg#!#a#!#4 -efg#!#b#!#4 -xyz#!#a#!#6 -xyz#!#b#!#6 -#!##!#7 +#!##!#1 +abc#!#a#!#3 +abc#!#b#!#3 +efg#!#a#!#5 +efg#!#b#!#5 +xyz#!#a#!#7 +xyz#!#b#!#7 ~~END~~ SELECT a, b, COUNT(*) OVER (ORDER BY a DESC) from t3; GO ~~START~~ varchar#!#varchar#!#int -#!##!#1 -xyz#!#b#!#3 -xyz#!#a#!#3 -efg#!#b#!#5 -efg#!#a#!#5 -abc#!#b#!#7 -abc#!#a#!#7 +xyz#!#b#!#2 +xyz#!#a#!#2 +efg#!#a#!#4 +efg#!#b#!#4 +abc#!#b#!#6 +abc#!#a#!#6 +#!##!#7 ~~END~~ SELECT a, b, COUNT(*) OVER(PARTITION BY a) from t3; @@ -2511,26 +2511,26 @@ SELECT a, b, COUNT_BIG(*) OVER (ORDER BY a) from t3; GO ~~START~~ varchar#!#varchar#!#bigint -abc#!#b#!#2 -abc#!#a#!#2 -efg#!#a#!#4 -efg#!#b#!#4 -xyz#!#a#!#6 -xyz#!#b#!#6 -#!##!#7 +#!##!#1 +abc#!#a#!#3 +abc#!#b#!#3 +efg#!#a#!#5 +efg#!#b#!#5 +xyz#!#a#!#7 +xyz#!#b#!#7 ~~END~~ SELECT a, b, COUNT_BIG(*) OVER (ORDER BY a DESC) from t3; GO ~~START~~ varchar#!#varchar#!#bigint -#!##!#1 -xyz#!#b#!#3 -xyz#!#a#!#3 -efg#!#b#!#5 -efg#!#a#!#5 -abc#!#b#!#7 -abc#!#a#!#7 +xyz#!#b#!#2 +xyz#!#a#!#2 +efg#!#a#!#4 +efg#!#b#!#4 +abc#!#b#!#6 +abc#!#a#!#6 +#!##!#7 ~~END~~ SELECT a, b, COUNT_BIG(*) OVER(PARTITION BY a) from t3; diff --git a/test/JDBC/expected/babel_orderby.out b/test/JDBC/expected/babel_orderby.out new file mode 100644 index 0000000000..f05ef9ed5f --- /dev/null +++ b/test/JDBC/expected/babel_orderby.out @@ -0,0 +1,118 @@ +drop table if exists t1; +GO + +create table t1(a int); +GO + +insert t1 values (1); +insert t1 values (3); +insert t1 values (null); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +with t1cte AS ( +select top(3) a from t1 order by 1 +) +select * from t1cte; +GO +~~START~~ +int + +1 +3 +~~END~~ + + +select top(3) a from t1 order by 1; +GO +~~START~~ +int + +1 +3 +~~END~~ + + +select a from t1; +GO +~~START~~ +int +1 +3 + +~~END~~ + + +select a from t1 order by a; +GO +~~START~~ +int + +1 +3 +~~END~~ + + +select a from t1 order by a desc; +GO +~~START~~ +int +3 +1 + +~~END~~ + + +select * from (select top(3) a from t1 order by 1) as b; +GO +~~START~~ +int + +1 +3 +~~END~~ + + +-- psql + + +-- to show pg ordering is different from tsql +select a from master_dbo.t1; +GO +~~START~~ +int4 +1 +3 + +~~END~~ + + +select a from master_dbo.t1 order by a; +GO +~~START~~ +int4 +1 +3 + +~~END~~ + + +select a from master_dbo.t1 order by a desc; +GO +~~START~~ +int4 + +3 +1 +~~END~~ + + +-- tsql + +drop table t1; +GO diff --git a/test/JDBC/expected/table-variable-vu-verify.out b/test/JDBC/expected/table-variable-vu-verify.out index 78e0140388..6eb29f6fc9 100644 --- a/test/JDBC/expected/table-variable-vu-verify.out +++ b/test/JDBC/expected/table-variable-vu-verify.out @@ -84,7 +84,7 @@ Query Text: EXEC table_variable_vu_prepareouter_proc @a, @b InitPlan 1 (returns $0) -> Limit (cost=49.55..49.55 rows=1 width=8) -> Sort (cost=49.55..55.20 rows=2260 width=8) - Sort Key: table_variable_vu_preparet1.b + Sort Key: table_variable_vu_preparet1.b NULLS FIRST -> Seq Scan on table_variable_vu_preparet1 (cost=0.00..38.25 rows=2260 width=8) Query Text: insert into table_variable_vu_preparet1 values ("@b", "@b"); -> Insert on table_variable_vu_preparet1 (cost=0.00..0.01 rows=0 width=0) From 26617c5059fea9877256dcec4bdc7efcbbcfe223 Mon Sep 17 00:00:00 2001 From: pratikzode <73869399+pratikzode@users.noreply.github.com> Date: Mon, 3 Apr 2023 15:49:32 -0700 Subject: [PATCH 042/363] TES2_14 Moving Test to JDBC (#1386) * TES2_14 Moving Test to JDBC Moved babel_219, babel_collection, babel_datatype, babel_ddl, babel_delete1, babel_function, babel_like, babel_typecode, babel_uniqueidentifier babel_set_command babel_table_type babel_transaction babel_emoji to JDBC And removed it from babelfish_extensions/contrib/babelfishpg_tsql/sql/test directory Modified babel_transaction file. Forget to add Go in last few lines Task: TES2_14 Signed-off-by: pratikzode --- test/JDBC/expected/babel_transaction.out | 54 ++++++++++++++++++++++++ test/JDBC/input/babel_transaction.sql | 36 ++-------------- 2 files changed, 58 insertions(+), 32 deletions(-) diff --git a/test/JDBC/expected/babel_transaction.out b/test/JDBC/expected/babel_transaction.out index c0aa474e67..924d38c03d 100644 --- a/test/JDBC/expected/babel_transaction.out +++ b/test/JDBC/expected/babel_transaction.out @@ -423,8 +423,62 @@ int ~~END~~ +-- begin transaction -> save transaction name -> rollback to savepoint +-- save transaction name -> commit transaction +begin transaction txn1; +insert into TxnTable values(3); +save transaction sp1; +insert into TxnTable values(4); +select c1 from TxnTable; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +3 +4 +~~END~~ + +rollback tran sp1; +save transaction sp2; +insert into TxnTable values(5); +commit transaction; +select c1 from TxnTable; +GO +~~ROW COUNT: 1~~ +~~START~~ +int +1 +3 +5 +~~END~~ +-- begin transaction -> save transaction name -> error -> rollback to savepoint +-- commit transaction +rollback tran sp1; +commit transaction; +select c1 from TxnTable; +GO +~~ERROR (Code: 3903)~~ +~~ERROR (Message: ROLLBACK TO SAVEPOINT can only be used in transaction blocks)~~ +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + +~~START~~ +int +1 +3 +5 +~~END~~ + + +drop table TxnTable; +GO diff --git a/test/JDBC/input/babel_transaction.sql b/test/JDBC/input/babel_transaction.sql index c04554fb7a..6015858df7 100644 --- a/test/JDBC/input/babel_transaction.sql +++ b/test/JDBC/input/babel_transaction.sql @@ -177,48 +177,20 @@ insert into TxnTable values(3); save transaction sp1; insert into TxnTable values(4); select c1 from TxnTable; +GO rollback tran sp1; save transaction sp2; insert into TxnTable values(5); commit transaction; select c1 from TxnTable; +GO -- begin transaction -> save transaction name -> error -> rollback to savepoint -- commit transaction -begin transaction txn1; -insert into TxnTable values(6); -save transaction sp1; -insert into TxnTable values(7); -select c1 frm TxnTable; rollback tran sp1; commit transaction; select c1 from TxnTable; - --- create and execute procedure with transaction commands --- \tsql on --- create procedure txnproc as --- begin tran; --- insert into TxnTable values(8); --- select c1 from TxnTable; --- save tran sp1; --- commit; --- rollback tran; --- go --- execute txnproc; --- go --- \tsql off --- drop procedure txnproc; - --- transaction syntax error -begin; -begin txn1; -commit txn1; -rollback txx1; - --- invalid transaction name -begin transaction txn1; -rollback transaction txn2; -rollback; +GO drop table TxnTable; -reset babelfish_pg_tsql.sql_dialect; \ No newline at end of file +GO From adddc1e944a4030c3ba5588f06d4bccfd53a6b05 Mon Sep 17 00:00:00 2001 From: Dipesh Dhameliya Date: Tue, 4 Apr 2023 11:52:23 +0530 Subject: [PATCH 043/363] Fixed test case failure related to sp_databases (#1378) Output of the system procedure, sp_databases contains the size of the database which is subjected to vary. Hence, it was causing the test failures unexpectedly. This commit adds a minor improvement to the definition of the view sys.sp_databases_view to consider only physical relations to calculate the database size. We are temporarily disabling the test case for sp_databases to fix the test flakiness arising due to database size. Task: BABEL-4052 Signed-off-by: Dipesh Dhameliya --- .../babelfishpg_tsql/sql/babelfishpg_tsql.sql | 2 +- .../babelfishpg_tsql--3.1.0--3.2.0.sql | 20 +++++++++++++++++++ test/JDBC/expected/BABEL-SP_DATABASES.out | 12 ++--------- test/JDBC/input/BABEL-SP_DATABASES.sql | 4 ++-- .../expected_create.out | 1 + 5 files changed, 26 insertions(+), 13 deletions(-) diff --git a/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql index 4f80559e67..f5ce2ecd06 100644 --- a/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql +++ b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql @@ -1093,7 +1093,7 @@ CREATE VIEW sys.sp_databases_view AS sys.babelfish_namespace_ext EXT JOIN sys.babelfish_sysdatabases INT ON EXT.dbid = INT.dbid JOIN pg_catalog.pg_namespace ON pg_catalog.pg_namespace.nspname = EXT.nspname - LEFT JOIN pg_catalog.pg_class ON relnamespace = pg_catalog.pg_namespace.oid + LEFT JOIN pg_catalog.pg_class ON relnamespace = pg_catalog.pg_namespace.oid where pg_catalog.pg_class.relkind = 'r' ) t GROUP BY database_name ORDER BY database_name; diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql index 8de61cbf0d..75a5b30169 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql @@ -747,6 +747,26 @@ CREATE OR REPLACE VIEW sys.spt_tablecollations_view AS WHERE c.is_sparse = 0 AND p.attnum >= 0; +CREATE OR REPLACE VIEW sys.sp_databases_view AS + SELECT CAST(database_name AS sys.SYSNAME), + -- DATABASE_SIZE returns a NULL value for databases larger than 2.15 TB + CASE WHEN (sum(table_size)/1024.0) > 2.15 * 1024.0 * 1024.0 * 1024.0 THEN NULL + ELSE CAST((sum(table_size)/1024.0) AS int) END as database_size, + CAST(NULL AS sys.VARCHAR(254)) as remarks + FROM ( + SELECT pg_catalog.pg_namespace.oid as schema_oid, + pg_catalog.pg_namespace.nspname as schema_name, + INT.name AS database_name, + coalesce(pg_relation_size(pg_catalog.pg_class.oid), 0) as table_size + FROM + sys.babelfish_namespace_ext EXT + JOIN sys.babelfish_sysdatabases INT ON EXT.dbid = INT.dbid + JOIN pg_catalog.pg_namespace ON pg_catalog.pg_namespace.nspname = EXT.nspname + LEFT JOIN pg_catalog.pg_class ON relnamespace = pg_catalog.pg_namespace.oid where pg_catalog.pg_class.relkind = 'r' + ) t + GROUP BY database_name + ORDER BY database_name; + -- Drops the temporary procedure used by the upgrade script. -- Please have this be one of the last statements executed in this upgrade script. DROP PROCEDURE sys.babelfish_drop_deprecated_object(varchar, varchar, varchar); diff --git a/test/JDBC/expected/BABEL-SP_DATABASES.out b/test/JDBC/expected/BABEL-SP_DATABASES.out index 516ec89772..98224e3360 100644 --- a/test/JDBC/expected/BABEL-SP_DATABASES.out +++ b/test/JDBC/expected/BABEL-SP_DATABASES.out @@ -37,17 +37,9 @@ db1#!# ~~END~~ -EXEC sp_databases; -GO -~~START~~ -varchar#!#int#!#varchar -db1#!#8#!# -master#!#0#!# -msdb#!#0#!# -tempdb#!#0#!# -~~END~~ - +-- EXEC sp_databases; +-- GO drop table t_spdatabases; go use master; diff --git a/test/JDBC/input/BABEL-SP_DATABASES.sql b/test/JDBC/input/BABEL-SP_DATABASES.sql index f204f68784..21f17d2183 100644 --- a/test/JDBC/input/BABEL-SP_DATABASES.sql +++ b/test/JDBC/input/BABEL-SP_DATABASES.sql @@ -19,8 +19,8 @@ go select database_name, remarks from sys.sp_databases_view where database_name='DB1'; go -EXEC sp_databases; -GO +-- EXEC sp_databases; +-- GO drop table t_spdatabases; go diff --git a/test/python/expected/sql_validation_framework/expected_create.out b/test/python/expected/sql_validation_framework/expected_create.out index 1bdea4edcb..4f5d3bda4b 100644 --- a/test/python/expected/sql_validation_framework/expected_create.out +++ b/test/python/expected/sql_validation_framework/expected_create.out @@ -69,6 +69,7 @@ Could not find tests for procedure sys.babel_drop_all_dbs Could not find tests for procedure sys.babel_drop_all_logins Could not find tests for procedure sys.babel_initialize_logins Could not find tests for procedure sys.printarg +Could not find tests for procedure sys.sp_databases Could not find tests for table sys.babelfish_helpcollation Could not find tests for table sys.babelfish_syslanguages Could not find tests for table sys.service_settings From b2dbb89cdda519e2e3006d532976b3289216030c Mon Sep 17 00:00:00 2001 From: Zhibai Date: Tue, 4 Apr 2023 22:58:28 -0700 Subject: [PATCH 044/363] modify the upgrade script for 3.1.0--3.2.0 (#1392) The version in the echo message is incorrect for this upgrade script. Task: BABEL-OSS Signed-off-by: Zhibai Song --- .../sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql index 75a5b30169..0dbe8736b2 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql @@ -1,5 +1,5 @@ -- complain if script is sourced in psql, rather than via ALTER EXTENSION -\echo Use "ALTER EXTENSION ""babelfishpg_tsql"" UPDATE TO '3.1.0'" to load this file. \quit +\echo Use "ALTER EXTENSION ""babelfishpg_tsql"" UPDATE TO '3.2.0'" to load this file. \quit -- add 'sys' to search path for the convenience SELECT set_config('search_path', 'sys, '||current_setting('search_path'), false); From d9ddc222f62e707f3e1041b3855d185fb4536833 Mon Sep 17 00:00:00 2001 From: Dipesh Dhameliya Date: Wed, 5 Apr 2023 21:16:05 +0530 Subject: [PATCH 045/363] Introducing upgrade script babelfishpg_tsql--2.5.0--3.0.0.sql to fix upgrade from v2.5.0 to v3.0.0 (#1394) Description Previously, Major version upgrade from v2.5.0 to v3.2.0 started failing due to missing babelfishpg_tsql--2.5.0--3.0.0.sql upgrade script. So this commit fixes that issue by appropriately adding upgrade script. Task: BABEL-4052 Signed-off-by: Dipesh Dhameliya dddhamel@amazon.com --- .../babelfishpg_tsql--2.5.0--3.0.0.sql | 147 ++++++++++++++++++ .../expected_drop.out | 3 + 2 files changed, 150 insertions(+) create mode 100644 contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.5.0--3.0.0.sql diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.5.0--3.0.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.5.0--3.0.0.sql new file mode 100644 index 0000000000..66e14c30e3 --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.5.0--3.0.0.sql @@ -0,0 +1,147 @@ +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION ""babelfishpg_tsql"" UPDATE TO '3.0.0'" to load this file. \quit + +-- add 'sys' to search path for the convenience +SELECT set_config('search_path', 'sys, '||current_setting('search_path'), false); + +-- Drops an object if it does not have any dependent objects. +-- Is a temporary procedure for use by the upgrade script. Will be dropped at the end of the upgrade. +-- Please have this be one of the first statements executed in this upgrade script. +CREATE OR REPLACE PROCEDURE babelfish_drop_deprecated_object(object_type varchar, schema_name varchar, object_name varchar) AS +$$ +DECLARE + error_msg text; + query1 text; + query2 text; +BEGIN + + query1 := pg_catalog.format('alter extension babelfishpg_tsql drop %s %s.%s', object_type, schema_name, object_name); + query2 := pg_catalog.format('drop %s %s.%s', object_type, schema_name, object_name); + + execute query1; + execute query2; +EXCEPTION + when object_not_in_prerequisite_state then --if 'alter extension' statement fails + GET STACKED DIAGNOSTICS error_msg = MESSAGE_TEXT; + raise warning '%', error_msg; + when dependent_objects_still_exist then --if 'drop view' statement fails + GET STACKED DIAGNOSTICS error_msg = MESSAGE_TEXT; + raise warning '%', error_msg; +end +$$ +LANGUAGE plpgsql; + +-- Created to to fetch default collation Oid which is being used to set collation of system objects +CREATE OR REPLACE FUNCTION sys.babelfishpg_tsql_get_babel_server_collation_oid() RETURNS OID +LANGUAGE C +AS 'babelfishpg_tsql', 'get_server_collation_oid'; + +-- Set the collation of given schema_name.table_name.column_name column to default collation +CREATE OR REPLACE PROCEDURE sys.babelfish_update_collation_to_default(schema_name varchar, table_name varchar, column_name varchar) AS +$$ +DECLARE + sys_schema oid; + table_oid oid; + att_coll oid; + default_coll_oid oid; + c_coll_oid oid; +BEGIN + select oid into default_coll_oid from pg_collation where collname = 'default'; + select oid into c_coll_oid from pg_collation where collname = 'C'; + select oid into sys_schema from pg_namespace where nspname = schema_name collate sys.database_default; + select oid into table_oid from pg_class where relname = table_name collate sys.database_default and relnamespace = sys_schema; + select attcollation into att_coll from pg_attribute where attname = column_name collate sys.database_default and attrelid = table_oid; + if att_coll = default_coll_oid or att_coll = c_coll_oid then + update pg_attribute set attcollation = sys.babelfishpg_tsql_get_babel_server_collation_oid() where attname = column_name collate sys.database_default and attrelid = table_oid; + end if; +END +$$ +LANGUAGE plpgsql; + +-- please add your SQL here + +CREATE OR REPLACE FUNCTION sys.datepart_internal(IN datepart PG_CATALOG.TEXT, IN arg anyelement,IN df_tz INTEGER DEFAULT 0) RETURNS INTEGER AS $$ +DECLARE + result INTEGER; + first_day DATE; + first_week_end INTEGER; + day INTEGER; +BEGIN + CASE datepart + WHEN 'dow' THEN + result = (date_part(datepart, arg)::INTEGER - current_setting('babelfishpg_tsql.datefirst')::INTEGER + 7) % 7 + 1; + WHEN 'tsql_week' THEN + first_day = make_date(date_part('year', arg)::INTEGER, 1, 1); + first_week_end = 8 - sys.datepart_internal('dow', first_day)::INTEGER; + day = date_part('doy', arg)::INTEGER; + IF day <= first_week_end THEN + result = 1; + ELSE + result = 2 + (day - first_week_end - 1) / 7; + END IF; + WHEN 'second' THEN + result = TRUNC(date_part(datepart, arg))::INTEGER; + WHEN 'millisecond' THEN + result = right(date_part(datepart, arg)::TEXT, 3)::INTEGER; + WHEN 'microsecond' THEN + result = right(date_part(datepart, arg)::TEXT, 6)::INTEGER; + WHEN 'nanosecond' THEN + -- Best we can do - Postgres does not support nanosecond precision + result = right(date_part('microsecond', arg)::TEXT, 6)::INTEGER * 1000; + WHEN 'tzoffset' THEN + -- timezone for datetimeoffset + result = df_tz; + ELSE + result = date_part(datepart, arg)::INTEGER; + END CASE; + RETURN result; +EXCEPTION WHEN invalid_parameter_value or feature_not_supported THEN + -- date_part() throws an exception when trying to get day/month/year etc. from + -- TIME, so we just need to catch the exception in this case + -- date_part() returns 0 when trying to get hour/minute/second etc. from + -- DATE, which is the desirable behavior for datepart() as well. + -- If the date argument data type does not have the specified datepart, + -- date_part() will return the default value for that datepart. + CASE datepart + -- Case for datepart is year, yy and yyyy, all mappings are defined in gram.y. + WHEN 'year' THEN RETURN 1900; + -- Case for datepart is quater, qq and q + WHEN 'quarter' THEN RETURN 1; + -- Case for datepart is month, mm and m + WHEN 'month' THEN RETURN 1; + -- Case for datepart is day, dd and d + WHEN 'day' THEN RETURN 1; + -- Case for datepart is dayofyear, dy + WHEN 'doy' THEN RETURN 1; + -- Case for datepart is y(also refers to dayofyear) + WHEN 'y' THEN RETURN 1; + -- Case for datepart is week, wk and ww + WHEN 'tsql_week' THEN RETURN 1; + -- Case for datepart is iso_week, isowk and isoww + WHEN 'week' THEN RETURN 1; + -- Case for datepart is tzoffset and tz + WHEN 'tzoffset' THEN RETURN 0; + -- Case for datepart is weekday and dw, return dow according to datefirst + WHEN 'dow' THEN + RETURN (1 - current_setting('babelfishpg_tsql.datefirst')::INTEGER + 7) % 7 + 1 ; + ELSE + RAISE EXCEPTION '''%'' is not a recognized datepart option', datepart; + RETURN -1; + END CASE; +END; +$$ +STRICT +LANGUAGE plpgsql IMMUTABLE; + +CALL sys.babelfish_update_collation_to_default('sys', 'babelfish_authid_user_ext_login_db_idx', 'database_name'); +-- we have to reindex babelfish_authid_user_ext_login_db_idx because given index includes database_name and we have to change its collation +REINDEX INDEX sys.babelfish_authid_user_ext_login_db_idx; + +-- Drops the temporary procedure used by the upgrade script. +-- Please have this be one of the last statements executed in this upgrade script. +DROP PROCEDURE sys.babelfish_drop_deprecated_object(varchar, varchar, varchar); +DROP PROCEDURE sys.babelfish_update_collation_to_default(varchar, varchar, varchar); +DROP FUNCTION sys.babelfishpg_tsql_get_babel_server_collation_oid(); + +-- Reset search_path to not affect any subsequent scripts +SELECT set_config('search_path', trim(leading 'sys, ' from current_setting('search_path')), false); \ No newline at end of file diff --git a/test/python/expected/sql_validation_framework/expected_drop.out b/test/python/expected/sql_validation_framework/expected_drop.out index 10db04c924..d774166cde 100644 --- a/test/python/expected/sql_validation_framework/expected_drop.out +++ b/test/python/expected/sql_validation_framework/expected_drop.out @@ -11,6 +11,7 @@ Unexpected drop found for function sys.babelfishpg_common_get_babel_server_colla Unexpected drop found for function sys.babelfishpg_tsql_get_babel_server_collation_oid in file babelfishpg_tsql--2.2.0--2.3.0.sql Unexpected drop found for function sys.babelfishpg_tsql_get_babel_server_collation_oid in file babelfishpg_tsql--2.3.0--3.0.0.sql Unexpected drop found for function sys.babelfishpg_tsql_get_babel_server_collation_oid in file babelfishpg_tsql--2.4.0--3.0.0.sql +Unexpected drop found for function sys.babelfishpg_tsql_get_babel_server_collation_oid in file babelfishpg_tsql--2.5.0--3.0.0.sql Unexpected drop found for function sys.pg_extension_config_remove in file babelfishpg_tsql--3.1.0--3.2.0.sql Unexpected drop found for operator sys.+ in file babelfishpg_common--1.1.0--1.2.0.sql Unexpected drop found for operator sys./ in file babelfishpg_common--1.1.0--1.2.0.sql @@ -27,6 +28,7 @@ Unexpected drop found for procedure sys.babelfish_drop_deprecated_object in file Unexpected drop found for procedure sys.babelfish_drop_deprecated_object in file babelfishpg_tsql--2.3.0--2.4.0.sql Unexpected drop found for procedure sys.babelfish_drop_deprecated_object in file babelfishpg_tsql--2.3.0--3.0.0.sql Unexpected drop found for procedure sys.babelfish_drop_deprecated_object in file babelfishpg_tsql--2.4.0--3.0.0.sql +Unexpected drop found for procedure sys.babelfish_drop_deprecated_object in file babelfishpg_tsql--2.5.0--3.0.0.sql Unexpected drop found for procedure sys.babelfish_drop_deprecated_object in file babelfishpg_tsql--3.0.0--3.1.0.sql Unexpected drop found for procedure sys.babelfish_drop_deprecated_object in file babelfishpg_tsql--3.1.0--3.2.0.sql Unexpected drop found for procedure sys.babelfish_drop_deprecated_table in file babelfishpg_tsql--2.1.0--2.2.0.sql @@ -38,6 +40,7 @@ Unexpected drop found for procedure sys.babelfish_update_collation_to_default in Unexpected drop found for procedure sys.babelfish_update_collation_to_default in file babelfishpg_tsql--2.2.0--2.3.0.sql Unexpected drop found for procedure sys.babelfish_update_collation_to_default in file babelfishpg_tsql--2.3.0--3.0.0.sql Unexpected drop found for procedure sys.babelfish_update_collation_to_default in file babelfishpg_tsql--2.4.0--3.0.0.sql +Unexpected drop found for procedure sys.babelfish_update_collation_to_default in file babelfishpg_tsql--2.5.0--3.0.0.sql Unexpected drop found for procedure sys.babelfish_update_user_catalog_for_guest in file babelfishpg_tsql--2.2.0--2.3.0.sql Unexpected drop found for procedure sys.create_xp_qv_in_master_dbo in file babelfishpg_tsql--1.1.0--1.2.0.sql Unexpected drop found for procedure sys.sp_babelfish_grant_usage_to_all in file babelfishpg_tsql--1.1.0--1.2.0.sql From 10388141d0ba2abdda4dc5edebdc1364f72445c4 Mon Sep 17 00:00:00 2001 From: Deepakshi Mittal <78574784+deepakshi-mittal@users.noreply.github.com> Date: Wed, 5 Apr 2023 10:41:55 -0700 Subject: [PATCH 046/363] Spelling Correction for select inside Create function Task: BABEL-4093 Signed-off-by: Deepakshi Mittal --- contrib/babelfishpg_tsql/src/tsqlIface.cpp | 2 +- test/JDBC/expected/BABEL-2218.out | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/babelfishpg_tsql/src/tsqlIface.cpp b/contrib/babelfishpg_tsql/src/tsqlIface.cpp index 974a37d0e7..051278b7ed 100644 --- a/contrib/babelfishpg_tsql/src/tsqlIface.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlIface.cpp @@ -1508,7 +1508,7 @@ class tsqlBuilder : public tsqlCommonMutator { /* select without destination should be blocked. We can use already information about desitnation, which is already processed. */ if (ctx->select_statement_standalone() && stmt->need_to_push_result) - throw PGErrorWrapperException(ERROR, ERRCODE_INVALID_FUNCTION_DEFINITION, "select statement returing result to a client cannot be used in a function", getLineAndPos(ctx->select_statement_standalone())); + throw PGErrorWrapperException(ERROR, ERRCODE_INVALID_FUNCTION_DEFINITION, "SELECT statement returning result to a client cannot be used in a function", getLineAndPos(ctx->select_statement_standalone())); /* T-SQL doens't allow side-effecting operations in CREATE FUNCTION */ if (ctx->insert_statement()) diff --git a/test/JDBC/expected/BABEL-2218.out b/test/JDBC/expected/BABEL-2218.out index d535f3a7c5..8b870341d3 100644 --- a/test/JDBC/expected/BABEL-2218.out +++ b/test/JDBC/expected/BABEL-2218.out @@ -19,7 +19,7 @@ END GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: select statement returing result to a client cannot be used in a function)~~ +~~ERROR (Message: SELECT statement returning result to a client cannot be used in a function)~~ -- if select statement has a destination, no error From a37ab9018982093bfce4df53a89eab0371354e6d Mon Sep 17 00:00:00 2001 From: Kristian Lejao <1741885+lejaokri@users.noreply.github.com> Date: Wed, 5 Apr 2023 11:29:00 -0700 Subject: [PATCH 047/363] [BABEL-3238] Protect get_tsql_error_details() from potential infinite loop (#1397) Signed-off-by: Kristian Lejao --- .../babelfishpg_tds/src/backend/tds/err_handler.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/contrib/babelfishpg_tds/src/backend/tds/err_handler.c b/contrib/babelfishpg_tds/src/backend/tds/err_handler.c index 462d0e36dc..ab689023a2 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/err_handler.c +++ b/contrib/babelfishpg_tds/src/backend/tds/err_handler.c @@ -193,8 +193,10 @@ get_tsql_error_details(ErrorData *edata, TDSInstrumentation(INSTR_TDS_UNMAPPED_ERROR); - elog(LOG, "Unmapped error found. Code: %d, Message: %s, File: %s, Line: %d, Context: %s", - edata->sqlerrcode, edata->message, edata->filename, edata->lineno, error_context); + /* Possible infinite loop of errors. Do not touch it further. */ + if (!error_stack_full()) + elog(LOG, "Unmapped error found. Code: %d, Message: %s, File: %s, Line: %d, Context: %s", + edata->sqlerrcode, edata->message, edata->filename, edata->lineno, error_context); return false; } @@ -263,8 +265,10 @@ get_tsql_error_details(ErrorData *edata, { TDSInstrumentation(INSTR_TDS_UNMAPPED_ERROR); - elog(LOG, "Unmapped error found. Code: %d, Message: %s, File: %s, Line: %d, Context: %s", - edata->sqlerrcode, edata->message, edata->filename, edata->lineno, error_context); + /* Possible infinite loop of errors. Do not touch it further. */ + if (!error_stack_full()) + elog(LOG, "Unmapped error found. Code: %d, Message: %s, File: %s, Line: %d, Context: %s", + edata->sqlerrcode, edata->message, edata->filename, edata->lineno, error_context); *tsql_error_code = ERRCODE_PLTSQL_ERROR_NOT_MAPPED; *tsql_error_severity = 16; From 6b394af10e079ed0b8e8bb31b1a877220cb6785c Mon Sep 17 00:00:00 2001 From: Satarupa Biswas Date: Thu, 6 Apr 2023 16:50:49 +0530 Subject: [PATCH 048/363] Support TIMEFROMPARTS(), DATETIME2FROMPARTS() Transact-SQL functions (#1371) Rectified following two functions such that: DATETIME2FROMPARTS ( year, month, day, hour, minute, seconds, fractions, precision ) returns a datetime2 value for the specified date and time arguments. The returned value has a precision specified by the precision argument. TIMEFROMPARTS ( hour, minute, seconds, fractions, precision ) returns a time value for the specified time and with the specified precision. Before Fix, the functions had type-cast mismatch while processing input data as well as while returning result after processing, which caused operator is not unique: integer > numeric error in babelfish. Fix includes handling input data using proper type as well as returning expected datatype instead of generic postgres timestamp datatype. Task: BABEL-1627, BABEL-2827, BABEL-2826 Signed-off-by: Satarupa Biswas Co-authored-by: Satarupa Biswas --- .../babelfishpg_tsql/sql/sys_functions.sql | 18 ++- .../babelfishpg_tsql--3.1.0--3.2.0.sql | 152 ++++++++++++++++++ ...tetime2fromparts-after-15-2-vu-prepare.out | 35 ++++ ...atetime2fromparts-after-15-2-vu-verify.out | 118 ++++++++++++++ .../datetime2fromparts-vu-prepare.out | 35 ++++ .../expected/datetime2fromparts-vu-verify.out | 117 ++++++++++++++ .../expected/timefromparts-vu-prepare.out | 18 +++ .../JDBC/expected/timefromparts-vu-verify.out | 69 ++++++++ ...tetime2fromparts-after-15-2-vu-prepare.sql | 35 ++++ ...atetime2fromparts-after-15-2-vu-verify.sql | 57 +++++++ .../datetime2fromparts-vu-prepare.sql | 35 ++++ .../datetime2fromparts-vu-verify.sql | 57 +++++++ .../functions/timefromparts-vu-prepare.sql | 18 +++ .../functions/timefromparts-vu-verify.sql | 29 ++++ test/JDBC/jdbc_schedule | 3 + test/JDBC/upgrade/13_4/schedule | 2 + test/JDBC/upgrade/13_5/schedule | 2 + test/JDBC/upgrade/13_6/schedule | 2 + test/JDBC/upgrade/13_7/schedule | 2 + test/JDBC/upgrade/13_8/schedule | 2 + test/JDBC/upgrade/13_9/schedule | 2 + test/JDBC/upgrade/14_3/schedule | 2 + test/JDBC/upgrade/14_5/schedule | 2 + test/JDBC/upgrade/14_6/schedule | 2 + test/JDBC/upgrade/14_7/schedule | 2 + test/JDBC/upgrade/14_8/schedule | 2 + test/JDBC/upgrade/15_1/schedule | 2 + test/JDBC/upgrade/15_2/schedule | 2 + test/JDBC/upgrade/latest/schedule | 2 + test/JDBC/upgrade/master/schedule | 2 + .../expected_create.out | 4 - .../expected_dependency.out | 2 - 32 files changed, 820 insertions(+), 12 deletions(-) create mode 100644 test/JDBC/expected/datetime2fromparts-after-15-2-vu-prepare.out create mode 100644 test/JDBC/expected/datetime2fromparts-after-15-2-vu-verify.out create mode 100644 test/JDBC/expected/datetime2fromparts-vu-prepare.out create mode 100644 test/JDBC/expected/datetime2fromparts-vu-verify.out create mode 100644 test/JDBC/expected/timefromparts-vu-prepare.out create mode 100644 test/JDBC/expected/timefromparts-vu-verify.out create mode 100644 test/JDBC/input/functions/datetime2fromparts-after-15-2-vu-prepare.sql create mode 100644 test/JDBC/input/functions/datetime2fromparts-after-15-2-vu-verify.sql create mode 100644 test/JDBC/input/functions/datetime2fromparts-vu-prepare.sql create mode 100644 test/JDBC/input/functions/datetime2fromparts-vu-verify.sql create mode 100644 test/JDBC/input/functions/timefromparts-vu-prepare.sql create mode 100644 test/JDBC/input/functions/timefromparts-vu-verify.sql diff --git a/contrib/babelfishpg_tsql/sql/sys_functions.sql b/contrib/babelfishpg_tsql/sql/sys_functions.sql index 3e66e432ec..7dde13c043 100644 --- a/contrib/babelfishpg_tsql/sql/sys_functions.sql +++ b/contrib/babelfishpg_tsql/sql/sys_functions.sql @@ -274,7 +274,7 @@ CREATE OR REPLACE FUNCTION sys.datetime2fromparts(IN p_year NUMERIC, IN p_seconds NUMERIC, IN p_fractions NUMERIC, IN p_precision NUMERIC) -RETURNS TIMESTAMP WITHOUT TIME ZONE +RETURNS sys.DATETIME2 AS $BODY$ DECLARE @@ -282,6 +282,8 @@ DECLARE v_precision SMALLINT; v_err_message VARCHAR; v_calc_seconds NUMERIC; + v_resdatetime TIMESTAMP WITHOUT TIME ZONE; + v_string pg_catalog.text; BEGIN v_fractions := floor(p_fractions)::INTEGER::VARCHAR; v_precision := p_precision::SMALLINT; @@ -295,7 +297,7 @@ BEGIN (p_minute::SMALLINT NOT BETWEEN 0 AND 59) OR (p_seconds::SMALLINT NOT BETWEEN 0 AND 59) OR (p_fractions::SMALLINT NOT BETWEEN 0 AND 9999999) OR - (p_fractions::SMALLINT != 0 AND char_length(v_fractions) > p_precision)) + (p_fractions::SMALLINT != 0 AND char_length(v_fractions) > v_precision)) THEN RAISE invalid_datetime_format; ELSIF (v_precision NOT BETWEEN 0 AND 7) THEN @@ -304,14 +306,18 @@ BEGIN v_calc_seconds := pg_catalog.format('%s.%s', floor(p_seconds)::SMALLINT, - substring(rpad(lpad(v_fractions, v_precision, '0'), 7, '0'), 1, 6))::NUMERIC; + substring(rpad(lpad(v_fractions, v_precision, '0'), 7, '0'), 1, v_precision))::NUMERIC; - RETURN make_timestamp(floor(p_year)::SMALLINT, + v_resdatetime := make_timestamp(floor(p_year)::SMALLINT, floor(p_month)::SMALLINT, floor(p_day)::SMALLINT, floor(p_hour)::SMALLINT, floor(p_minute)::SMALLINT, v_calc_seconds); + + v_string := v_resdatetime::pg_catalog.text; + + RETURN CAST(v_string AS sys.DATETIME2); EXCEPTION WHEN most_specific_type_mismatch THEN RAISE USING MESSAGE := 'Scale argument is not valid. Valid expressions for data type DATETIME2 scale argument are integer constants and integer constant expressions.', @@ -579,7 +585,7 @@ BEGIN (p_minute::SMALLINT NOT BETWEEN 0 AND 59) OR (p_seconds::SMALLINT NOT BETWEEN 0 AND 59) OR (p_fractions::SMALLINT NOT BETWEEN 0 AND 9999999) OR - (p_fractions::SMALLINT != 0 AND char_length(v_fractions) > p_precision)) + (p_fractions::SMALLINT != 0 AND char_length(v_fractions) > v_precision)) THEN RAISE invalid_datetime_format; ELSIF (v_precision NOT BETWEEN 0 AND 7) THEN @@ -588,7 +594,7 @@ BEGIN v_calc_seconds := pg_catalog.format('%s.%s', floor(p_seconds)::SMALLINT, - substring(rpad(lpad(v_fractions, v_precision, '0'), 7, '0'), 1, 6))::NUMERIC; + substring(rpad(lpad(v_fractions, v_precision, '0'), 7, '0'), 1, v_precision))::NUMERIC; RETURN make_time(floor(p_hour)::SMALLINT, floor(p_minute)::SMALLINT, diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql index 0dbe8736b2..3b60d6058e 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql @@ -767,6 +767,158 @@ CREATE OR REPLACE VIEW sys.sp_databases_view AS GROUP BY database_name ORDER BY database_name; +ALTER FUNCTION sys.datetime2fromparts(NUMERIC, NUMERIC, NUMERIC, NUMERIC, NUMERIC, NUMERIC, NUMERIC, NUMERIC) RENAME TO datetime2fromparts_deprecated_3_2; +CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'datetime2fromparts_deprecated_3_2'); + +CREATE OR REPLACE FUNCTION sys.datetime2fromparts(IN p_year NUMERIC, + IN p_month NUMERIC, + IN p_day NUMERIC, + IN p_hour NUMERIC, + IN p_minute NUMERIC, + IN p_seconds NUMERIC, + IN p_fractions NUMERIC, + IN p_precision NUMERIC) +RETURNS sys.DATETIME2 +AS +$BODY$ +DECLARE + v_fractions VARCHAR; + v_precision SMALLINT; + v_err_message VARCHAR; + v_calc_seconds NUMERIC; + v_resdatetime TIMESTAMP WITHOUT TIME ZONE; + v_string pg_catalog.text; +BEGIN + v_fractions := floor(p_fractions)::INTEGER::VARCHAR; + v_precision := p_precision::SMALLINT; + + IF (scale(p_precision) > 0) THEN + RAISE most_specific_type_mismatch; + ELSIF ((p_year::SMALLINT NOT BETWEEN 1 AND 9999) OR + (p_month::SMALLINT NOT BETWEEN 1 AND 12) OR + (p_day::SMALLINT NOT BETWEEN 1 AND 31) OR + (p_hour::SMALLINT NOT BETWEEN 0 AND 23) OR + (p_minute::SMALLINT NOT BETWEEN 0 AND 59) OR + (p_seconds::SMALLINT NOT BETWEEN 0 AND 59) OR + (p_fractions::SMALLINT NOT BETWEEN 0 AND 9999999) OR + (p_fractions::SMALLINT != 0 AND char_length(v_fractions) > v_precision)) + THEN + RAISE invalid_datetime_format; + ELSIF (v_precision NOT BETWEEN 0 AND 7) THEN + RAISE invalid_parameter_value; + END IF; + + v_calc_seconds := pg_catalog.format('%s.%s', + floor(p_seconds)::SMALLINT, + substring(rpad(lpad(v_fractions, v_precision, '0'), 7, '0'), 1, v_precision))::NUMERIC; + + v_resdatetime := make_timestamp(floor(p_year)::SMALLINT, + floor(p_month)::SMALLINT, + floor(p_day)::SMALLINT, + floor(p_hour)::SMALLINT, + floor(p_minute)::SMALLINT, + v_calc_seconds); + + v_string := v_resdatetime::pg_catalog.text; + + RETURN CAST(v_string AS sys.DATETIME2); +EXCEPTION + WHEN most_specific_type_mismatch THEN + RAISE USING MESSAGE := 'Scale argument is not valid. Valid expressions for data type DATETIME2 scale argument are integer constants and integer constant expressions.', + DETAIL := 'Use of incorrect "precision" parameter value during conversion process.', + HINT := 'Change "precision" parameter to the proper value and try again.'; + + WHEN invalid_parameter_value THEN + RAISE USING MESSAGE := pg_catalog.format('Specified scale %s is invalid.', v_precision), + DETAIL := 'Use of incorrect "precision" parameter value during conversion process.', + HINT := 'Change "precision" parameter to the proper value and try again.'; + + WHEN invalid_datetime_format THEN + RAISE USING MESSAGE := 'Cannot construct data type DATETIME2, some of the arguments have values which are not valid.', + DETAIL := 'Possible use of incorrect value of date or time part (which lies outside of valid range).', + HINT := 'Check each input argument belongs to the valid range and try again.'; + + WHEN numeric_value_out_of_range THEN + GET STACKED DIAGNOSTICS v_err_message = MESSAGE_TEXT; + v_err_message := upper(split_part(v_err_message, ' ', 1)); + + RAISE USING MESSAGE := pg_catalog.format('Error while trying to cast to %s data type.', v_err_message), + DETAIL := pg_catalog.format('Source value is out of %s data type range.', v_err_message), + HINT := pg_catalog.format('Correct the source value you are trying to cast to %s data type and try again.', + v_err_message); +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE +RETURNS NULL ON NULL INPUT; + +CREATE OR REPLACE FUNCTION sys.timefromparts(IN p_hour NUMERIC, + IN p_minute NUMERIC, + IN p_seconds NUMERIC, + IN p_fractions NUMERIC, + IN p_precision NUMERIC) +RETURNS TIME WITHOUT TIME ZONE +AS +$BODY$ +DECLARE + v_fractions VARCHAR; + v_precision SMALLINT; + v_err_message VARCHAR; + v_calc_seconds NUMERIC; +BEGIN + v_fractions := floor(p_fractions)::INTEGER::VARCHAR; + v_precision := p_precision::SMALLINT; + + IF (scale(p_precision) > 0) THEN + RAISE most_specific_type_mismatch; + ELSIF ((p_hour::SMALLINT NOT BETWEEN 0 AND 23) OR + (p_minute::SMALLINT NOT BETWEEN 0 AND 59) OR + (p_seconds::SMALLINT NOT BETWEEN 0 AND 59) OR + (p_fractions::SMALLINT NOT BETWEEN 0 AND 9999999) OR + (p_fractions::SMALLINT != 0 AND char_length(v_fractions) > v_precision)) + THEN + RAISE invalid_datetime_format; + ELSIF (v_precision NOT BETWEEN 0 AND 7) THEN + RAISE numeric_value_out_of_range; + END IF; + + v_calc_seconds := pg_catalog.format('%s.%s', + floor(p_seconds)::SMALLINT, + substring(rpad(lpad(v_fractions, v_precision, '0'), 7, '0'), 1, v_precision))::NUMERIC; + + RETURN make_time(floor(p_hour)::SMALLINT, + floor(p_minute)::SMALLINT, + v_calc_seconds); +EXCEPTION + WHEN most_specific_type_mismatch THEN + RAISE USING MESSAGE := 'Scale argument is not valid. Valid expressions for data type DATETIME2 scale argument are integer constants and integer constant expressions.', + DETAIL := 'Use of incorrect "precision" parameter value during conversion process.', + HINT := 'Change "precision" parameter to the proper value and try again.'; + + WHEN invalid_parameter_value THEN + RAISE USING MESSAGE := pg_catalog.format('Specified scale %s is invalid.', v_precision), + DETAIL := 'Use of incorrect "precision" parameter value during conversion process.', + HINT := 'Change "precision" parameter to the proper value and try again.'; + + WHEN invalid_datetime_format THEN + RAISE USING MESSAGE := 'Cannot construct data type time, some of the arguments have values which are not valid.', + DETAIL := 'Possible use of incorrect value of time part (which lies outside of valid range).', + HINT := 'Check each input argument belongs to the valid range and try again.'; + + WHEN numeric_value_out_of_range THEN + GET STACKED DIAGNOSTICS v_err_message = MESSAGE_TEXT; + v_err_message := upper(split_part(v_err_message, ' ', 1)); + + RAISE USING MESSAGE := pg_catalog.format('Error while trying to cast to %s data type.', v_err_message), + DETAIL := pg_catalog.format('Source value is out of %s data type range.', v_err_message), + HINT := pg_catalog.format('Correct the source value you are trying to cast to %s data type and try again.', + v_err_message); +END; +$BODY$ +LANGUAGE plpgsql +VOLATILE +RETURNS NULL ON NULL INPUT; + -- Drops the temporary procedure used by the upgrade script. -- Please have this be one of the last statements executed in this upgrade script. DROP PROCEDURE sys.babelfish_drop_deprecated_object(varchar, varchar, varchar); diff --git a/test/JDBC/expected/datetime2fromparts-after-15-2-vu-prepare.out b/test/JDBC/expected/datetime2fromparts-after-15-2-vu-prepare.out new file mode 100644 index 0000000000..2cd9b7972b --- /dev/null +++ b/test/JDBC/expected/datetime2fromparts-after-15-2-vu-prepare.out @@ -0,0 +1,35 @@ +-- [BABEL-1627, 2827] Support DATETIME2FROMPARTS Transact-SQL function +CREATE VIEW datetime2fromparts_vu_prepare_v1 AS (select DATETIME2FROMPARTS(1962, 16, 1, 14, 64, 48, 59, 5 )); +GO + +CREATE VIEW datetime2fromparts_vu_prepare_v2 AS (select DATETIME2FROMPARTS(20008, 8, 32, 34, 23, 78, 45, 8 )); +GO + +CREATE VIEW datetime2fromparts_vu_prepare_v3 AS (select DATETIME2FROMPARTS(1980, 11, 25, 22, 09, 58, 671, 4 )); +GO + +CREATE PROCEDURE datetime2fromparts_vu_prepare_p1 AS (select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 1 )); +GO + +CREATE PROCEDURE datetime2fromparts_vu_prepare_p2 AS (select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 2 )); +GO + +CREATE PROCEDURE datetime2fromparts_vu_prepare_p3 AS (select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 3 )); +GO + +CREATE PROCEDURE datetime2fromparts_vu_prepare_p4 AS (select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 4 )); +GO + +CREATE FUNCTION datetime2fromparts_vu_prepare_f1() +RETURNS DATETIME2 AS +BEGIN +RETURN (select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 5 )); +END +GO + +CREATE FUNCTION datetime2fromparts_vu_prepare_f2() +RETURNS DATETIME2 AS +BEGIN +RETURN (select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 6 )); +END +GO diff --git a/test/JDBC/expected/datetime2fromparts-after-15-2-vu-verify.out b/test/JDBC/expected/datetime2fromparts-after-15-2-vu-verify.out new file mode 100644 index 0000000000..e0340e83aa --- /dev/null +++ b/test/JDBC/expected/datetime2fromparts-after-15-2-vu-verify.out @@ -0,0 +1,118 @@ +-- [BABEL-1627, 2827] Support DATETIME2FROMPARTS Transact-SQL function +select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 0 ); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type DATETIME2, some of the arguments have values which are not valid.)~~ + + +select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 7 ); +GO +~~START~~ +datetime2 +2011-08-15 14:23:44.0000000 +~~END~~ + + +select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 8 ); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Specified scale 8 is invalid.)~~ + + +SELECT DATETIME2FROMPARTS ( 2010, 12, 31, 23, 59, 59, 0, 0 ) AS Result; +GO +~~START~~ +datetime2 +2010-12-31 23:59:59.0000000 +~~END~~ + + +SELECT * FROM datetime2fromparts_vu_prepare_v1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type DATETIME2, some of the arguments have values which are not valid.)~~ + +DROP VIEW datetime2fromparts_vu_prepare_v1 +GO + +SELECT * FROM datetime2fromparts_vu_prepare_v2 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type DATETIME2, some of the arguments have values which are not valid.)~~ + +DROP VIEW datetime2fromparts_vu_prepare_v2 +GO + +SELECT * FROM datetime2fromparts_vu_prepare_v3 +GO +~~START~~ +datetime2 +1980-11-25 22:09:58.0671000 +~~END~~ + +DROP VIEW datetime2fromparts_vu_prepare_v3 +GO + +EXEC datetime2fromparts_vu_prepare_p1 +GO +~~START~~ +datetime2 +2011-08-15 14:23:44.5000000 +~~END~~ + +DROP PROCEDURE datetime2fromparts_vu_prepare_p1 +GO + +EXEC datetime2fromparts_vu_prepare_p2 +GO +~~START~~ +datetime2 +2011-08-15 14:23:44.0500000 +~~END~~ + +DROP PROCEDURE datetime2fromparts_vu_prepare_p2 +GO + +EXEC datetime2fromparts_vu_prepare_p3 +GO +~~START~~ +datetime2 +2011-08-15 14:23:44.0050000 +~~END~~ + +DROP PROCEDURE datetime2fromparts_vu_prepare_p3 +GO + +EXEC datetime2fromparts_vu_prepare_p4 +GO +~~START~~ +datetime2 +2011-08-15 14:23:44.0005000 +~~END~~ + +DROP PROCEDURE datetime2fromparts_vu_prepare_p4 +GO + +SELECT datetime2fromparts_vu_prepare_f1() +GO +~~START~~ +datetime2 +2011-08-15 14:23:44.0000500 +~~END~~ + +DROP FUNCTION datetime2fromparts_vu_prepare_f1() +GO + +SELECT datetime2fromparts_vu_prepare_f2() +GO +~~START~~ +datetime2 +2011-08-15 14:23:44.0000050 +~~END~~ + +DROP FUNCTION datetime2fromparts_vu_prepare_f2() +GO diff --git a/test/JDBC/expected/datetime2fromparts-vu-prepare.out b/test/JDBC/expected/datetime2fromparts-vu-prepare.out new file mode 100644 index 0000000000..2cd9b7972b --- /dev/null +++ b/test/JDBC/expected/datetime2fromparts-vu-prepare.out @@ -0,0 +1,35 @@ +-- [BABEL-1627, 2827] Support DATETIME2FROMPARTS Transact-SQL function +CREATE VIEW datetime2fromparts_vu_prepare_v1 AS (select DATETIME2FROMPARTS(1962, 16, 1, 14, 64, 48, 59, 5 )); +GO + +CREATE VIEW datetime2fromparts_vu_prepare_v2 AS (select DATETIME2FROMPARTS(20008, 8, 32, 34, 23, 78, 45, 8 )); +GO + +CREATE VIEW datetime2fromparts_vu_prepare_v3 AS (select DATETIME2FROMPARTS(1980, 11, 25, 22, 09, 58, 671, 4 )); +GO + +CREATE PROCEDURE datetime2fromparts_vu_prepare_p1 AS (select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 1 )); +GO + +CREATE PROCEDURE datetime2fromparts_vu_prepare_p2 AS (select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 2 )); +GO + +CREATE PROCEDURE datetime2fromparts_vu_prepare_p3 AS (select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 3 )); +GO + +CREATE PROCEDURE datetime2fromparts_vu_prepare_p4 AS (select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 4 )); +GO + +CREATE FUNCTION datetime2fromparts_vu_prepare_f1() +RETURNS DATETIME2 AS +BEGIN +RETURN (select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 5 )); +END +GO + +CREATE FUNCTION datetime2fromparts_vu_prepare_f2() +RETURNS DATETIME2 AS +BEGIN +RETURN (select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 6 )); +END +GO diff --git a/test/JDBC/expected/datetime2fromparts-vu-verify.out b/test/JDBC/expected/datetime2fromparts-vu-verify.out new file mode 100644 index 0000000000..9d32d1ad20 --- /dev/null +++ b/test/JDBC/expected/datetime2fromparts-vu-verify.out @@ -0,0 +1,117 @@ +-- [BABEL-1627, 2827] Support DATETIME2FROMPARTS Transact-SQL function +select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 0 ); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type DATETIME2, some of the arguments have values which are not valid.)~~ + + +select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 7 ); +GO +~~START~~ +datetime2 +2011-08-15 14:23:44.0000000 +~~END~~ + + +select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 8 ); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Specified scale 8 is invalid.)~~ + + +SELECT DATETIME2FROMPARTS ( 2010, 12, 31, 23, 59, 59, 0, 0 ) AS Result; +GO +~~START~~ +datetime2 +2010-12-31 23:59:59.0000000 +~~END~~ + + +SELECT * FROM datetime2fromparts_vu_prepare_v1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: operator is not unique: integer > numeric)~~ + +DROP VIEW datetime2fromparts_vu_prepare_v1 +GO + +SELECT * FROM datetime2fromparts_vu_prepare_v2 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: operator is not unique: integer > numeric)~~ + +DROP VIEW datetime2fromparts_vu_prepare_v2 +GO + +SELECT * FROM datetime2fromparts_vu_prepare_v3 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: operator is not unique: integer > numeric)~~ + +DROP VIEW datetime2fromparts_vu_prepare_v3 +GO + +EXEC datetime2fromparts_vu_prepare_p1 +GO +~~START~~ +datetime2 +2011-08-15 14:23:44.5000000 +~~END~~ + +DROP PROCEDURE datetime2fromparts_vu_prepare_p1 +GO + +EXEC datetime2fromparts_vu_prepare_p2 +GO +~~START~~ +datetime2 +2011-08-15 14:23:44.0500000 +~~END~~ + +DROP PROCEDURE datetime2fromparts_vu_prepare_p2 +GO + +EXEC datetime2fromparts_vu_prepare_p3 +GO +~~START~~ +datetime2 +2011-08-15 14:23:44.0050000 +~~END~~ + +DROP PROCEDURE datetime2fromparts_vu_prepare_p3 +GO + +EXEC datetime2fromparts_vu_prepare_p4 +GO +~~START~~ +datetime2 +2011-08-15 14:23:44.0005000 +~~END~~ + +DROP PROCEDURE datetime2fromparts_vu_prepare_p4 +GO + +SELECT datetime2fromparts_vu_prepare_f1() +GO +~~START~~ +datetime2 +2011-08-15 14:23:44.0000500 +~~END~~ + +DROP FUNCTION datetime2fromparts_vu_prepare_f1() +GO + +SELECT datetime2fromparts_vu_prepare_f2() +GO +~~START~~ +datetime2 +2011-08-15 14:23:44.0000050 +~~END~~ + +DROP FUNCTION datetime2fromparts_vu_prepare_f2() +GO diff --git a/test/JDBC/expected/timefromparts-vu-prepare.out b/test/JDBC/expected/timefromparts-vu-prepare.out new file mode 100644 index 0000000000..5e7554f0cc --- /dev/null +++ b/test/JDBC/expected/timefromparts-vu-prepare.out @@ -0,0 +1,18 @@ +-- [BABEL-2826] Support TIMEFROMPARTS Transact-SQL function +CREATE VIEW timefromparts_vu_prepare_v1 AS (SELECT TIMEFROMPARTS ( 23, 59, 59, 0, 0)); +GO + +CREATE VIEW timefromparts_vu_prepare_v2 AS (SELECT TIMEFROMPARTS ( 23, 59, 59, 456, 5)); +GO + +-- error expected, fractional part should not be larger than scale +CREATE PROCEDURE timefromparts_vu_prepare_p1 AS (SELECT TIMEFROMPARTS ( 23, 59, 59, 5678, 3)); +GO + +-- error expected, scale > 7 +CREATE FUNCTION timefromparts_vu_prepare_f1() +RETURNS TIME AS +BEGIN +RETURN (SELECT TIMEFROMPARTS ( 23, 59, 59, 52, 8)); +END +GO diff --git a/test/JDBC/expected/timefromparts-vu-verify.out b/test/JDBC/expected/timefromparts-vu-verify.out new file mode 100644 index 0000000000..762d77677b --- /dev/null +++ b/test/JDBC/expected/timefromparts-vu-verify.out @@ -0,0 +1,69 @@ +-- [BABEL-2826] Support TIMEFROMPARTS Transact-SQL function +select TIMEFROMPARTS(24, 23, 54, 35, 2 ); +GO +~~START~~ +time +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type time, some of the arguments have values which are not valid.)~~ + + +select TIMEFROMPARTS(18, 63, 49, 75, 5 ); +GO +~~START~~ +time +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type time, some of the arguments have values which are not valid.)~~ + + +select TIMEFROMPARTS(08, 39, 84, 589, 3 ); +GO +~~START~~ +time +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type time, some of the arguments have values which are not valid.)~~ + + +SELECT * FROM timefromparts_vu_prepare_v1 +GO +~~START~~ +time +23:59:59.0000000 +~~END~~ + +DROP VIEW timefromparts_vu_prepare_v1 +GO + +SELECT * FROM timefromparts_vu_prepare_v2 +GO +~~START~~ +time +23:59:59.0045600 +~~END~~ + +DROP VIEW timefromparts_vu_prepare_v2 +GO + +EXEC timefromparts_vu_prepare_p1 +GO +~~START~~ +time +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type time, some of the arguments have values which are not valid.)~~ + +DROP PROCEDURE timefromparts_vu_prepare_p1 +GO + +SELECT timefromparts_vu_prepare_f1() +GO +~~START~~ +time +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Error while trying to cast to NUMERIC_VALUE_OUT_OF_RANGE data type.)~~ + +DROP FUNCTION timefromparts_vu_prepare_f1() +GO diff --git a/test/JDBC/input/functions/datetime2fromparts-after-15-2-vu-prepare.sql b/test/JDBC/input/functions/datetime2fromparts-after-15-2-vu-prepare.sql new file mode 100644 index 0000000000..2cd9b7972b --- /dev/null +++ b/test/JDBC/input/functions/datetime2fromparts-after-15-2-vu-prepare.sql @@ -0,0 +1,35 @@ +-- [BABEL-1627, 2827] Support DATETIME2FROMPARTS Transact-SQL function +CREATE VIEW datetime2fromparts_vu_prepare_v1 AS (select DATETIME2FROMPARTS(1962, 16, 1, 14, 64, 48, 59, 5 )); +GO + +CREATE VIEW datetime2fromparts_vu_prepare_v2 AS (select DATETIME2FROMPARTS(20008, 8, 32, 34, 23, 78, 45, 8 )); +GO + +CREATE VIEW datetime2fromparts_vu_prepare_v3 AS (select DATETIME2FROMPARTS(1980, 11, 25, 22, 09, 58, 671, 4 )); +GO + +CREATE PROCEDURE datetime2fromparts_vu_prepare_p1 AS (select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 1 )); +GO + +CREATE PROCEDURE datetime2fromparts_vu_prepare_p2 AS (select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 2 )); +GO + +CREATE PROCEDURE datetime2fromparts_vu_prepare_p3 AS (select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 3 )); +GO + +CREATE PROCEDURE datetime2fromparts_vu_prepare_p4 AS (select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 4 )); +GO + +CREATE FUNCTION datetime2fromparts_vu_prepare_f1() +RETURNS DATETIME2 AS +BEGIN +RETURN (select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 5 )); +END +GO + +CREATE FUNCTION datetime2fromparts_vu_prepare_f2() +RETURNS DATETIME2 AS +BEGIN +RETURN (select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 6 )); +END +GO diff --git a/test/JDBC/input/functions/datetime2fromparts-after-15-2-vu-verify.sql b/test/JDBC/input/functions/datetime2fromparts-after-15-2-vu-verify.sql new file mode 100644 index 0000000000..4adb2ecd5c --- /dev/null +++ b/test/JDBC/input/functions/datetime2fromparts-after-15-2-vu-verify.sql @@ -0,0 +1,57 @@ +-- [BABEL-1627, 2827] Support DATETIME2FROMPARTS Transact-SQL function +select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 0 ); +GO + +select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 7 ); +GO + +select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 8 ); +GO + +SELECT DATETIME2FROMPARTS ( 2010, 12, 31, 23, 59, 59, 0, 0 ) AS Result; +GO + +SELECT * FROM datetime2fromparts_vu_prepare_v1 +GO +DROP VIEW datetime2fromparts_vu_prepare_v1 +GO + +SELECT * FROM datetime2fromparts_vu_prepare_v2 +GO +DROP VIEW datetime2fromparts_vu_prepare_v2 +GO + +SELECT * FROM datetime2fromparts_vu_prepare_v3 +GO +DROP VIEW datetime2fromparts_vu_prepare_v3 +GO + +EXEC datetime2fromparts_vu_prepare_p1 +GO +DROP PROCEDURE datetime2fromparts_vu_prepare_p1 +GO + +EXEC datetime2fromparts_vu_prepare_p2 +GO +DROP PROCEDURE datetime2fromparts_vu_prepare_p2 +GO + +EXEC datetime2fromparts_vu_prepare_p3 +GO +DROP PROCEDURE datetime2fromparts_vu_prepare_p3 +GO + +EXEC datetime2fromparts_vu_prepare_p4 +GO +DROP PROCEDURE datetime2fromparts_vu_prepare_p4 +GO + +SELECT datetime2fromparts_vu_prepare_f1() +GO +DROP FUNCTION datetime2fromparts_vu_prepare_f1() +GO + +SELECT datetime2fromparts_vu_prepare_f2() +GO +DROP FUNCTION datetime2fromparts_vu_prepare_f2() +GO diff --git a/test/JDBC/input/functions/datetime2fromparts-vu-prepare.sql b/test/JDBC/input/functions/datetime2fromparts-vu-prepare.sql new file mode 100644 index 0000000000..2cd9b7972b --- /dev/null +++ b/test/JDBC/input/functions/datetime2fromparts-vu-prepare.sql @@ -0,0 +1,35 @@ +-- [BABEL-1627, 2827] Support DATETIME2FROMPARTS Transact-SQL function +CREATE VIEW datetime2fromparts_vu_prepare_v1 AS (select DATETIME2FROMPARTS(1962, 16, 1, 14, 64, 48, 59, 5 )); +GO + +CREATE VIEW datetime2fromparts_vu_prepare_v2 AS (select DATETIME2FROMPARTS(20008, 8, 32, 34, 23, 78, 45, 8 )); +GO + +CREATE VIEW datetime2fromparts_vu_prepare_v3 AS (select DATETIME2FROMPARTS(1980, 11, 25, 22, 09, 58, 671, 4 )); +GO + +CREATE PROCEDURE datetime2fromparts_vu_prepare_p1 AS (select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 1 )); +GO + +CREATE PROCEDURE datetime2fromparts_vu_prepare_p2 AS (select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 2 )); +GO + +CREATE PROCEDURE datetime2fromparts_vu_prepare_p3 AS (select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 3 )); +GO + +CREATE PROCEDURE datetime2fromparts_vu_prepare_p4 AS (select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 4 )); +GO + +CREATE FUNCTION datetime2fromparts_vu_prepare_f1() +RETURNS DATETIME2 AS +BEGIN +RETURN (select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 5 )); +END +GO + +CREATE FUNCTION datetime2fromparts_vu_prepare_f2() +RETURNS DATETIME2 AS +BEGIN +RETURN (select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 6 )); +END +GO diff --git a/test/JDBC/input/functions/datetime2fromparts-vu-verify.sql b/test/JDBC/input/functions/datetime2fromparts-vu-verify.sql new file mode 100644 index 0000000000..4adb2ecd5c --- /dev/null +++ b/test/JDBC/input/functions/datetime2fromparts-vu-verify.sql @@ -0,0 +1,57 @@ +-- [BABEL-1627, 2827] Support DATETIME2FROMPARTS Transact-SQL function +select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 0 ); +GO + +select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 7 ); +GO + +select DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 8 ); +GO + +SELECT DATETIME2FROMPARTS ( 2010, 12, 31, 23, 59, 59, 0, 0 ) AS Result; +GO + +SELECT * FROM datetime2fromparts_vu_prepare_v1 +GO +DROP VIEW datetime2fromparts_vu_prepare_v1 +GO + +SELECT * FROM datetime2fromparts_vu_prepare_v2 +GO +DROP VIEW datetime2fromparts_vu_prepare_v2 +GO + +SELECT * FROM datetime2fromparts_vu_prepare_v3 +GO +DROP VIEW datetime2fromparts_vu_prepare_v3 +GO + +EXEC datetime2fromparts_vu_prepare_p1 +GO +DROP PROCEDURE datetime2fromparts_vu_prepare_p1 +GO + +EXEC datetime2fromparts_vu_prepare_p2 +GO +DROP PROCEDURE datetime2fromparts_vu_prepare_p2 +GO + +EXEC datetime2fromparts_vu_prepare_p3 +GO +DROP PROCEDURE datetime2fromparts_vu_prepare_p3 +GO + +EXEC datetime2fromparts_vu_prepare_p4 +GO +DROP PROCEDURE datetime2fromparts_vu_prepare_p4 +GO + +SELECT datetime2fromparts_vu_prepare_f1() +GO +DROP FUNCTION datetime2fromparts_vu_prepare_f1() +GO + +SELECT datetime2fromparts_vu_prepare_f2() +GO +DROP FUNCTION datetime2fromparts_vu_prepare_f2() +GO diff --git a/test/JDBC/input/functions/timefromparts-vu-prepare.sql b/test/JDBC/input/functions/timefromparts-vu-prepare.sql new file mode 100644 index 0000000000..5e7554f0cc --- /dev/null +++ b/test/JDBC/input/functions/timefromparts-vu-prepare.sql @@ -0,0 +1,18 @@ +-- [BABEL-2826] Support TIMEFROMPARTS Transact-SQL function +CREATE VIEW timefromparts_vu_prepare_v1 AS (SELECT TIMEFROMPARTS ( 23, 59, 59, 0, 0)); +GO + +CREATE VIEW timefromparts_vu_prepare_v2 AS (SELECT TIMEFROMPARTS ( 23, 59, 59, 456, 5)); +GO + +-- error expected, fractional part should not be larger than scale +CREATE PROCEDURE timefromparts_vu_prepare_p1 AS (SELECT TIMEFROMPARTS ( 23, 59, 59, 5678, 3)); +GO + +-- error expected, scale > 7 +CREATE FUNCTION timefromparts_vu_prepare_f1() +RETURNS TIME AS +BEGIN +RETURN (SELECT TIMEFROMPARTS ( 23, 59, 59, 52, 8)); +END +GO diff --git a/test/JDBC/input/functions/timefromparts-vu-verify.sql b/test/JDBC/input/functions/timefromparts-vu-verify.sql new file mode 100644 index 0000000000..5768cddd55 --- /dev/null +++ b/test/JDBC/input/functions/timefromparts-vu-verify.sql @@ -0,0 +1,29 @@ +-- [BABEL-2826] Support TIMEFROMPARTS Transact-SQL function +select TIMEFROMPARTS(24, 23, 54, 35, 2 ); +GO + +select TIMEFROMPARTS(18, 63, 49, 75, 5 ); +GO + +select TIMEFROMPARTS(08, 39, 84, 589, 3 ); +GO + +SELECT * FROM timefromparts_vu_prepare_v1 +GO +DROP VIEW timefromparts_vu_prepare_v1 +GO + +SELECT * FROM timefromparts_vu_prepare_v2 +GO +DROP VIEW timefromparts_vu_prepare_v2 +GO + +EXEC timefromparts_vu_prepare_p1 +GO +DROP PROCEDURE timefromparts_vu_prepare_p1 +GO + +SELECT timefromparts_vu_prepare_f1() +GO +DROP FUNCTION timefromparts_vu_prepare_f1() +GO diff --git a/test/JDBC/jdbc_schedule b/test/JDBC/jdbc_schedule index d231123ceb..7a2cda7b30 100644 --- a/test/JDBC/jdbc_schedule +++ b/test/JDBC/jdbc_schedule @@ -108,6 +108,9 @@ ignore#!#test_windows_login_before_15_2-vu-cleanup ignore#!#datediff_internal_date-before-14_7-or-15_2-vu-prepare ignore#!#datediff_internal_date-before-14_7-or-15_2-vu-verify ignore#!#datediff_internal_date-before-14_7-or-15_2-vu-cleanup +ignore#!#datetime2fromparts-vu-prepare +ignore#!#datetime2fromparts-vu-verify +ignore#!#datetime2fromparts-vu-cleanup # These tests are meant for only upgrade ignore#!#openquery_upgrd-vu-prepare diff --git a/test/JDBC/upgrade/13_4/schedule b/test/JDBC/upgrade/13_4/schedule index 6b4c0941a8..4b89f15462 100644 --- a/test/JDBC/upgrade/13_4/schedule +++ b/test/JDBC/upgrade/13_4/schedule @@ -200,3 +200,5 @@ BABEL-3938 rowcount BABEL-1625 BABEL-3474 +datetime2fromparts +timefromparts diff --git a/test/JDBC/upgrade/13_5/schedule b/test/JDBC/upgrade/13_5/schedule index b297bdf61e..51e850df52 100644 --- a/test/JDBC/upgrade/13_5/schedule +++ b/test/JDBC/upgrade/13_5/schedule @@ -251,3 +251,5 @@ BABEL-3938 rowcount BABEL-1625 BABEL-3474 +datetime2fromparts +timefromparts diff --git a/test/JDBC/upgrade/13_6/schedule b/test/JDBC/upgrade/13_6/schedule index 2e74e8f8b7..3375969143 100644 --- a/test/JDBC/upgrade/13_6/schedule +++ b/test/JDBC/upgrade/13_6/schedule @@ -310,3 +310,5 @@ BABEL-3938 rowcount BABEL-1625 BABEL-3474 +datetime2fromparts +timefromparts diff --git a/test/JDBC/upgrade/13_7/schedule b/test/JDBC/upgrade/13_7/schedule index b42b9a1e08..3e1acc5c81 100644 --- a/test/JDBC/upgrade/13_7/schedule +++ b/test/JDBC/upgrade/13_7/schedule @@ -305,3 +305,5 @@ BABEL-3938 rowcount BABEL-1625 BABEL-3474 +datetime2fromparts +timefromparts diff --git a/test/JDBC/upgrade/13_8/schedule b/test/JDBC/upgrade/13_8/schedule index b42b9a1e08..3e1acc5c81 100644 --- a/test/JDBC/upgrade/13_8/schedule +++ b/test/JDBC/upgrade/13_8/schedule @@ -305,3 +305,5 @@ BABEL-3938 rowcount BABEL-1625 BABEL-3474 +datetime2fromparts +timefromparts diff --git a/test/JDBC/upgrade/13_9/schedule b/test/JDBC/upgrade/13_9/schedule index bf2092985f..c8e76cf070 100644 --- a/test/JDBC/upgrade/13_9/schedule +++ b/test/JDBC/upgrade/13_9/schedule @@ -308,3 +308,5 @@ BABEL-3938 rowcount BABEL-1625 BABEL-3474 +datetime2fromparts +timefromparts diff --git a/test/JDBC/upgrade/14_3/schedule b/test/JDBC/upgrade/14_3/schedule index 4c5f507317..f65a0b81e6 100644 --- a/test/JDBC/upgrade/14_3/schedule +++ b/test/JDBC/upgrade/14_3/schedule @@ -323,3 +323,5 @@ binary-index rowcount BABEL-1625 BABEL-3474 +datetime2fromparts +timefromparts diff --git a/test/JDBC/upgrade/14_5/schedule b/test/JDBC/upgrade/14_5/schedule index c0a0f5e4fd..a5dd2476ab 100644 --- a/test/JDBC/upgrade/14_5/schedule +++ b/test/JDBC/upgrade/14_5/schedule @@ -337,3 +337,5 @@ binary-index rowcount BABEL-1625 BABEL-3474 +datetime2fromparts +timefromparts diff --git a/test/JDBC/upgrade/14_6/schedule b/test/JDBC/upgrade/14_6/schedule index 02bbdc0d5e..e306632d4c 100644 --- a/test/JDBC/upgrade/14_6/schedule +++ b/test/JDBC/upgrade/14_6/schedule @@ -363,3 +363,5 @@ rowcount BABEL-1625 BABEL-3474 dateadd_internal_df +datetime2fromparts +timefromparts diff --git a/test/JDBC/upgrade/14_7/schedule b/test/JDBC/upgrade/14_7/schedule index d424e13be3..e1eb1f06df 100644 --- a/test/JDBC/upgrade/14_7/schedule +++ b/test/JDBC/upgrade/14_7/schedule @@ -394,3 +394,5 @@ rowcount BABEL-1625 BABEL-3474 dateadd_internal_df +datetime2fromparts +timefromparts diff --git a/test/JDBC/upgrade/14_8/schedule b/test/JDBC/upgrade/14_8/schedule index b85aa3ed36..36da072669 100644 --- a/test/JDBC/upgrade/14_8/schedule +++ b/test/JDBC/upgrade/14_8/schedule @@ -392,3 +392,5 @@ rowcount BABEL-1625 BABEL-3474 dateadd_internal_df +datetime2fromparts +timefromparts diff --git a/test/JDBC/upgrade/15_1/schedule b/test/JDBC/upgrade/15_1/schedule index 55ec667ef5..1b10fe2b5d 100644 --- a/test/JDBC/upgrade/15_1/schedule +++ b/test/JDBC/upgrade/15_1/schedule @@ -372,3 +372,5 @@ rowcount BABEL-1625 BABEL-3474 dateadd_internal_df +datetime2fromparts +timefromparts diff --git a/test/JDBC/upgrade/15_2/schedule b/test/JDBC/upgrade/15_2/schedule index e8afcbcb4f..68c7211bce 100644 --- a/test/JDBC/upgrade/15_2/schedule +++ b/test/JDBC/upgrade/15_2/schedule @@ -410,3 +410,5 @@ rowcount BABEL-1625 BABEL-3474 dateadd_internal_df +datetime2fromparts +timefromparts diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index 7b886aff40..3701eb2211 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -419,3 +419,5 @@ rowcount BABEL-1625 BABEL-3474 dateadd_internal_df +datetime2fromparts-after-15-2 +timefromparts diff --git a/test/JDBC/upgrade/master/schedule b/test/JDBC/upgrade/master/schedule index 5ac00e6da8..c7dbf8097c 100644 --- a/test/JDBC/upgrade/master/schedule +++ b/test/JDBC/upgrade/master/schedule @@ -413,3 +413,5 @@ binary-index BABEL-1625 BABEL-3474 dateadd_internal_df +datetime2fromparts-after-15-2 +timefromparts diff --git a/test/python/expected/sql_validation_framework/expected_create.out b/test/python/expected/sql_validation_framework/expected_create.out index 4f5d3bda4b..a3b4bbe11f 100644 --- a/test/python/expected/sql_validation_framework/expected_create.out +++ b/test/python/expected/sql_validation_framework/expected_create.out @@ -12,7 +12,6 @@ Could not find tests for function sys.dateadd_internal Could not find tests for function sys.datediff_internal Could not find tests for function sys.datediff_internal_df Could not find tests for function sys.datepart_internal -Could not find tests for function sys.datetime2fromparts Could not find tests for function sys.default_domain Could not find tests for function sys.format_datetime Could not find tests for function sys.format_numeric @@ -45,7 +44,6 @@ Could not find tests for function sys.suser_id_internal Could not find tests for function sys.suser_name_internal Could not find tests for function sys.sysdatetime Could not find tests for function sys.systypes_precision_helper -Could not find tests for function sys.timefromparts Could not find tests for function sys.tsql_get_returntypmodvalue Could not find tests for function sys.tsql_query_to_json_ffunc Could not find tests for function sys.tsql_query_to_json_sfunc @@ -111,7 +109,6 @@ Could not find upgrade tests for function sys.dateadd_internal Could not find upgrade tests for function sys.datediff_internal Could not find upgrade tests for function sys.datediff_internal_df Could not find upgrade tests for function sys.datepart_internal -Could not find upgrade tests for function sys.datetime2fromparts Could not find upgrade tests for function sys.default_domain Could not find upgrade tests for function sys.error_line Could not find upgrade tests for function sys.error_number @@ -166,7 +163,6 @@ Could not find upgrade tests for function sys.suser_id_internal Could not find upgrade tests for function sys.suser_name_internal Could not find upgrade tests for function sys.sysdatetime Could not find upgrade tests for function sys.systypes_precision_helper -Could not find upgrade tests for function sys.timefromparts Could not find upgrade tests for function sys.tsql_get_functiondef Could not find upgrade tests for function sys.tsql_get_returntypmodvalue Could not find upgrade tests for function sys.tsql_query_to_json_ffunc diff --git a/test/python/expected/upgrade_validation/expected_dependency.out b/test/python/expected/upgrade_validation/expected_dependency.out index 701f74948f..b236cd586a 100644 --- a/test/python/expected/upgrade_validation/expected_dependency.out +++ b/test/python/expected/upgrade_validation/expected_dependency.out @@ -329,7 +329,6 @@ Function sys.datetime2bpchar(sys.datetime) Function sys.datetime2char(sys.datetime) Function sys.datetime2date(sys.datetime) Function sys.datetime2datetimeoffset(sys.datetime) -Function sys.datetime2fromparts(numeric,numeric,numeric,numeric,numeric,numeric,numeric,numeric) Function sys.datetime2fromparts(text,text,text,text,text,text,text,text) Function sys.datetime2smalldatetime(sys.datetime) Function sys.datetime2sysvarchar(sys.datetime) @@ -631,7 +630,6 @@ Function sys.time2datetime(time without time zone) Function sys.time2datetime2(time without time zone) Function sys.time2datetimeoffset(time without time zone) Function sys.time_sqlvariant(time without time zone) -Function sys.timefromparts(numeric,numeric,numeric,numeric,numeric) Function sys.timefromparts(text,text,text,text,text) Function sys.timestamp2datetime(timestamp without time zone) Function sys.timestamp2datetime2(timestamp without time zone) From 4b4df182a6be5791d8c6bb41f4bc965dce453730 Mon Sep 17 00:00:00 2001 From: Zhibai Date: Thu, 6 Apr 2023 16:16:03 -0700 Subject: [PATCH 049/363] add mvu test cases for orderby null first with CTE (#1398) verify the orderby null first change would work fine with MVU Signed-off-by: Zhibai Song Task: BABEL-3991 --- .../orderby-before-15_3-vu-cleanup.out | 11 +++++ .../orderby-before-15_3-vu-prepare.out | 30 ++++++++++++ .../orderby-before-15_3-vu-verify.out | 29 +++++++++++ test/JDBC/expected/orderby-vu-cleanup.out | 11 +++++ test/JDBC/expected/orderby-vu-prepare.out | 30 ++++++++++++ test/JDBC/expected/orderby-vu-verify.out | 29 +++++++++++ test/JDBC/input/babel_orderby.mix | 49 +++++++++++++++++++ .../input/orderby-before-15_3-vu-cleanup.sql | 11 +++++ .../input/orderby-before-15_3-vu-prepare.sql | 24 +++++++++ .../input/orderby-before-15_3-vu-verify.sql | 8 +++ test/JDBC/input/orderby-vu-cleanup.sql | 11 +++++ test/JDBC/input/orderby-vu-prepare.sql | 24 +++++++++ test/JDBC/input/orderby-vu-verify.sql | 8 +++ test/JDBC/jdbc_schedule | 3 ++ test/JDBC/upgrade/14_8/schedule | 1 + test/JDBC/upgrade/15_1/schedule | 1 + test/JDBC/upgrade/15_2/schedule | 1 + test/JDBC/upgrade/latest/schedule | 1 + 18 files changed, 282 insertions(+) create mode 100644 test/JDBC/expected/orderby-before-15_3-vu-cleanup.out create mode 100644 test/JDBC/expected/orderby-before-15_3-vu-prepare.out create mode 100644 test/JDBC/expected/orderby-before-15_3-vu-verify.out create mode 100644 test/JDBC/expected/orderby-vu-cleanup.out create mode 100644 test/JDBC/expected/orderby-vu-prepare.out create mode 100644 test/JDBC/expected/orderby-vu-verify.out create mode 100644 test/JDBC/input/babel_orderby.mix create mode 100644 test/JDBC/input/orderby-before-15_3-vu-cleanup.sql create mode 100644 test/JDBC/input/orderby-before-15_3-vu-prepare.sql create mode 100644 test/JDBC/input/orderby-before-15_3-vu-verify.sql create mode 100644 test/JDBC/input/orderby-vu-cleanup.sql create mode 100644 test/JDBC/input/orderby-vu-prepare.sql create mode 100644 test/JDBC/input/orderby-vu-verify.sql diff --git a/test/JDBC/expected/orderby-before-15_3-vu-cleanup.out b/test/JDBC/expected/orderby-before-15_3-vu-cleanup.out new file mode 100644 index 0000000000..13edaa3da6 --- /dev/null +++ b/test/JDBC/expected/orderby-before-15_3-vu-cleanup.out @@ -0,0 +1,11 @@ +drop view orderby_vu_view_1; +GO + +drop view orderby_vu_view_2; +GO + +drop view orderby_vu_view_3; +GO + +drop table t1; +GO diff --git a/test/JDBC/expected/orderby-before-15_3-vu-prepare.out b/test/JDBC/expected/orderby-before-15_3-vu-prepare.out new file mode 100644 index 0000000000..7de516ee2b --- /dev/null +++ b/test/JDBC/expected/orderby-before-15_3-vu-prepare.out @@ -0,0 +1,30 @@ +drop table if exists t1; +GO + +create table t1(a int); +GO + +insert t1 values (1); +insert t1 values (3); +insert t1 values (null); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +create view orderby_vu_view_1 as with t1cte AS ( +select top(3) a from t1 order by 1 +) +select * from t1cte; +GO + +create view orderby_vu_view_2 as +select top(3) a from t1 order by 1; +GO + +create view orderby_vu_view_3 as +select * from (select top(3) a from t1 order by 1) as b; +GO diff --git a/test/JDBC/expected/orderby-before-15_3-vu-verify.out b/test/JDBC/expected/orderby-before-15_3-vu-verify.out new file mode 100644 index 0000000000..c437a51f3c --- /dev/null +++ b/test/JDBC/expected/orderby-before-15_3-vu-verify.out @@ -0,0 +1,29 @@ +select * from orderby_vu_view_1; +GO +~~START~~ +int +1 +3 + +~~END~~ + + +select * from orderby_vu_view_2; +GO +~~START~~ +int + +1 +3 +~~END~~ + + +select * from orderby_vu_view_3; +GO +~~START~~ +int + +1 +3 +~~END~~ + diff --git a/test/JDBC/expected/orderby-vu-cleanup.out b/test/JDBC/expected/orderby-vu-cleanup.out new file mode 100644 index 0000000000..1e296e3842 --- /dev/null +++ b/test/JDBC/expected/orderby-vu-cleanup.out @@ -0,0 +1,11 @@ +drop view orderby_vu_view_1; +GO + +drop view orderby_vu_view_2; +GO + +drop view orderby_vu_view_3; +GO + +drop table t2; +GO diff --git a/test/JDBC/expected/orderby-vu-prepare.out b/test/JDBC/expected/orderby-vu-prepare.out new file mode 100644 index 0000000000..7b0b23d33b --- /dev/null +++ b/test/JDBC/expected/orderby-vu-prepare.out @@ -0,0 +1,30 @@ +drop table if exists t2; +GO + +create table t2(a int); +GO + +insert t2 values (1); +insert t2 values (3); +insert t2 values (null); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +create view orderby_vu_view_1 as with t1cte AS ( +select top(3) a from t2 order by 1 +) +select * from t1cte; +GO + +create view orderby_vu_view_2 as +select top(3) a from t2 order by 1; +GO + +create view orderby_vu_view_3 as +select * from (select top(3) a from t2 order by 1) as b; +GO diff --git a/test/JDBC/expected/orderby-vu-verify.out b/test/JDBC/expected/orderby-vu-verify.out new file mode 100644 index 0000000000..a8288ddbb7 --- /dev/null +++ b/test/JDBC/expected/orderby-vu-verify.out @@ -0,0 +1,29 @@ +select * from orderby_vu_view_1; +GO +~~START~~ +int + +1 +3 +~~END~~ + + +select * from orderby_vu_view_2; +GO +~~START~~ +int + +1 +3 +~~END~~ + + +select * from orderby_vu_view_3; +GO +~~START~~ +int + +1 +3 +~~END~~ + diff --git a/test/JDBC/input/babel_orderby.mix b/test/JDBC/input/babel_orderby.mix new file mode 100644 index 0000000000..c4a52ae791 --- /dev/null +++ b/test/JDBC/input/babel_orderby.mix @@ -0,0 +1,49 @@ +drop table if exists t1; +GO + +create table t1(a int); +GO + +insert t1 values (1); +insert t1 values (3); +insert t1 values (null); +GO + +with t1cte AS ( +select top(3) a from t1 order by 1 +) +select * from t1cte; +GO + +select top(3) a from t1 order by 1; +GO + +select a from t1; +GO + +select a from t1 order by a; +GO + +select a from t1 order by a desc; +GO + +select * from (select top(3) a from t1 order by 1) as b; +GO + +-- psql + +-- to show pg ordering is different from tsql + +select a from master_dbo.t1; +GO + +select a from master_dbo.t1 order by a; +GO + +select a from master_dbo.t1 order by a desc; +GO + +-- tsql + +drop table t1; +GO diff --git a/test/JDBC/input/orderby-before-15_3-vu-cleanup.sql b/test/JDBC/input/orderby-before-15_3-vu-cleanup.sql new file mode 100644 index 0000000000..1fa00d5456 --- /dev/null +++ b/test/JDBC/input/orderby-before-15_3-vu-cleanup.sql @@ -0,0 +1,11 @@ +drop view orderby_vu_view_1; +GO + +drop view orderby_vu_view_2; +GO + +drop view orderby_vu_view_3; +GO + +drop table t1; +GO \ No newline at end of file diff --git a/test/JDBC/input/orderby-before-15_3-vu-prepare.sql b/test/JDBC/input/orderby-before-15_3-vu-prepare.sql new file mode 100644 index 0000000000..cb9da8b36a --- /dev/null +++ b/test/JDBC/input/orderby-before-15_3-vu-prepare.sql @@ -0,0 +1,24 @@ +drop table if exists t1; +GO + +create table t1(a int); +GO + +insert t1 values (1); +insert t1 values (3); +insert t1 values (null); +GO + +create view orderby_vu_view_1 as with t1cte AS ( +select top(3) a from t1 order by 1 +) +select * from t1cte; +GO + +create view orderby_vu_view_2 as +select top(3) a from t1 order by 1; +GO + +create view orderby_vu_view_3 as +select * from (select top(3) a from t1 order by 1) as b; +GO diff --git a/test/JDBC/input/orderby-before-15_3-vu-verify.sql b/test/JDBC/input/orderby-before-15_3-vu-verify.sql new file mode 100644 index 0000000000..97b1eb1d5c --- /dev/null +++ b/test/JDBC/input/orderby-before-15_3-vu-verify.sql @@ -0,0 +1,8 @@ +select * from orderby_vu_view_1; +GO + +select * from orderby_vu_view_2; +GO + +select * from orderby_vu_view_3; +GO diff --git a/test/JDBC/input/orderby-vu-cleanup.sql b/test/JDBC/input/orderby-vu-cleanup.sql new file mode 100644 index 0000000000..f4f1e90df2 --- /dev/null +++ b/test/JDBC/input/orderby-vu-cleanup.sql @@ -0,0 +1,11 @@ +drop view orderby_vu_view_1; +GO + +drop view orderby_vu_view_2; +GO + +drop view orderby_vu_view_3; +GO + +drop table t2; +GO \ No newline at end of file diff --git a/test/JDBC/input/orderby-vu-prepare.sql b/test/JDBC/input/orderby-vu-prepare.sql new file mode 100644 index 0000000000..f8ee0674cb --- /dev/null +++ b/test/JDBC/input/orderby-vu-prepare.sql @@ -0,0 +1,24 @@ +drop table if exists t2; +GO + +create table t2(a int); +GO + +insert t2 values (1); +insert t2 values (3); +insert t2 values (null); +GO + +create view orderby_vu_view_1 as with t1cte AS ( +select top(3) a from t2 order by 1 +) +select * from t1cte; +GO + +create view orderby_vu_view_2 as +select top(3) a from t2 order by 1; +GO + +create view orderby_vu_view_3 as +select * from (select top(3) a from t2 order by 1) as b; +GO diff --git a/test/JDBC/input/orderby-vu-verify.sql b/test/JDBC/input/orderby-vu-verify.sql new file mode 100644 index 0000000000..97b1eb1d5c --- /dev/null +++ b/test/JDBC/input/orderby-vu-verify.sql @@ -0,0 +1,8 @@ +select * from orderby_vu_view_1; +GO + +select * from orderby_vu_view_2; +GO + +select * from orderby_vu_view_3; +GO diff --git a/test/JDBC/jdbc_schedule b/test/JDBC/jdbc_schedule index 7a2cda7b30..17b0342a21 100644 --- a/test/JDBC/jdbc_schedule +++ b/test/JDBC/jdbc_schedule @@ -71,6 +71,9 @@ ignore#!#sys-all_sql_modules_before-14_7-or-15_2-vu-cleanup ignore#!#sys-sql_modules_before-14_7-or-15_2-vu-prepare ignore#!#sys-sql_modules_before-14_7-or-15_2-vu-verify ignore#!#sys-sql_modules_before-14_7-or-15_2-vu-cleanup +ignore#!#orderby-before-15_3-vu-prepare +ignore#!#orderby-before-15_3-vu-verify +ignore#!#orderby-before-15_3-vu-cleanup # These tests are meant for upgrade scenario where source version is 13_X ignore#!#sys_database_principals_dep_for_13_x-vu-cleanup diff --git a/test/JDBC/upgrade/14_8/schedule b/test/JDBC/upgrade/14_8/schedule index 36da072669..4c9ec141e6 100644 --- a/test/JDBC/upgrade/14_8/schedule +++ b/test/JDBC/upgrade/14_8/schedule @@ -394,3 +394,4 @@ BABEL-3474 dateadd_internal_df datetime2fromparts timefromparts +orderby-before-15_3 diff --git a/test/JDBC/upgrade/15_1/schedule b/test/JDBC/upgrade/15_1/schedule index 1b10fe2b5d..fdc44a24f4 100644 --- a/test/JDBC/upgrade/15_1/schedule +++ b/test/JDBC/upgrade/15_1/schedule @@ -374,3 +374,4 @@ BABEL-3474 dateadd_internal_df datetime2fromparts timefromparts +orderby-before-15_3 diff --git a/test/JDBC/upgrade/15_2/schedule b/test/JDBC/upgrade/15_2/schedule index 68c7211bce..c13b329b93 100644 --- a/test/JDBC/upgrade/15_2/schedule +++ b/test/JDBC/upgrade/15_2/schedule @@ -412,3 +412,4 @@ BABEL-3474 dateadd_internal_df datetime2fromparts timefromparts +orderby-before-15_3 diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index 3701eb2211..163f240cbb 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -421,3 +421,4 @@ BABEL-3474 dateadd_internal_df datetime2fromparts-after-15-2 timefromparts +orderby From 6be9904540b87411ba28dea08ba1ae774d216cd2 Mon Sep 17 00:00:00 2001 From: Walt Boettge Date: Fri, 7 Apr 2023 11:41:16 -0700 Subject: [PATCH 050/363] Rewrite ORDER BY column with set operators (#1246) Currently, some queries that combine ORDER BY clauses with the set operators UNION, INTERSECT, and EXCEPT are failing with the error 'missing FROM-cause entry'. This occurs when the column specified in the ORDER BY clause is not a simple column reference. This change will rewrite the targets to only have a column reference so that the query can be run Signed-off-by: Walt Boettge Task: BABEL-3215 --- contrib/babelfishpg_tsql/src/hooks.c | 17 + contrib/babelfishpg_tsql/src/tsql_analyze.c | 58 +++ contrib/babelfishpg_tsql/src/tsql_analyze.h | 9 + test/JDBC/expected/BABEL-3215-vu-prepare.out | 24 ++ test/JDBC/expected/BABEL-3215-vu-verify.out | 354 +++++++++++++++++++ test/JDBC/input/BABEL-3215-vu-prepare.sql | 18 + test/JDBC/input/BABEL-3215-vu-verify.sql | 189 ++++++++++ test/JDBC/upgrade/13_4/schedule | 1 + test/JDBC/upgrade/13_5/schedule | 1 + test/JDBC/upgrade/13_6/schedule | 1 + test/JDBC/upgrade/13_7/schedule | 1 + test/JDBC/upgrade/13_8/schedule | 1 + test/JDBC/upgrade/13_9/schedule | 1 + test/JDBC/upgrade/14_3/schedule | 1 + test/JDBC/upgrade/14_5/schedule | 1 + test/JDBC/upgrade/14_6/schedule | 1 + test/JDBC/upgrade/14_7/schedule | 1 + test/JDBC/upgrade/14_8/schedule | 1 + test/JDBC/upgrade/15_1/schedule | 1 + test/JDBC/upgrade/15_2/schedule | 1 + test/JDBC/upgrade/latest/schedule | 1 + 21 files changed, 683 insertions(+) create mode 100644 test/JDBC/expected/BABEL-3215-vu-prepare.out create mode 100644 test/JDBC/expected/BABEL-3215-vu-verify.out create mode 100644 test/JDBC/input/BABEL-3215-vu-prepare.sql create mode 100644 test/JDBC/input/BABEL-3215-vu-verify.sql diff --git a/contrib/babelfishpg_tsql/src/hooks.c b/contrib/babelfishpg_tsql/src/hooks.c index 3809cedbec..7a28f4d7b3 100644 --- a/contrib/babelfishpg_tsql/src/hooks.c +++ b/contrib/babelfishpg_tsql/src/hooks.c @@ -163,6 +163,10 @@ static core_yylex_hook_type prev_core_yylex_hook = NULL; static pre_transform_returning_hook_type prev_pre_transform_returning_hook = NULL; static pre_transform_insert_hook_type prev_pre_transform_insert_hook = NULL; static post_transform_insert_row_hook_type prev_post_transform_insert_row_hook = NULL; +static push_namespace_stack_hook_type prev_push_namespace_stack_hook = NULL; +static pre_transform_sort_clause_hook_type prev_pre_transform_sort_clause_hook = NULL; +static post_transform_sort_clause_hook_type prev_post_transform_sort_clause_hook = NULL; +static post_transform_from_clause_hook_type prev_post_transform_from_clause_hook = NULL; static pre_transform_target_entry_hook_type prev_pre_transform_target_entry_hook = NULL; static tle_name_comparison_hook_type prev_tle_name_comparison_hook = NULL; static get_trigger_object_address_hook_type prev_get_trigger_object_address_hook = NULL; @@ -220,6 +224,15 @@ InstallExtendedHooks(void) prev_post_transform_insert_row_hook = post_transform_insert_row_hook; post_transform_insert_row_hook = check_insert_row; + prev_push_namespace_stack_hook = push_namespace_stack_hook; + push_namespace_stack_hook = push_namespace_stack; + prev_pre_transform_sort_clause_hook = pre_transform_sort_clause_hook; + pre_transform_sort_clause_hook = pre_transform_sort_clause; + prev_post_transform_sort_clause_hook = post_transform_sort_clause_hook; + post_transform_sort_clause_hook = post_transform_sort_clause; + prev_post_transform_from_clause_hook = post_transform_from_clause_hook; + post_transform_from_clause_hook = post_transform_from_clause; + post_transform_column_definition_hook = pltsql_post_transform_column_definition; post_transform_table_definition_hook = pltsql_post_transform_table_definition; @@ -319,6 +332,10 @@ UninstallExtendedHooks(void) pre_transform_returning_hook = prev_pre_transform_returning_hook; pre_transform_insert_hook = prev_pre_transform_insert_hook; post_transform_insert_row_hook = prev_post_transform_insert_row_hook; + push_namespace_stack_hook = prev_push_namespace_stack_hook; + pre_transform_sort_clause_hook = prev_pre_transform_sort_clause_hook; + post_transform_sort_clause_hook = prev_post_transform_sort_clause_hook; + post_transform_from_clause_hook = prev_post_transform_from_clause_hook; post_transform_column_definition_hook = NULL; post_transform_table_definition_hook = NULL; pre_transform_target_entry_hook = prev_pre_transform_target_entry_hook; diff --git a/contrib/babelfishpg_tsql/src/tsql_analyze.c b/contrib/babelfishpg_tsql/src/tsql_analyze.c index 16a431dce9..7928df0c67 100644 --- a/contrib/babelfishpg_tsql/src/tsql_analyze.c +++ b/contrib/babelfishpg_tsql/src/tsql_analyze.c @@ -23,6 +23,9 @@ static RangeVar *find_matching_table(RangeVar *target, Node *tblref); +List *sv_setop_targetlist = NIL; +namespace_stack_t *set_op_ns_stack = NULL; + /* * If a table alias is used when specifying the target table, we need to refer to the * FROM clause for table reference. @@ -300,3 +303,58 @@ rewrite_update_outer_join(Node *stmt, CmdType command, RangeVar *target) return; } } + +void +push_namespace_stack(void) +{ + namespace_stack_t *ns_stack_item; + + if (sql_dialect != SQL_DIALECT_TSQL) + return; + + ns_stack_item = palloc(sizeof(namespace_stack_t)); + ns_stack_item->prev = set_op_ns_stack; + ns_stack_item->namespace = NIL; + set_op_ns_stack = ns_stack_item; +} + +void +post_transform_from_clause(ParseState *pstate) +{ + namespace_stack_t *ns = set_op_ns_stack; + if (sql_dialect == SQL_DIALECT_TSQL && ns && ns->namespace == NIL) + ns->namespace = pstate->p_namespace; +} + +void +pre_transform_sort_clause(ParseState *pstate, Query *qry, Query *leftmostQuery) +{ + namespace_stack_t *old_ns_stack_item = set_op_ns_stack; + + if (sql_dialect != SQL_DIALECT_TSQL) + return; + + sv_setop_targetlist = qry->targetList; + + qry->targetList = leftmostQuery->targetList; + pstate->p_namespace = set_op_ns_stack->namespace; + + set_op_ns_stack = set_op_ns_stack->prev; + pfree(old_ns_stack_item); +} + +void +post_transform_sort_clause(Query *qry) +{ + ListCell *lc_q, *lc_sv; + if (sql_dialect != SQL_DIALECT_TSQL || sv_setop_targetlist == NIL) + return; + /* Copy the ressortgroupref from the leftmost target list to the previous tl */ + forboth(lc_q, qry->targetList, lc_sv, sv_setop_targetlist) + { + TargetEntry *tle_q= (TargetEntry *) lfirst(lc_q); + TargetEntry *tle_sv = (TargetEntry *) lfirst(lc_sv); + tle_sv->ressortgroupref = tle_q->ressortgroupref; + } + qry->targetList = sv_setop_targetlist; +} diff --git a/contrib/babelfishpg_tsql/src/tsql_analyze.h b/contrib/babelfishpg_tsql/src/tsql_analyze.h index dc8819d37d..780bce648a 100644 --- a/contrib/babelfishpg_tsql/src/tsql_analyze.h +++ b/contrib/babelfishpg_tsql/src/tsql_analyze.h @@ -13,5 +13,14 @@ extern RangeVar *pltsql_get_target_table(RangeVar *orig_target, List *fromClause extern void pltsql_update_query_result_relation(Query *qry, Relation target_rel, List *rtable); extern void handle_rowversion_target_in_update_stmt(RangeVar *target_table, UpdateStmt *stmt); extern void rewrite_update_outer_join(Node *stmt, CmdType command, RangeVar *target); +extern void push_namespace_stack(void); +extern void pre_transform_sort_clause(ParseState *pstate, Query *qry, Query *leftmostQuery); +extern void post_transform_sort_clause(Query *qry); +extern void post_transform_from_clause(ParseState *pstate); + +typedef struct namespace_stack { + struct namespace_stack *prev; + List *namespace; +} namespace_stack_t; #endif /* TSQL_ANALYZE_H */ diff --git a/test/JDBC/expected/BABEL-3215-vu-prepare.out b/test/JDBC/expected/BABEL-3215-vu-prepare.out new file mode 100644 index 0000000000..12a162ea64 --- /dev/null +++ b/test/JDBC/expected/BABEL-3215-vu-prepare.out @@ -0,0 +1,24 @@ +create table dbo.unionorder1 (c1 int ); +create table dbo.unionorder2 (c2 int ); +create table dbo.unionorder1b (c1 int ); +go + +insert into unionorder1 VALUES (1), (2), (3); +insert into unionorder2 VALUES (2), (3), (4); +insert into unionorder1b VALUES (2), (3), (4); +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + + +create procedure babel_3215_unionorder_proc as +BEGIN + SELECT * FROM unionorder1 u1, unionorder1b u2 WHERE u1.c1 = u2.c1 + union + SELECT u.c1, u.c1 FROM unionorder1 u + ORDER BY u1.c1 +END +go diff --git a/test/JDBC/expected/BABEL-3215-vu-verify.out b/test/JDBC/expected/BABEL-3215-vu-verify.out new file mode 100644 index 0000000000..687282b1f8 --- /dev/null +++ b/test/JDBC/expected/BABEL-3215-vu-verify.out @@ -0,0 +1,354 @@ +EXEC babel_3215_unionorder_proc +go +~~START~~ +int#!#int +1#!#1 +2#!#2 +3#!#3 +~~END~~ + + +SELECT u.c1 FROM unionorder1 u +UNION +SELECT u.c1 FROM unionorder1 u +ORDER BY u.c1; +go +~~START~~ +int +1 +2 +3 +~~END~~ + + +SELECT c1 FROM unionorder1 +UNION +SELECT c2 FROM unionorder2 +ORDER BY unionorder1.c1; +go +~~START~~ +int +1 +2 +3 +4 +~~END~~ + + +SELECT c1 FROM unionorder1 +intersect +SELECT c2 FROM unionorder2 +ORDER BY unionorder1.c1; +go +~~START~~ +int +2 +3 +~~END~~ + + +SELECT u.c1 FROM unionorder1 u +intersect +SELECT c2 FROM unionorder2 +ORDER BY u.c1; +go +~~START~~ +int +2 +3 +~~END~~ + + +SELECT c1 FROM unionorder1 +except +SELECT c2 FROM unionorder2 +ORDER BY unionorder1.c1; +go +~~START~~ +int +1 +~~END~~ + + +SELECT c1 FROM unionorder1 u +except +SELECT c2 FROM unionorder2 +ORDER BY u.c1; +go +~~START~~ +int +1 +~~END~~ + + +SELECT c1 FROM dbo.unionorder1 +UNION +SELECT c2 FROM dbo.unionorder2 +ORDER BY dbo.unionorder1.c1; +go +~~START~~ +int +1 +2 +3 +4 +~~END~~ + + +SELECT c1 FROM master.dbo.unionorder1 +UNION +SELECT c1 FROM master.dbo.unionorder1 +ORDER BY master.dbo.unionorder1.c1; +go +~~START~~ +int +1 +2 +3 +~~END~~ + + +SELECT c1 FROM dbo.unionorder1 +UNION +SELECT c2 FROM dbo.unionorder2 +ORDER BY dbo.unionorder2.c2; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: missing FROM-clause entry for table "unionorder2")~~ + + +SELECT u.* FROM unionorder1 u +UNION +SELECT u.* FROM unionorder1 u +ORDER BY u.c1 +go +~~START~~ +int +1 +2 +3 +~~END~~ + + +SELECT u1.c1, u2.c2 FROM unionorder1 u1, unionorder2 u2 where u1.c1 = u2.c2 +UNION +SELECT u1.c1, u2.c2 FROM unionorder1 u1, unionorder2 u2 where u1.c1 = u2.c2 +ORDER BY u2.c2 +go +~~START~~ +int#!#int +2#!#2 +3#!#3 +~~END~~ + + +select u.c2 from unionorder1 JOIN unionorder2 u on u.c2 = unionorder1.c1 +union +select u.c1 from unionorder1 u +ORDER BY u.c2 +go +~~START~~ +int +1 +2 +3 +~~END~~ + + +SELECT unionorder1.c1 FROM unionorder1, unionorder1b WHERE unionorder1.c1 = unionorder1b.c1 +union +SELECT u.c1 FROM unionorder1 u +ORDER BY unionorder1.c1 +go +~~START~~ +int +1 +2 +3 +~~END~~ + + +SELECT * FROM unionorder1, unionorder1b WHERE unionorder1.c1 = unionorder1b.c1 +union +SELECT u.c1, u.c1 FROM unionorder1 u +ORDER BY unionorder1.c1 +go +~~START~~ +int#!#int +1#!#1 +2#!#2 +3#!#3 +~~END~~ + + +SELECT * FROM unionorder1 u1, unionorder1b u2 WHERE u1.c1 = u2.c1 +union +SELECT u.c1, u.c1 FROM unionorder1 u +ORDER BY u1.c1 +go +~~START~~ +int#!#int +1#!#1 +2#!#2 +3#!#3 +~~END~~ + + +SELECT u1.c1 FROM unionorder1 u1 +UNION +SELECT c2 FROM unionorder2 +WHERE c2 IN ( + SELECT TOP 5 c2 FROM unionorder2 + UNION + SELECT TOP 5 c1 FROM unionorder1 + WHERE c1 IN ( + SELECT TOP 5 c1 FROM unionorder1 + UNION + SELECT TOP 5 c2 FROM unionorder2 + ORDER BY unionorder1.c1 + ) + ORDER BY unionorder2.c2 +) +ORDER BY u1.c1; +go +~~START~~ +int +1 +2 +3 +4 +~~END~~ + + +SELECT u1.c1, (SELECT TOP 1 c2 FROM unionorder2) AS col2 +FROM unionorder1 u1 +UNION +SELECT c2, c2 FROM unionorder2 +WHERE c2 IN ( + SELECT TOP 5 c2 FROM unionorder2 + UNION + SELECT TOP 5 c1 FROM unionorder1 + ORDER BY unionorder2.c2 +) +ORDER BY col2; +go +~~START~~ +int#!#int +3#!#2 +1#!#2 +2#!#2 +3#!#3 +4#!#4 +~~END~~ + + +SELECT c1 FROM unionorder1 +WHERE c1 IN ( + SELECT TOP 5 c2 FROM unionorder2 + UNION + SELECT TOP 5 c1 FROM unionorder1 + ORDER BY unionorder2.c2 +) +UNION +SELECT c2 FROM unionorder2 +ORDER BY unionorder1.c1; +go +~~START~~ +int +1 +2 +3 +4 +~~END~~ + + +SELECT c1 FROM unionorder1 +WHERE c1 IN ( + SELECT TOP 5 c2 FROM unionorder2 + UNION + SELECT TOP 5 c1 FROM unionorder1 + ORDER BY unionorder2.c2 +) +UNION +SELECT c2 FROM unionorder2 +ORDER BY unionorder2.c2; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: missing FROM-clause entry for table "unionorder2")~~ + + +SELECT c2 FROM ( + SELECT TOP 5 c2 FROM unionorder2 + UNION + SELECT TOP 5 c1 FROM unionorder1 + ORDER BY unionorder2.c2 +) u +UNION +SELECT c1 FROM unionorder1 +ORDER BY u.c2; +go +~~START~~ +int +1 +2 +3 +4 +~~END~~ + + +-- Test babel_613 UNION ALL with numeric issue +create table dbo.unionorder_numeric (a numeric(6,4), b numeric(6,3)); +insert into unionorder_numeric values (4, 16); +insert into unionorder_numeric values (NULL, 101.123); +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +create table dbo.unionorder_char (a CHAR(5), b CHAR(10)); +insert into unionorder_char values ('aaa', 'bbbbbbbb'); +insert into unionorder_char values (NULL, '5'); +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +SELECT t.a, t.b FROM unionorder_numeric t +UNION ALL +SELECT t.a, t.b FROM unionorder_numeric t +ORDER BY t.b; +go +~~START~~ +numeric#!#numeric +4.0000#!#16.000 +4.0000#!#16.000 +#!#101.123 +#!#101.123 +~~END~~ + + +SELECT t.a, t.b FROM unionorder_char t +UNION ALL +SELECT t.a, t.b FROM unionorder_char t +ORDER BY t.b; +go +~~START~~ +char#!#char +#!#5 +#!#5 +aaa #!#bbbbbbbb +aaa #!#bbbbbbbb +~~END~~ + + +drop procedure babel_3215_unionorder_proc; +drop table dbo.unionorder_numeric; +drop table dbo.unionorder_char; +drop table dbo.unionorder1; +drop table dbo.unionorder2; +drop table dbo.unionorder1b; +go diff --git a/test/JDBC/input/BABEL-3215-vu-prepare.sql b/test/JDBC/input/BABEL-3215-vu-prepare.sql new file mode 100644 index 0000000000..587c7f3f94 --- /dev/null +++ b/test/JDBC/input/BABEL-3215-vu-prepare.sql @@ -0,0 +1,18 @@ +create table dbo.unionorder1 (c1 int ); +create table dbo.unionorder2 (c2 int ); +create table dbo.unionorder1b (c1 int ); +go + +insert into unionorder1 VALUES (1), (2), (3); +insert into unionorder2 VALUES (2), (3), (4); +insert into unionorder1b VALUES (2), (3), (4); +go + +create procedure babel_3215_unionorder_proc as +BEGIN + SELECT * FROM unionorder1 u1, unionorder1b u2 WHERE u1.c1 = u2.c1 + union + SELECT u.c1, u.c1 FROM unionorder1 u + ORDER BY u1.c1 +END +go diff --git a/test/JDBC/input/BABEL-3215-vu-verify.sql b/test/JDBC/input/BABEL-3215-vu-verify.sql new file mode 100644 index 0000000000..53995cd45c --- /dev/null +++ b/test/JDBC/input/BABEL-3215-vu-verify.sql @@ -0,0 +1,189 @@ +EXEC babel_3215_unionorder_proc +go + +SELECT u.c1 FROM unionorder1 u +UNION +SELECT u.c1 FROM unionorder1 u +ORDER BY u.c1; +go + +SELECT c1 FROM unionorder1 +UNION +SELECT c2 FROM unionorder2 +ORDER BY unionorder1.c1; +go + +SELECT c1 FROM unionorder1 +intersect +SELECT c2 FROM unionorder2 +ORDER BY unionorder1.c1; +go + +SELECT u.c1 FROM unionorder1 u +intersect +SELECT c2 FROM unionorder2 +ORDER BY u.c1; +go + +SELECT c1 FROM unionorder1 +except +SELECT c2 FROM unionorder2 +ORDER BY unionorder1.c1; +go + +SELECT c1 FROM unionorder1 u +except +SELECT c2 FROM unionorder2 +ORDER BY u.c1; +go + +SELECT c1 FROM dbo.unionorder1 +UNION +SELECT c2 FROM dbo.unionorder2 +ORDER BY dbo.unionorder1.c1; +go + +SELECT c1 FROM master.dbo.unionorder1 +UNION +SELECT c1 FROM master.dbo.unionorder1 +ORDER BY master.dbo.unionorder1.c1; +go + +SELECT c1 FROM dbo.unionorder1 +UNION +SELECT c2 FROM dbo.unionorder2 +ORDER BY dbo.unionorder2.c2; +go + +SELECT u.* FROM unionorder1 u +UNION +SELECT u.* FROM unionorder1 u +ORDER BY u.c1 +go + +SELECT u1.c1, u2.c2 FROM unionorder1 u1, unionorder2 u2 where u1.c1 = u2.c2 +UNION +SELECT u1.c1, u2.c2 FROM unionorder1 u1, unionorder2 u2 where u1.c1 = u2.c2 +ORDER BY u2.c2 +go + +select u.c2 from unionorder1 JOIN unionorder2 u on u.c2 = unionorder1.c1 +union +select u.c1 from unionorder1 u +ORDER BY u.c2 +go + +SELECT unionorder1.c1 FROM unionorder1, unionorder1b WHERE unionorder1.c1 = unionorder1b.c1 +union +SELECT u.c1 FROM unionorder1 u +ORDER BY unionorder1.c1 +go + +SELECT * FROM unionorder1, unionorder1b WHERE unionorder1.c1 = unionorder1b.c1 +union +SELECT u.c1, u.c1 FROM unionorder1 u +ORDER BY unionorder1.c1 +go + +SELECT * FROM unionorder1 u1, unionorder1b u2 WHERE u1.c1 = u2.c1 +union +SELECT u.c1, u.c1 FROM unionorder1 u +ORDER BY u1.c1 +go + +SELECT u1.c1 FROM unionorder1 u1 +UNION +SELECT c2 FROM unionorder2 +WHERE c2 IN ( + SELECT TOP 5 c2 FROM unionorder2 + UNION + SELECT TOP 5 c1 FROM unionorder1 + WHERE c1 IN ( + SELECT TOP 5 c1 FROM unionorder1 + UNION + SELECT TOP 5 c2 FROM unionorder2 + ORDER BY unionorder1.c1 + ) + ORDER BY unionorder2.c2 +) +ORDER BY u1.c1; +go + +SELECT u1.c1, (SELECT TOP 1 c2 FROM unionorder2) AS col2 +FROM unionorder1 u1 +UNION +SELECT c2, c2 FROM unionorder2 +WHERE c2 IN ( + SELECT TOP 5 c2 FROM unionorder2 + UNION + SELECT TOP 5 c1 FROM unionorder1 + ORDER BY unionorder2.c2 +) +ORDER BY col2; +go + +SELECT c1 FROM unionorder1 +WHERE c1 IN ( + SELECT TOP 5 c2 FROM unionorder2 + UNION + SELECT TOP 5 c1 FROM unionorder1 + ORDER BY unionorder2.c2 +) +UNION +SELECT c2 FROM unionorder2 +ORDER BY unionorder1.c1; +go + +SELECT c1 FROM unionorder1 +WHERE c1 IN ( + SELECT TOP 5 c2 FROM unionorder2 + UNION + SELECT TOP 5 c1 FROM unionorder1 + ORDER BY unionorder2.c2 +) +UNION +SELECT c2 FROM unionorder2 +ORDER BY unionorder2.c2; +go + +SELECT c2 FROM ( + SELECT TOP 5 c2 FROM unionorder2 + UNION + SELECT TOP 5 c1 FROM unionorder1 + ORDER BY unionorder2.c2 +) u +UNION +SELECT c1 FROM unionorder1 +ORDER BY u.c2; +go + +-- Test babel_613 UNION ALL with numeric issue +create table dbo.unionorder_numeric (a numeric(6,4), b numeric(6,3)); +insert into unionorder_numeric values (4, 16); +insert into unionorder_numeric values (NULL, 101.123); +go + +create table dbo.unionorder_char (a CHAR(5), b CHAR(10)); +insert into unionorder_char values ('aaa', 'bbbbbbbb'); +insert into unionorder_char values (NULL, '5'); +go + +SELECT t.a, t.b FROM unionorder_numeric t +UNION ALL +SELECT t.a, t.b FROM unionorder_numeric t +ORDER BY t.b; +go + +SELECT t.a, t.b FROM unionorder_char t +UNION ALL +SELECT t.a, t.b FROM unionorder_char t +ORDER BY t.b; +go + +drop procedure babel_3215_unionorder_proc; +drop table dbo.unionorder_numeric; +drop table dbo.unionorder_char; +drop table dbo.unionorder1; +drop table dbo.unionorder2; +drop table dbo.unionorder1b; +go diff --git a/test/JDBC/upgrade/13_4/schedule b/test/JDBC/upgrade/13_4/schedule index 4b89f15462..7b5385c581 100644 --- a/test/JDBC/upgrade/13_4/schedule +++ b/test/JDBC/upgrade/13_4/schedule @@ -202,3 +202,4 @@ BABEL-1625 BABEL-3474 datetime2fromparts timefromparts +BABEL-3215 diff --git a/test/JDBC/upgrade/13_5/schedule b/test/JDBC/upgrade/13_5/schedule index 51e850df52..03da225e81 100644 --- a/test/JDBC/upgrade/13_5/schedule +++ b/test/JDBC/upgrade/13_5/schedule @@ -253,3 +253,4 @@ BABEL-1625 BABEL-3474 datetime2fromparts timefromparts +BABEL-3215 diff --git a/test/JDBC/upgrade/13_6/schedule b/test/JDBC/upgrade/13_6/schedule index 3375969143..657a64e1d3 100644 --- a/test/JDBC/upgrade/13_6/schedule +++ b/test/JDBC/upgrade/13_6/schedule @@ -312,3 +312,4 @@ BABEL-1625 BABEL-3474 datetime2fromparts timefromparts +BABEL-3215 diff --git a/test/JDBC/upgrade/13_7/schedule b/test/JDBC/upgrade/13_7/schedule index 3e1acc5c81..a170009382 100644 --- a/test/JDBC/upgrade/13_7/schedule +++ b/test/JDBC/upgrade/13_7/schedule @@ -307,3 +307,4 @@ BABEL-1625 BABEL-3474 datetime2fromparts timefromparts +BABEL-3215 diff --git a/test/JDBC/upgrade/13_8/schedule b/test/JDBC/upgrade/13_8/schedule index 3e1acc5c81..a170009382 100644 --- a/test/JDBC/upgrade/13_8/schedule +++ b/test/JDBC/upgrade/13_8/schedule @@ -307,3 +307,4 @@ BABEL-1625 BABEL-3474 datetime2fromparts timefromparts +BABEL-3215 diff --git a/test/JDBC/upgrade/13_9/schedule b/test/JDBC/upgrade/13_9/schedule index c8e76cf070..d01b39cf98 100644 --- a/test/JDBC/upgrade/13_9/schedule +++ b/test/JDBC/upgrade/13_9/schedule @@ -310,3 +310,4 @@ BABEL-1625 BABEL-3474 datetime2fromparts timefromparts +BABEL-3215 diff --git a/test/JDBC/upgrade/14_3/schedule b/test/JDBC/upgrade/14_3/schedule index f65a0b81e6..fb83007c8e 100644 --- a/test/JDBC/upgrade/14_3/schedule +++ b/test/JDBC/upgrade/14_3/schedule @@ -325,3 +325,4 @@ BABEL-1625 BABEL-3474 datetime2fromparts timefromparts +BABEL-3215 diff --git a/test/JDBC/upgrade/14_5/schedule b/test/JDBC/upgrade/14_5/schedule index a5dd2476ab..d89345313d 100644 --- a/test/JDBC/upgrade/14_5/schedule +++ b/test/JDBC/upgrade/14_5/schedule @@ -339,3 +339,4 @@ BABEL-1625 BABEL-3474 datetime2fromparts timefromparts +BABEL-3215 diff --git a/test/JDBC/upgrade/14_6/schedule b/test/JDBC/upgrade/14_6/schedule index e306632d4c..43b4cbafc7 100644 --- a/test/JDBC/upgrade/14_6/schedule +++ b/test/JDBC/upgrade/14_6/schedule @@ -365,3 +365,4 @@ BABEL-3474 dateadd_internal_df datetime2fromparts timefromparts +BABEL-3215 diff --git a/test/JDBC/upgrade/14_7/schedule b/test/JDBC/upgrade/14_7/schedule index e1eb1f06df..906dcbada5 100644 --- a/test/JDBC/upgrade/14_7/schedule +++ b/test/JDBC/upgrade/14_7/schedule @@ -396,3 +396,4 @@ BABEL-3474 dateadd_internal_df datetime2fromparts timefromparts +BABEL-3215 diff --git a/test/JDBC/upgrade/14_8/schedule b/test/JDBC/upgrade/14_8/schedule index 4c9ec141e6..37ea827f64 100644 --- a/test/JDBC/upgrade/14_8/schedule +++ b/test/JDBC/upgrade/14_8/schedule @@ -395,3 +395,4 @@ dateadd_internal_df datetime2fromparts timefromparts orderby-before-15_3 +BABEL-3215 diff --git a/test/JDBC/upgrade/15_1/schedule b/test/JDBC/upgrade/15_1/schedule index fdc44a24f4..153845415b 100644 --- a/test/JDBC/upgrade/15_1/schedule +++ b/test/JDBC/upgrade/15_1/schedule @@ -375,3 +375,4 @@ dateadd_internal_df datetime2fromparts timefromparts orderby-before-15_3 +BABEL-3215 diff --git a/test/JDBC/upgrade/15_2/schedule b/test/JDBC/upgrade/15_2/schedule index c13b329b93..5770e4e712 100644 --- a/test/JDBC/upgrade/15_2/schedule +++ b/test/JDBC/upgrade/15_2/schedule @@ -370,6 +370,7 @@ app_name atn2 str case_insensitive_collation +BABEL-3215 # linked_servers ISC-sequences jira-BABEL-3504-upgrade diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index 163f240cbb..f52263e28e 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -422,3 +422,4 @@ dateadd_internal_df datetime2fromparts-after-15-2 timefromparts orderby +BABEL-3215 From 9a6b2cde9ede7ee47c6abdb02499db74d24e1d09 Mon Sep 17 00:00:00 2001 From: pratikzode <73869399+pratikzode@users.noreply.github.com> Date: Fri, 7 Apr 2023 13:41:16 -0700 Subject: [PATCH 051/363] TES2_14 Moving Test to JDBC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Forget to delete babel_function from the  contrib/babelfidhpg_tsql/expected/test on github site. But have already removed from gitfirm site. Task: TES2_14 Signed-off-by: pratikzode --- .../expected/test/babel_function.out | 2921 ----------------- test/JDBC/expected/babel_datatype.out | 10 - test/JDBC/input/babel_datatype.sql | 5 - 3 files changed, 2936 deletions(-) delete mode 100644 contrib/babelfishpg_tsql/expected/test/babel_function.out diff --git a/contrib/babelfishpg_tsql/expected/test/babel_function.out b/contrib/babelfishpg_tsql/expected/test/babel_function.out deleted file mode 100644 index 06c14c9fd3..0000000000 --- a/contrib/babelfishpg_tsql/expected/test/babel_function.out +++ /dev/null @@ -1,2921 +0,0 @@ --- tsql stype create function/procedure is not supported in postgres dialect -CREATE FUNCTION hi_func("@message" varchar(20)) RETURNS VOID AS BEGIN PRINT @message END; -ERROR: syntax error at or near "BEGIN" -LINE 1: ...N hi_func("@message" varchar(20)) RETURNS VOID AS BEGIN PRIN... - ^ -CREATE PROCEDURE hi_proc("@message" varchar(20)) AS BEGIN PRINT @message END; -ERROR: syntax error at or near "BEGIN" -LINE 1: ...EATE PROCEDURE hi_proc("@message" varchar(20)) AS BEGIN PRIN... - ^ -set babelfishpg_tsql.sql_dialect = "tsql"; --- it's supported in tsql dialect -CREATE FUNCTION hi_func("@message" varchar(20)) RETURNS VOID AS BEGIN PRINT @message END; -CREATE PROCEDURE hi_proc("@message" varchar(20)) AS BEGIN PRINT @message END; --- PROC is also supported in tsql dialect -create proc proc_1 as print 'Hello World from Babel'; --- BABEL-219 typmod/length of sys.varchar works correctly in procudure parameter -call hi_proc('Hello World'); -INFO: Hello World -call proc_1(); -INFO: Hello World from Babel --- clean up -drop function hi_func; -drop procedure hi_proc; -drop proc proc_1; --- test executing pltsql function in postgres dialect -reset babelfishpg_tsql.sql_dialect; -CREATE OR REPLACE FUNCTION test_func() RETURNS int AS $$ -BEGIN - DECLARE @a int = 1; - RETURN @a -END; -$$ LANGUAGE pltsql; --- should be able execute a pltsql function in postgres dialect -show babelfishpg_tsql.sql_dialect; - babelfishpg_tsql.sql_dialect ------------------------------- - postgres -(1 row) - -select test_func(); - test_func ------------ - 1 -(1 row) - -show babelfishpg_tsql.sql_dialect; - babelfishpg_tsql.sql_dialect ------------------------------- - postgres -(1 row) - --- test executing pltsql trigger in postgres dialect -CREATE TABLE employees( - id SERIAL PRIMARY KEY, - first_name VARCHAR(40) NOT NULL, - last_name VARCHAR(40) NOT NULL -); -CREATE TABLE employee_audits ( - id SERIAL PRIMARY KEY, - employee_id INT NOT NULL, - last_name VARCHAR(40) NOT NULL -); -CREATE OR REPLACE FUNCTION log_last_name_changes() RETURNS trigger AS $$ -BEGIN - IF NEW.last_name <> OLD.last_name THEN - INSERT INTO employee_audits(employee_id,last_name) - VALUES(OLD.id,OLD.last_name); - END IF; - RETURN NEW; -END; -$$ LANGUAGE plpgsql; -CREATE TRIGGER last_name_changes -BEFORE UPDATE -ON employees -FOR EACH ROW -EXECUTE PROCEDURE log_last_name_changes(); -INSERT INTO employees (first_name, last_name) VALUES ('A', 'B'); -INSERT INTO employees (first_name, last_name) VALUES ('C', 'D'); -SELECT * FROM employees; - id | first_name | last_name -----+------------+----------- - 1 | A | B - 2 | C | D -(2 rows) - -show babelfishpg_tsql.sql_dialect; - babelfishpg_tsql.sql_dialect ------------------------------- - postgres -(1 row) - -UPDATE employees SET last_name = 'E' WHERE ID = 2; -show babelfishpg_tsql.sql_dialect; - babelfishpg_tsql.sql_dialect ------------------------------- - postgres -(1 row) - -SELECT * FROM employees; - id | first_name | last_name -----+------------+----------- - 1 | A | B - 2 | C | E -(2 rows) - -SELECT * FROM employee_audits; - id | employee_id | last_name -----+-------------+----------- - 1 | 2 | D -(1 row) - --- test executing a plpgsql function in tsql dialect -CREATE OR REPLACE FUNCTION test_increment(i integer) RETURNS integer AS $$ -BEGIN - RETURN i + "1"; -END; -$$ LANGUAGE plpgsql; -CREATE OR REPLACE FUNCTION test_increment1(i integer) RETURNS integer AS $$ -BEGIN - RETURN i + CAST(n'1' AS varchar); -END; -$$ LANGUAGE plpgsql; --- test that sql_dialect is restored even when the function has error in it -set babelfishpg_tsql.sql_dialect = "tsql"; -show babelfishpg_tsql.sql_dialect; - babelfishpg_tsql.sql_dialect ------------------------------- - tsql -(1 row) - -select test_increment(1); -ERROR: column "1" does not exist -LINE 1: i + "1" - ^ -QUERY: i + "1" -CONTEXT: PL/pgSQL function test_increment(integer) line 3 at RETURN -show babelfishpg_tsql.sql_dialect; - babelfishpg_tsql.sql_dialect ------------------------------- - tsql -(1 row) - -select test_increment1(1); -ERROR: operator does not exist: integer + character varying -LINE 1: i + CAST(n'1' AS varchar) - ^ -HINT: No operator matches the given name and argument types. You might need to add explicit type casts. -QUERY: i + CAST(n'1' AS varchar) -CONTEXT: PL/pgSQL function test_increment1(integer) line 3 at RETURN -show babelfishpg_tsql.sql_dialect; - babelfishpg_tsql.sql_dialect ------------------------------- - tsql -(1 row) - --- test OBJECT_NAME function -select OBJECT_NAME('sys.columns'::regclass::Oid::int); - object_name -------------- - columns -(1 row) - -select OBJECT_NAME('boolin'::regproc::Oid::int); - object_name -------------- - boolin -(1 row) - -select OBJECT_NAME('int4'::regtype::Oid::int); - object_name -------------- - int4 -(1 row) - -select OBJECT_NAME(1); - object_name -------------- - -(1 row) - --- test SYSDATETIME function --- Returns of type datetime2 -select pg_typeof(SYSDATETIME()); - pg_typeof ------------ - datetime2 -(1 row) - --- test GETDATE function --- Returns of type datetime -select pg_typeof(GETDATE()); - pg_typeof ------------ - datetime -(1 row) - --- test current_timestamp function -select pg_typeof(current_timestamp); - pg_typeof ------------ - datetime -(1 row) - --- test calling with parenthesis, should fail -select current_timestamp(); -ERROR: syntax error at or near ")" -LINE 1: select current_timestamp(); - ^ --- test CONVERT function --- Conversion between varchar and date/time/datetime -select CONVERT(varchar(30), CAST('2017-08-25' AS date), 102); - babelfish_conv_helper_to_varchar ----------------------------------- - 2017.08.25 -(1 row) - -select CONVERT(varchar(30), CAST('13:01:59' AS time), 8); - babelfish_conv_helper_to_varchar ----------------------------------- - 13:01:59 -(1 row) - -select CONVERT(varchar(30), CAST('13:01:59' AS time), 22); - babelfish_conv_helper_to_varchar ----------------------------------- - 1:01:59 PM -(1 row) - -select CONVERT(varchar(30), CAST('13:01:59' AS time), 22); - babelfish_conv_helper_to_varchar ----------------------------------- - 1:01:59 PM -(1 row) - -select CONVERT(varchar(30), CAST('2017-08-25 13:01:59' AS datetime), 100); - babelfish_conv_helper_to_varchar ----------------------------------- - Aug 25 2017 1:01PM -(1 row) - -select CONVERT(varchar(30), CAST('2017-08-25 13:01:59' AS datetime), 109); - babelfish_conv_helper_to_varchar ----------------------------------- - Aug 25 2017 1:01:59:000PM -(1 row) - -select CONVERT(date, '08/25/2017', 101); - babelfish_conv_helper_to_date -------------------------------- - 08-25-2017 -(1 row) - -select CONVERT(time, '12:01:59', 101); - babelfish_conv_helper_to_time -------------------------------- - 12:01:59 -(1 row) - -select CONVERT(datetime, '2017-08-25 01:01:59PM', 120); - babelfish_conv_helper_to_datetime ------------------------------------ - Fri Aug 25 13:01:59 2017 -(1 row) - -select CONVERT(varchar, CONVERT(datetime2(7), '9999-12-31 23:59:59.9999999')); -WARNING: TIMESTAMP(7) precision reduced to maximum allowed, 6 -WARNING: TIMESTAMP(7) precision reduced to maximum allowed, 6 -LINE 1: select CONVERT(varchar, CONVERT(datetime2(7), '9999-12-31 23... - ^ - babelfish_conv_helper_to_varchar ----------------------------------- - Fri Dec 31 23:59:59.999999 999 -(1 row) - --- Conversion from float to varchar -select CONVERT(varchar(30), 11234561231231.234::float, 0); - babelfish_conv_helper_to_varchar ----------------------------------- - 1.12346e+13 -(1 row) - -select CONVERT(varchar(30), 11234561231231.234::float, 1); - babelfish_conv_helper_to_varchar ----------------------------------- - 1.1234561e+13 -(1 row) - -select CONVERT(varchar(30), 11234561231231.234::float, 2); - babelfish_conv_helper_to_varchar ----------------------------------- - 1.123456123123123e+13 -(1 row) - -select CONVERT(varchar(30), 11234561231231.234::float, 3); - babelfish_conv_helper_to_varchar ----------------------------------- - 1.1234561231231234e+13 -(1 row) - --- Conversion from money to varchar -select CONVERT(varchar(10), CAST(4936.56 AS MONEY), 0); - babelfish_conv_helper_to_varchar ----------------------------------- - 4936.56 -(1 row) - -select CONVERT(varchar(10), CAST(4936.56 AS MONEY), 1); - babelfish_conv_helper_to_varchar ----------------------------------- - 4,936.56 -(1 row) - -select CONVERT(varchar(10), CAST(4936.56 AS MONEY), 2); - babelfish_conv_helper_to_varchar ----------------------------------- - 4936.5600 -(1 row) - -select CONVERT(varchar(10), CAST(-4936.56 AS MONEY), 0); - babelfish_conv_helper_to_varchar ----------------------------------- - -4936.56 -(1 row) - --- Floor conversion to smallint, int, bigint -SELECT CONVERT(int, 99.9); - int4 ------- - 99 -(1 row) - -SELECT CONVERT(smallint, 99.9); - int2 ------- - 99 -(1 row) - -SELECT CONVERT(bigint, 99.9); - int8 ------- - 99 -(1 row) - -SELECT CONVERT(int, -99.9); - int4 ------- - -99 -(1 row) - -SELECT CONVERT(int, '99'); - int4 ------- - 99 -(1 row) - -SELECT CONVERT(int, CAST(99.9 AS double precision)); - int4 ------- - 99 -(1 row) - -SELECT CONVERT(int, CAST(99.9 AS real)); - int4 ------- - 99 -(1 row) - --- test TRY_CONVERT function --- Conversion between different types and varchar -select TRY_CONVERT(varchar(30), CAST('2017-08-25' AS date), 102); - babelfish_conv_helper_to_varchar ----------------------------------- - 2017.08.25 -(1 row) - -select TRY_CONVERT(varchar(30), CAST('13:01:59' AS time), 8); - babelfish_conv_helper_to_varchar ----------------------------------- - 13:01:59 -(1 row) - -select TRY_CONVERT(varchar(30), CAST('13:01:59' AS time), 22); - babelfish_conv_helper_to_varchar ----------------------------------- - 1:01:59 PM -(1 row) - -select TRY_CONVERT(varchar(30), CAST('2017-08-25 13:01:59' AS datetime), 109); - babelfish_conv_helper_to_varchar ----------------------------------- - Aug 25 2017 1:01:59:000PM -(1 row) - -select TRY_CONVERT(varchar(30), 11234561231231.234::float, 0); - babelfish_conv_helper_to_varchar ----------------------------------- - 1.12346e+13 -(1 row) - -select TRY_CONVERT(varchar(30), 11234561231231.234::float, 1); - babelfish_conv_helper_to_varchar ----------------------------------- - 1.1234561e+13 -(1 row) - -select TRY_CONVERT(varchar(10), CAST(4936.56 AS MONEY), 0); - babelfish_conv_helper_to_varchar ----------------------------------- - 4936.56 -(1 row) - --- Wrong conversions that return NULL -select TRY_CONVERT(date, 123); - babelfish_conv_helper_to_date -------------------------------- - -(1 row) - -select TRY_CONVERT(time, 123); - babelfish_conv_helper_to_time -------------------------------- - -(1 row) - -select TRY_CONVERT(datetime, 123); - babelfish_conv_helper_to_datetime ------------------------------------ - -(1 row) - -select TRY_CONVERT(money, 'asdf'); - babelfish_try_cast_to_any ---------------------------- - -(1 row) - --- test PARSE function --- Conversion from string to date/time/datetime -select PARSE('2017-08-25' AS date); - babelfish_parse_helper_to_date --------------------------------- - 08-25-2017 -(1 row) - -select PARSE('2017-08-25' AS date USING 'Cs-CZ'); - babelfish_parse_helper_to_date --------------------------------- - 08-25-2017 -(1 row) - -select PARSE('08/25/2017' AS date USING 'en-US'); - babelfish_parse_helper_to_date --------------------------------- - 08-25-2017 -(1 row) - -select PARSE('25/08/2017' AS date USING 'de-DE'); - babelfish_parse_helper_to_date --------------------------------- - 08-25-2017 -(1 row) - -select PARSE('13:01:59' AS time); - babelfish_parse_helper_to_time --------------------------------- - 13:01:59 -(1 row) - -select PARSE('13:01:59' AS time USING 'en-US'); - babelfish_parse_helper_to_time --------------------------------- - 13:01:59 -(1 row) - -select PARSE('13:01:59' AS time USING 'zh-CN'); - babelfish_parse_helper_to_time --------------------------------- - 13:01:59 -(1 row) - -select PARSE('2017-08-25 13:01:59' AS datetime); - babelfish_parse_helper_to_datetime ------------------------------------- - Fri Aug 25 13:01:59 2017 -(1 row) - -select PARSE('2017-08-25 13:01:59' AS datetime USING 'zh-CN'); - babelfish_parse_helper_to_datetime ------------------------------------- - Fri Aug 25 13:01:59 2017 -(1 row) - -select PARSE('12:01:59' AS time); - babelfish_parse_helper_to_time --------------------------------- - 12:01:59 -(1 row) - -select PARSE('2017-08-25 01:01:59PM' AS datetime); - babelfish_parse_helper_to_datetime ------------------------------------- - Fri Aug 25 13:01:59 2017 -(1 row) - --- Test if unnecessary culture arg given -select PARSE('123' AS int USING 'de-DE'); - int4 ------- - 123 -(1 row) - --- test TRY_PARSE function --- Expect null return on error --- Conversion from string to date/time/datetime -select TRY_PARSE('2017-08-25' AS date); - babelfish_parse_helper_to_date --------------------------------- - 08-25-2017 -(1 row) - -select TRY_PARSE('2017-08-25' AS date USING 'Cs-CZ'); - babelfish_parse_helper_to_date --------------------------------- - 08-25-2017 -(1 row) - -select TRY_PARSE('789' AS date USING 'en-US'); - babelfish_parse_helper_to_date --------------------------------- - -(1 row) - -select TRY_PARSE('asdf' AS date USING 'de-DE'); - babelfish_parse_helper_to_date --------------------------------- - -(1 row) - -select TRY_PARSE('13:01:59' AS time); - babelfish_parse_helper_to_time --------------------------------- - 13:01:59 -(1 row) - -select TRY_PARSE('asdf' AS time USING 'en-US'); - babelfish_parse_helper_to_time --------------------------------- - -(1 row) - -select TRY_PARSE('13-12-21' AS time USING 'zh-CN'); - babelfish_parse_helper_to_time --------------------------------- - 00:00:00 -(1 row) - -select TRY_PARSE('2017-08-25 13:01:59' AS datetime); - babelfish_parse_helper_to_datetime ------------------------------------- - Fri Aug 25 13:01:59 2017 -(1 row) - -select TRY_PARSE('20asdf17' AS datetime USING 'de-DE'); - babelfish_parse_helper_to_datetime ------------------------------------- - -(1 row) - --- Wrong conversions that return NULL -select TRY_PARSE('asdf' AS numeric(3,2)); - babelfish_try_cast_to_any ---------------------------- - -(1 row) - -select TRY_PARSE('123' AS datetime2); - babelfish_try_cast_to_any ---------------------------- - -(1 row) - -select TRY_PARSE('asdf' AS MONEY); - babelfish_try_cast_to_any ---------------------------- - -(1 row) - -select TRY_PARSE('asdf' AS int USING 'de-DE'); - babelfish_try_cast_floor_int ------------------------------- - -(1 row) - --- test serverproperty() function --- invalid property name, should reutnr NULL -select serverproperty(n'invalid property'); - serverproperty ----------------- - -(1 row) - --- valid supported properties -select serverproperty(n'collation'); - serverproperty ------------------------------- - sql_latin1_general_cp1_ci_as -(1 row) - -select serverproperty(n'collationId'); - serverproperty ----------------- - 0 -(1 row) - -select serverproperty(n'IsSingleUser'); - serverproperty ----------------- - 0 -(1 row) - -select serverproperty(n'ServerName'); - serverproperty ----------------- - BABELFISH -(1 row) - --- test ISDATE function --- test valid argument -SELECT ISDATE('12/26/2016'); - isdate --------- - 1 -(1 row) - -SELECT ISDATE('12-26-2016'); - isdate --------- - 1 -(1 row) - -SELECT ISDATE('12.26.2016'); - isdate --------- - 1 -(1 row) - -SELECT ISDATE('2016-12-26 23:30:05.523456'); - isdate --------- - 1 -(1 row) - --- test invalid argument -SELECT ISDATE('02/30/2016'); - isdate --------- - 0 -(1 row) - -SELECT ISDATE('12/32/2016'); - isdate --------- - 0 -(1 row) - -SELECT ISDATE('1995-10-1a'); - isdate --------- - 0 -(1 row) - -SELECT ISDATE(NULL); - isdate --------- - 0 -(1 row) - --- test DATEFROMPARTS function --- test valid arguments -select datefromparts(2020,12,31); - datefromparts ---------------- - 12-31-2020 -(1 row) - --- test invalid arguments, should fail -select datefromparts(2020, 2, 30); -ERROR: date field value out of range: 2020-02-30 -CONTEXT: SQL function "datefromparts" statement 1 -select datefromparts(2020, 13, 1); -ERROR: date field value out of range: 2020-13-01 -CONTEXT: SQL function "datefromparts" statement 1 -select datefromparts(-4, 3, 150); -ERROR: date field value out of range: -3-03-150 -CONTEXT: SQL function "datefromparts" statement 1 -select datefromparts(10, 55, 10.1); -ERROR: date field value out of range: 10-55-10 -select datefromparts('2020', 55, 100.1); -ERROR: date field value out of range: 2020-55-100 --- test DATETIMEFROMPARTS function --- test valid arguments -select datetimefromparts(2016, 12, 26, 23, 30, 5, 32); - datetimefromparts ------------------------------- - Mon Dec 26 23:30:05.033 2016 -(1 row) - -select datetimefromparts(2016.0, 12, 26, 23, 30, 5, 32); - datetimefromparts ------------------------------- - Mon Dec 26 23:30:05.033 2016 -(1 row) - -select datetimefromparts(2016.1, 12, 26, 23, 30, 5, 32); - datetimefromparts ------------------------------- - Mon Dec 26 23:30:05.033 2016 -(1 row) - -select datetimefromparts(2016, 12, 26.99, 23, 30, 5, 32); - datetimefromparts ------------------------------- - Mon Dec 26 23:30:05.033 2016 -(1 row) - -select datetimefromparts(2016, 12.90, 26, 23, 30, 5, 32); - datetimefromparts ------------------------------- - Mon Dec 26 23:30:05.033 2016 -(1 row) - --- test invalid arguments -select datetimefromparts(2016, 2, 30, 23, 30, 5, 32); -ERROR: date field value out of range: 2016-02-30 -CONTEXT: PL/pgSQL function sys.datetimefromparts(numeric,numeric,numeric,numeric,numeric,numeric,numeric) line 29 at assignment -select datetimefromparts(2016, 12, 26, 23, 30, 5); -ERROR: The datetimefromparts function requires 7 arguments -LINE 1: select datetimefromparts(2016, 12, 26, 23, 30, 5); - ^ -select datetimefromparts(2016, 12, 26, 23, 30, 5, NULL); - datetimefromparts -------------------- - -(1 row) - --- test DATEPART function --- test all valid datepart arguments -select datepart(year, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 2016 -(1 row) - -select datepart(yyyy, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 2016 -(1 row) - -select datepart(yy, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 2016 -(1 row) - -select datepart(quarter, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 4 -(1 row) - -select datepart(qq, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 4 -(1 row) - -select datepart(q, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 4 -(1 row) - -select datepart(month, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 12 -(1 row) - -select datepart(mm, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 12 -(1 row) - -select datepart(m, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 12 -(1 row) - -select datepart(dayofyear, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 361 -(1 row) - -select datepart(dy, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 361 -(1 row) - -select datepart(day, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 26 -(1 row) - -select datepart(dd, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 26 -(1 row) - -select datepart(d, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 26 -(1 row) - -select datepart(week, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 53 -(1 row) - -select datepart(wk, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 53 -(1 row) - -select datepart(ww, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 53 -(1 row) - -select datepart(weekday, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 2 -(1 row) - -select datepart(dw, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 2 -(1 row) - -select datepart(hour, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 15 -(1 row) - -select datepart(hh, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 15 -(1 row) - -select datepart(minute, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 30 -(1 row) - -select datepart(n, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 30 -(1 row) - -select datepart(second, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 5 -(1 row) - -select datepart(ss, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 5 -(1 row) - -select datepart(s, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 5 -(1 row) - -select datepart(millisecond, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 456 -(1 row) - -select datepart(ms, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 456 -(1 row) - -select datepart(microsecond, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 523456 -(1 row) - -select datepart(mcs, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 523456 -(1 row) - -select datepart(nanosecond, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ------------ - 523456000 -(1 row) - -select datepart(ns, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ------------ - 523456000 -(1 row) - -select datepart(tzoffset, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 480 -(1 row) - -select datepart(tz, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 480 -(1 row) - -select datepart(iso_week, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 52 -(1 row) - -select datepart(isowk, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 52 -(1 row) - -select datepart(isoww, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datepart ----------- - 52 -(1 row) - --- test different types of date/time arguments -select datepart(month, '2016-12-26 23:30:05.523'::sys.datetime); - datepart ----------- - 12 -(1 row) - -select datepart(quarter, '2016-12-26 23:30:05.523456'::datetime2); - datepart ----------- - 4 -(1 row) - -select datepart(hour, '2016-12-26 23:30:05'::smalldatetime); - datepart ----------- - 23 -(1 row) - -select datepart(dayofyear, '2016-12-26'::date); - datepart ----------- - 361 -(1 row) - -select datepart(second, '04:12:34.876543'::time); - datepart ----------- - 34 -(1 row) - --- test edge cases: try to get datepart that does not exist in the argument -select datepart(year, cast('12:10:30.123' as time)); - datepart ----------- - 1900 -(1 row) - -select datepart(yyyy, cast('12:10:30.123' as time)); - datepart ----------- - 1900 -(1 row) - -select datepart(yy, cast('12:10:30.123' as time)); - datepart ----------- - 1900 -(1 row) - -select datepart(quarter, cast('12:10:30.123' as time)); - datepart ----------- - 1 -(1 row) - -select datepart(qq, cast('12:10:30.123' as time)); - datepart ----------- - 1 -(1 row) - -select datepart(q, cast('12:10:30.123' as time)); - datepart ----------- - 1 -(1 row) - -select datepart(month, cast('12:10:30.123' as time)); - datepart ----------- - 1 -(1 row) - -select datepart(mm, cast('12:10:30.123' as time)); - datepart ----------- - 1 -(1 row) - -select datepart(m, cast('12:10:30.123' as time)); - datepart ----------- - 1 -(1 row) - -select datepart(dayofyear, cast('12:10:30.123' as time)); - datepart ----------- - 1 -(1 row) - -select datepart(dy, cast('12:10:30.123' as time)); - datepart ----------- - 1 -(1 row) - -select datepart(y, cast('12:10:30.123' as time)); - datepart ----------- - 1 -(1 row) - -select datepart(day, cast('12:10:30.123' as time)); - datepart ----------- - 1 -(1 row) - -select datepart(dd, cast('12:10:30.123' as time)); - datepart ----------- - 1 -(1 row) - -select datepart(d, cast('12:10:30.123' as time)); - datepart ----------- - 1 -(1 row) - -select datepart(week, cast('12:10:30.123' as time)); - datepart ----------- - 1 -(1 row) - -select datepart(wk, cast('12:10:30.123' as time)); - datepart ----------- - 1 -(1 row) - -select datepart(ww, cast('12:10:30.123' as time)); - datepart ----------- - 1 -(1 row) - -select datepart(weekday, cast('12:10:30.123' as time)); - datepart ----------- - 2 -(1 row) - -select datepart(dw, cast('12:10:30.123' as time)); - datepart ----------- - 2 -(1 row) - -select datepart(tzoffset, cast('12:10:30.123' as time)); - datepart ----------- - 0 -(1 row) - -select datepart(tz, cast('12:10:30.123' as time)); - datepart ----------- - 0 -(1 row) - -select datepart(iso_week, cast('12:10:30.123' as time)); - datepart ----------- - 1 -(1 row) - -select datepart(isowk, cast('12:10:30.123' as time)); - datepart ----------- - 1 -(1 row) - -select datepart(isoww, cast('12:10:30.123' as time)); - datepart ----------- - 1 -(1 row) - -select datepart(hour, cast('2016-12-26' as date)); - datepart ----------- - 0 -(1 row) - -select datepart(hh, cast('2016-12-26' as date)); - datepart ----------- - 0 -(1 row) - -select datepart(minute, cast('2016-12-26' as date)); - datepart ----------- - 0 -(1 row) - -select datepart(n, cast('2016-12-26' as date)); - datepart ----------- - 0 -(1 row) - -select datepart(second, cast('2016-12-26' as date)); - datepart ----------- - 0 -(1 row) - -select datepart(ss, cast('2016-12-26' as date)); - datepart ----------- - 0 -(1 row) - -select datepart(s, cast('2016-12-26' as date)); - datepart ----------- - 0 -(1 row) - -select datepart(millisecond, cast('2016-12-26' as date)); - datepart ----------- - 0 -(1 row) - -select datepart(ms, cast('2016-12-26' as date)); - datepart ----------- - 0 -(1 row) - -select datepart(microsecond, cast('2016-12-26' as date)); - datepart ----------- - 0 -(1 row) - -select datepart(mcs, cast('2016-12-26' as date)); - datepart ----------- - 0 -(1 row) - -select datepart(nanosecond, cast('2016-12-26' as date)); - datepart ----------- - 0 -(1 row) - -select datepart(ns, cast('2016-12-26' as date)); - datepart ----------- - 0 -(1 row) - --- test invalid interval, expect error -select datepart(invalid_interval, cast('2016-12-26 23:30:05.523456' as date)); -ERROR: 'invalid_interval' is not a recognized datepart option -CONTEXT: PL/pgSQL function sys.datepart_internal(text,anyelement,integer) line 66 at RAISE -PL/pgSQL function sys.datepart(text,anyelement) line 7 at RETURN -select datepart(invalidinterval, cast('12:10:30.123' as time)); -ERROR: 'invalidinterval' is not a recognized datepart option -CONTEXT: PL/pgSQL function sys.datepart_internal(text,anyelement,integer) line 66 at RAISE -PL/pgSQL function sys.datepart(text,anyelement) line 7 at RETURN --- test DATENAME function -select datename(year, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datename ----------- - 2016 -(1 row) - -select datename(dd, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datename ----------- - 26 -(1 row) - -select datename(weekday, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datename ----------- - Monday -(1 row) - -select datename(dw, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datename ----------- - Monday -(1 row) - -select datename(month, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datename ----------- - December -(1 row) - -select datename(mm, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datename ----------- - December -(1 row) - -select datename(m, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datename ----------- - December -(1 row) - -select datename(isowk, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - datename ----------- - 52 -(1 row) - --- test invalid argument, expect error -select datename(invalid_interval, cast('2016-12-26 23:30:05.523456' as date)); -ERROR: 'invalid_interval' is not a recognized datepart option -CONTEXT: PL/pgSQL function sys.datepart_internal(text,anyelement,integer) line 66 at RAISE -PL/pgSQL function sys.datepart(text,anyelement) line 7 at RETURN -SQL function "datename" statement 1 --- test DATEFIRST option, together DATEPART function --- This shows the return value for the week and weekday datepart for '2007-04-21' for each SET DATEFIRST argument. --- January 1, 2007 falls on a Monday. April 21, 2007 falls on a Saturday. --- DATEFIRST week weekday --- 1 16 6 --- 2 17 5 --- 3 17 4 --- 4 17 3 --- 5 17 2 --- 6 17 1 --- 7 16 7 -select @@datefirst; - datefirst ------------ - 7 -(1 row) - -set datefirst 1; -select datepart(week, '2007-04-21'::date), datepart(weekday, '2007-04-21'::date); - datepart | datepart -----------+---------- - 16 | 6 -(1 row) - -set datefirst 2; -select datepart(week, '2007-04-21'::date), datepart(weekday, '2007-04-21'::date); - datepart | datepart -----------+---------- - 17 | 5 -(1 row) - -set datefirst 3; -select datepart(week, '2007-04-21'::date), datepart(weekday, '2007-04-21'::date); - datepart | datepart -----------+---------- - 17 | 4 -(1 row) - -set datefirst 4; -select datepart(week, '2007-04-21'::date), datepart(weekday, '2007-04-21'::date); - datepart | datepart -----------+---------- - 17 | 3 -(1 row) - -set datefirst 5; -select datepart(week, '2007-04-21'::date), datepart(weekday, '2007-04-21'::date); - datepart | datepart -----------+---------- - 17 | 2 -(1 row) - -set datefirst 6; -select datepart(week, '2007-04-21'::date), datepart(weekday, '2007-04-21'::date); - datepart | datepart -----------+---------- - 17 | 1 -(1 row) - -set datefirst 7; -select datepart(week, '2007-04-21'::date), datepart(weekday, '2007-04-21'::date); - datepart | datepart -----------+---------- - 16 | 7 -(1 row) - --- test edge case: date within the week of Jan. 1st -select datepart(week, '2007-01-01'::date), datepart(weekday, '2007-01-01'::date); - datepart | datepart -----------+---------- - 1 | 2 -(1 row) - -select datepart(week, '2007-01-02'::date), datepart(weekday, '2007-01-02'::date); - datepart | datepart -----------+---------- - 1 | 3 -(1 row) - -select datepart(week, '2007-01-03'::date), datepart(weekday, '2007-01-03'::date); - datepart | datepart -----------+---------- - 1 | 4 -(1 row) - -select datepart(week, '2007-01-04'::date), datepart(weekday, '2007-01-04'::date); - datepart | datepart -----------+---------- - 1 | 5 -(1 row) - -select datepart(week, '2007-01-05'::date), datepart(weekday, '2007-01-05'::date); - datepart | datepart -----------+---------- - 1 | 6 -(1 row) - -select datepart(week, '2007-01-06'::date), datepart(weekday, '2007-01-06'::date); - datepart | datepart -----------+---------- - 1 | 7 -(1 row) - --- test edge case: date just outside the week of Jan. 1st -select datepart(week, '2007-01-07'::date), datepart(weekday, '2007-01-07'::date); - datepart | datepart -----------+---------- - 2 | 1 -(1 row) - --- test DATEDIFF function -select datediff(year, '2037-03-01 23:30:05.523'::sys.datetime, '2036-02-28 23:30:05.523'::sys.datetime); - datediff ----------- - -1 -(1 row) - -select datediff(quarter, '2037-03-01 23:30:05.523'::sys.datetime, '2036-02-28 23:30:05.523'::sys.datetime); - datediff ----------- - -4 -(1 row) - -select datediff(month, '2037-03-01 23:30:05.523'::sys.datetime, '2036-02-28 23:30:05.523'::sys.datetime); - datediff ----------- - -13 -(1 row) - -select datediff(dayofyear, '2037-03-01 23:30:05.523'::sys.datetime, '2036-02-28 23:30:05.523'::sys.datetime); - datediff ----------- - -367 -(1 row) - -select datediff(day, '2037-03-01 23:30:05.523'::sys.datetime, '2036-02-28 23:30:05.523'::sys.datetime); - datediff ----------- - -367 -(1 row) - -select datediff(week, '2037-03-01 23:30:05.523'::sys.datetime, '2036-02-28 23:30:05.523'::sys.datetime); - datediff ----------- - -52 -(1 row) - -select datediff(hour, '2037-03-01 23:30:05.523'::sys.datetime, '2036-02-28 23:30:05.523'::sys.datetime); - datediff ----------- - -8808 -(1 row) - -select datediff(minute, '2037-03-01 23:30:05.523'::sys.datetime, '2036-02-28 23:30:05.523'::sys.datetime); - datediff ----------- - -528480 -(1 row) - -select datediff(second, '2037-03-01 23:30:05.523'::sys.datetime, '2036-02-28 23:30:05.523'::sys.datetime); - datediff ------------ - -31708800 -(1 row) - -select datediff(millisecond, '2036-02-28 01:23:45.234'::sys.datetime, '2036-02-28 01:23:45.123'::sys.datetime); - datediff ----------- - -111 -(1 row) - -select datediff(microsecond, '2036-02-28 01:23:45.234'::sys.datetime, '2036-02-28 01:23:45.123'::sys.datetime); - datediff ----------- - -111000 -(1 row) - -select datediff(nanosecond, '2036-02-28 01:23:45.234'::sys.datetime, '2036-02-28 01:23:45.123'::sys.datetime); - datediff ------------- - -111000000 -(1 row) - --- test different types of date/time arguments -select datediff(minute, '2016-12-26 23:30:05.523456+8'::datetimeoffset, '2016-12-31 23:30:05.523456+8'::datetimeoffset); - datediff ----------- - 7200 -(1 row) - -select datediff(quarter, '2016-12-26 23:30:05.523456'::datetime2, '2018-08-31 23:30:05.523456'::datetime2); - datediff ----------- - 6 -(1 row) - -select datediff(hour, '2016-12-26 23:30:05'::smalldatetime, '2016-12-28 21:29:05'::smalldatetime); - datediff ----------- - 46 -(1 row) - -select datediff(year, '2037-03-01'::date, '2036-02-28'::date); - datediff ----------- - -1 -(1 row) - --- test DATEADD function -select dateadd(year, 2, '20060830'::datetime); - dateadd --------------------------- - Sat Aug 30 00:00:00 2008 -(1 row) - -select dateadd(quarter, 2, '20060830'::datetime); - dateadd --------------------------- - Wed Feb 28 00:00:00 2007 -(1 row) - -select dateadd(month, 1, '20060831'::datetime); - dateadd --------------------------- - Sat Sep 30 00:00:00 2006 -(1 row) - -select dateadd(dayofyear, 2, '20060830'::datetime); - dateadd --------------------------- - Fri Sep 01 00:00:00 2006 -(1 row) - -select dateadd(day, 2, '20060830'::datetime); - dateadd --------------------------- - Fri Sep 01 00:00:00 2006 -(1 row) - -select dateadd(week, 2, '20060830'::datetime); - dateadd --------------------------- - Wed Sep 13 00:00:00 2006 -(1 row) - -select dateadd(weekday, 2, '20060830'::datetime); - dateadd --------------------------- - Fri Sep 01 00:00:00 2006 -(1 row) - -select dateadd(hour, 2, '20060830'::datetime); - dateadd --------------------------- - Wed Aug 30 02:00:00 2006 -(1 row) - -select dateadd(minute, 2, '20060830'::datetime); - dateadd --------------------------- - Wed Aug 30 00:02:00 2006 -(1 row) - -select dateadd(second, 2, '20060830'::datetime); - dateadd --------------------------- - Wed Aug 30 00:00:02 2006 -(1 row) - -select dateadd(millisecond, 123, '20060830'::datetime); - dateadd ------------------------------- - Wed Aug 30 00:00:00.123 2006 -(1 row) - -select dateadd(microsecond, 123456, '20060830'::datetime); -ERROR: The datepart microsecond is not supported by date function dateadd for data type datetime. -CONTEXT: PL/pgSQL function sys.dateadd_internal(text,integer,anyelement) line 43 at RAISE -PL/pgSQL function sys.dateadd(text,integer,anyelement) line 7 at RETURN -select dateadd(nanosecond, 123456, '20060830'::datetime); -ERROR: The datepart nanosecond is not supported by date function dateadd for data type datetime. -CONTEXT: PL/pgSQL function sys.dateadd_internal(text,integer,anyelement) line 53 at RAISE -PL/pgSQL function sys.dateadd(text,integer,anyelement) line 7 at RETURN --- test different types of date/time arguments -select dateadd(hour, 2, '23:12:34.876543'::time); - dateadd ------------------ - 01:12:34.876543 -(1 row) - -select dateadd(quarter, 3, '2037-03-01'::date); - dateadd ------------- - 12-01-2037 -(1 row) - -select dateadd(minute, 70, '2016-12-26 23:30:05.523456+8'::datetimeoffset); - dateadd ----------------------------------------- - Tue Dec 27 00:40:05.523456 2016 +08:00 -(1 row) - -select dateadd(month, 2, '2016-12-26 23:30:05.523456'::datetime2); - dateadd ---------------------------------- - Sun Feb 26 23:30:05.523456 2017 -(1 row) - -select dateadd(second, 56, '2016-12-26 23:30:05'::smalldatetime); - dateadd --------------------------- - Mon Dec 26 23:31:00 2016 -(1 row) - --- test negative argument -select dateadd(year, -2, '20060830'::datetime); - dateadd --------------------------- - Mon Aug 30 00:00:00 2004 -(1 row) - -select dateadd(month, -20, '2016-12-26 23:30:05.523456'::datetime2); - dateadd ---------------------------------- - Sun Apr 26 23:30:05.523456 2015 -(1 row) - -select dateadd(hour, -2, '01:12:34.876543'::time); - dateadd ------------------ - 23:12:34.876543 -(1 row) - -select dateadd(minute, -70, '2016-12-26 00:30:05.523456+8'::datetimeoffset); - dateadd ----------------------------------------- - Sun Dec 25 23:20:05.523456 2016 +08:00 -(1 row) - -select dateadd(second, -56, '2016-12-26 00:00:55'::smalldatetime); - dateadd --------------------------- - Mon Dec 26 00:00:00 2016 -(1 row) - --- test return type -select pg_typeof(dateadd(hour, -2, '01:12:34.876543'::time)); - pg_typeof ------------------------- - time without time zone -(1 row) - -select pg_typeof(dateadd(second, -56, '2016-12-26 00:00:55'::smalldatetime)); - pg_typeof ---------------- - smalldatetime -(1 row) - -select pg_typeof(dateadd(year, -2, '20060830'::datetime)); - pg_typeof ------------ - datetime -(1 row) - -select pg_typeof(dateadd(month, -20, '2016-12-26 23:30:05.523456'::datetime2)); - pg_typeof ------------ - datetime2 -(1 row) - -select pg_typeof(dateadd(minute, -70, '2016-12-26 00:30:05.523456+8'::datetimeoffset)); - pg_typeof ----------------- - datetimeoffset -(1 row) - --- test illegal usage -select dateadd(minute, 2, '2037-03-01'::date); -ERROR: The datepart minute is not supported by date function dateadd for data type date. -CONTEXT: PL/pgSQL function sys.dateadd_internal(text,integer,anyelement) line 5 at RAISE -PL/pgSQL function sys.dateadd(text,integer,anyelement) line 7 at RETURN -select dateadd(day, 4, '04:12:34.876543'::time); -ERROR: The datepart day is not supported by date function dateadd for data type time. -CONTEXT: PL/pgSQL function sys.dateadd_internal(text,integer,anyelement) line 9 at RAISE -PL/pgSQL function sys.dateadd(text,integer,anyelement) line 7 at RETURN --- test using variables, instead of constants, for the second parameter -create table dateadd_table(a int, b datetime); -insert into dateadd_table values(1, '2020-10-29'::datetime); -select * from dateadd_table; - a | b ----+-------------------------- - 1 | Thu Oct 29 00:00:00 2020 -(1 row) - -update dateadd_table set b = dateadd(dd, a, '2020-10-30'::datetime); -select * from dateadd_table; - a | b ----+-------------------------- - 1 | Sat Oct 31 00:00:00 2020 -(1 row) - -create procedure dateadd_procedure as -begin - declare @d int = 1 - update dateadd_table set b = dateadd(dd, @d, CAST('2020-10-31' AS datetime)) -end; -call dateadd_procedure(); -select * from dateadd_table; - a | b ----+-------------------------- - 1 | Sun Nov 01 00:00:00 2020 -(1 row) - --- test CHARINDEX function -select CHARINDEX('hello', 'hello world'); - charindex ------------ - 1 -(1 row) - -select CHARINDEX('hello ', 'hello world'); - charindex ------------ - 0 -(1 row) - -select CHARINDEX('hello world', 'hello'); - charindex ------------ - 0 -(1 row) - --- test NULL input -select CHARINDEX(NULL, NULL); - charindex ------------ - -(1 row) - -select CHARINDEX(NULL, 'string'); - charindex ------------ - -(1 row) - -select CHARINDEX('pattern', NULL); - charindex ------------ - -(1 row) - -select CHARINDEX('pattern', 'string', NULL); - charindex ------------ - -(1 row) - --- test start_location parameter -select CHARINDEX('hello', 'hello world', -1); - charindex ------------ - 1 -(1 row) - -select CHARINDEX('hello', 'hello world', 0); - charindex ------------ - 1 -(1 row) - -select CHARINDEX('hello', 'hello world', 1); - charindex ------------ - 1 -(1 row) - -select CHARINDEX('hello', 'hello world', 2); - charindex ------------ - 0 -(1 row) - -select CHARINDEX('world', 'hello world', 6); - charindex ------------ - 7 -(1 row) - -select CHARINDEX('world', 'hello world', 7); - charindex ------------ - 7 -(1 row) - -select CHARINDEX('world', 'hello world', 8); - charindex ------------ - 0 -(1 row) - -select CHARINDEX('is', 'This is a string'); - charindex ------------ - 3 -(1 row) - -select CHARINDEX('is', 'This is a string', 4); - charindex ------------ - 6 -(1 row) - --- test STUFF function -select STUFF(n'abcdef', 2, 3, n'ijklmn'); - stuff ------------ - aijklmnef -(1 row) - -select STUFF(N' abcdef', 2, 3, N'ijklmn '); - stuff -------------- - ijklmn def -(1 row) - -select STUFF(N'abcdef', 2, 3, N' ijklmn '); - stuff -------------- - a ijklmn ef -(1 row) - -select STUFF(N'abcdef', 2, 3, N'ijklmn '); - stuff -------------- - aijklmn ef -(1 row) - --- test corner cases --- when start is negative or zero or longer than expr, return NULL -select STUFF(n'abcdef', -1, 3, n'ijklmn'); - stuff -------- - -(1 row) - -select STUFF(n'abcdef', 0, 3, n'ijklmn'); - stuff -------- - -(1 row) - -select STUFF(n'abcdef', 7, 3, n'ijklmn'); - stuff -------- - -(1 row) - --- when length is negative, return NULL -select STUFF(n'abcdef', 2, -3, n'ijklmn'); - stuff -------- - -(1 row) - --- when length is zero, just insert without deleting -select STUFF(n'abcdef', 2, 0, n'ijklmn'); - stuff --------------- - aijklmnbcdef -(1 row) - --- when length is longer than expr, delete up to the last character in expr -select STUFF(n'abcdef', 2, 7, n'ijklmn'); - stuff ---------- - aijklmn -(1 row) - --- when replace_expr is NULL, just delete without inserting -select STUFF(n'abcdef', 2, 3, NULL); - stuff -------- - aef -(1 row) - --- when argument are type unknown -select STUFF('abcdef', 2, 3, 'ijklmn'); - stuff ------------ - aijklmnef -(1 row) - -select STUFF('abcdef', 2, 3, n'ijklmn'); - stuff ------------ - aijklmnef -(1 row) - -select STUFF(n'abcdef', 2, 3, 'ijklmn'); - stuff ------------ - aijklmnef -(1 row) - --- when argument are type text -SELECT STUFF(CAST('abcdef' as text), 2, 3, CAST('ijklmn' as text)); - stuff ------------ - aijklmnef -(1 row) - -SELECT STUFF(CAST('abcdef' as text), 2, 3, 'ijklmn'); - stuff ------------ - aijklmnef -(1 row) - -SELECT STUFF('abcdef', 2, 3, CAST('ijklmn' as text)); - stuff ------------ - aijklmnef -(1 row) - --- when argument are type sys.varchar -SELECT STUFF(CAST('abcdef' as sys.varchar), 2, 3, CAST('ijklmn' as sys.varchar)); - stuff ------------ - aijklmnef -(1 row) - -SELECT STUFF('abcdef', 2, 3, CAST('ijklmn' as sys.varchar)); - stuff ------------ - aijklmnef -(1 row) - -SELECT STUFF(CAST('abcdef' as sys.varchar), 2, 3, 'ijklmn'); - stuff ------------ - aijklmnef -(1 row) - --- test ROUND function --- test rounding to the left of decimal point -select ROUND(748.58, -1); - round -------- - 750 -(1 row) - -select ROUND(748.58, -2); - round -------- - 700 -(1 row) - -select ROUND(748.58, -3); -ERROR: value overflows for numeric format -select ROUND(748.58, -4); - round -------- - 0 -(1 row) - -select ROUND(-648.1234, -2); - round -------- - -600 -(1 row) - -select ROUND(-648.1234, -3); -ERROR: value overflows for numeric format -select ROUND(-1548.1234, -3); - round -------- - -2000 -(1 row) - -select ROUND(-1548.1234, -4); -ERROR: value overflows for numeric format --- test NULL input -select ROUND(NULL, -3); - round -------- - -(1 row) - -select ROUND(748.58, NULL); - round -------- - -(1 row) - --- test rounding -SELECT ROUND(123.9994, 3); - round ---------- - 123.999 -(1 row) - -SELECT ROUND(123.9995, 3); - round ---------- - 124.000 -(1 row) - -SELECT ROUND(123.4545, 2); - round --------- - 123.45 -(1 row) - -SELECT ROUND(123.45, -2); - round -------- - 100 -(1 row) - --- test function parameter, i.e. truncation when not NULL or 0 -SELECT ROUND(150.75, 0); - round -------- - 151 -(1 row) - -SELECT ROUND(150.75, 0, 0); - round -------- - 151 -(1 row) - -SELECT ROUND(150.75, 0, NULL); - round -------- - 151 -(1 row) - -SELECT ROUND(150.75, 0, 1); - round -------- - 150 -(1 row) - --- test negative numbers -SELECT ROUND(-150.49, 0); - round -------- - -150 -(1 row) - -SELECT ROUND(-150.75, 0); - round -------- - -151 -(1 row) - -SELECT ROUND(-150.49, 0, 1); - round -------- - -150 -(1 row) - -SELECT ROUND(-150.75, 0, 1); - round -------- - -150 -(1 row) - --- test SELECT ROUND(col, ) -create table t1 (col numeric(4,2)); -insert into t1 values (64.24); -insert into t1 values (79.65); -insert into t1 values (NULL); -select ROUND(col, 3) from t1; - round --------- - 64.240 - 79.650 - -(3 rows) - -select ROUND(col, 2) from t1; - round -------- - 64.24 - 79.65 - -(3 rows) - -select ROUND(col, 1) from t1; - round -------- - 64.2 - 79.7 - -(3 rows) - -select ROUND(col, 0) from t1; - round -------- - 64 - 80 - -(3 rows) - -select ROUND(col, -1) from t1; - round -------- - 60 - 80 - -(3 rows) - -select ROUND(col, -2) from t1; -ERROR: value overflows for numeric format -select ROUND(col, -3) from t1; - round -------- - 0 - 0 - -(3 rows) - -select ROUND(col, 1, 1) from t1; - round -------- - 64.2 - 79.6 - -(3 rows) - -drop table t1; --- test DAY function -select DAY(CAST('2016-12-26 23:30:05.523456+8' AS datetimeoffset)); - day ------ - 26 -(1 row) - -select DAY(CAST('2016-12-26 23:30:05.523456' AS datetime2)); - day ------ - 26 -(1 row) - -select DAY(CAST('2016-12-26 23:30:05' AS smalldatetime)); - day ------ - 26 -(1 row) - -select DAY(CAST('04:12:34.876543' AS time)); - day ------ - 1 -(1 row) - -select DAY(CAST('2037-03-01' AS date)); - day ------ - 1 -(1 row) - -select DAY(CAST('2037-03-01 23:30:05.523' AS sys.datetime)); - day ------ - 1 -(1 row) - --- test MONTH function -select MONTH('2016-12-26 23:30:05.523456+8'::datetimeoffset); - month -------- - 12 -(1 row) - -select MONTH('2016-12-26 23:30:05.523456'::datetime2); - month -------- - 12 -(1 row) - -select MONTH('2016-12-26 23:30:05'::smalldatetime); - month -------- - 12 -(1 row) - -select MONTH('04:12:34.876543'::time); - month -------- - 1 -(1 row) - -select MONTH('2037-03-01'::date); - month -------- - 3 -(1 row) - -select MONTH('2037-03-01 23:30:05.523'::sys.datetime); - month -------- - 3 -(1 row) - --- test YEAR function -select YEAR('2016-12-26 23:30:05.523456+8'::datetimeoffset); - year ------- - 2016 -(1 row) - -select YEAR('2016-12-26 23:30:05.523456'::datetime2); - year ------- - 2016 -(1 row) - -select YEAR('2016-12-26 23:30:05'::smalldatetime); - year ------- - 2016 -(1 row) - -select YEAR('04:12:34.876543'::time); - year ------- - 1900 -(1 row) - -select YEAR('2037-03-01'::date); - year ------- - 2037 -(1 row) - -select YEAR('2037-03-01 23:30:05.523'::sys.datetime); - year ------- - 2037 -(1 row) - --- test SPACE function -select SPACE(NULL); - space -------- - -(1 row) - -select SPACE(2); - space -------- - -(1 row) - -select LEN(SPACE(5)); - len ------ - 0 -(1 row) - -select DATALENGTH(SPACE(5)); - datalength ------------- - 5 -(1 row) - --- test COUNT and COUNT_BIG aggregate function -CREATE TABLE t2(a int, b int); -INSERT INTO t2 VALUES(1, 100); -INSERT INTO t2 VALUES(2, 200); -INSERT INTO t2 VALUES(NULL, 300); -INSERT INTO t2 VALUES(2, 400); -CREATE TABLE t3(a varchar(255), b varchar(255),c int); -INSERT INTO t3 VALUES('xyz', 'a',1); -INSERT INTO t3 VALUES('xyz', 'b',1); -INSERT INTO t3 VALUES('abc', 'a',2); -INSERT INTO t3 VALUES('abc', 'b',2); -INSERT INTO t3 VALUES('efg', 'a',3); -INSERT INTO t3 VALUES('efg', 'b',3); -INSERT INTO t3 VALUES(NULL, NULL, 1); --- Aggregation Function Syntax --- COUNT[_BIG] ( { [ [ ALL | DISTINCT ] expression ] | * } ) --- should return all rows - 4 -SELECT COUNT(*) from t2; - count -------- - 4 -(1 row) - -SELECT pg_typeof(COUNT(*)) from t2; - pg_typeof ------------ - integer -(1 row) - -SELECT COUNT_BIG(*) from t2; - count_big ------------ - 4 -(1 row) - -SELECT pg_typeof(COUNT_BIG(*)) from t2; - pg_typeof ------------ - bigint -(1 row) - --- should return all rows where a is not NULL - 3 -SELECT COUNT(a) from t2; - count -------- - 3 -(1 row) - -SELECT pg_typeof(COUNT(a)) from t2; - pg_typeof ------------ - integer -(1 row) - -SELECT COUNT_BIG(a) from t2; - count_big ------------ - 3 -(1 row) - -SELECT pg_typeof(COUNT_BIG(a)) from t2; - pg_typeof ------------ - bigint -(1 row) - --- should return all rows where a is not NULL - 3 -SELECT COUNT(ALL a) from t2; - count -------- - 3 -(1 row) - -SELECT pg_typeof(COUNT(ALL a)) from t2; - pg_typeof ------------ - integer -(1 row) - -SELECT COUNT_BIG(ALL a) from t2; - count_big ------------ - 3 -(1 row) - -SELECT pg_typeof(COUNT_BIG(ALL a)) from t2; - pg_typeof ------------ - bigint -(1 row) - --- should return all rows where a is distinct - 2 -SELECT COUNT(DISTINCT a) from t2; - count -------- - 2 -(1 row) - -SELECT pg_typeof(COUNT(DISTINCT a)) from t2; - pg_typeof ------------ - integer -(1 row) - -SELECT COUNT_BIG(DISTINCT a) from t2; - count_big ------------ - 2 -(1 row) - -SELECT pg_typeof(COUNT_BIG(DISTINCT a)) from t2; - pg_typeof ------------ - bigint -(1 row) - --- Analytic Function Syntax --- COUNT[_BIG] ( [ ALL ] { expression | * } ) OVER ( [ ] ) -SELECT pg_typeof(COUNT(*) OVER (PARTITION BY a)) from t2; - pg_typeof ------------ - integer - integer - integer - integer -(4 rows) - -SELECT pg_typeof(COUNT_BIG(*) OVER (PARTITION BY a)) from t2; - pg_typeof ------------ - bigint - bigint - bigint - bigint -(4 rows) - -SELECT pg_typeof(COUNT(a) OVER (PARTITION BY a)) from t2; - pg_typeof ------------ - integer - integer - integer - integer -(4 rows) - -SELECT pg_typeof(COUNT_BIG(a) OVER (PARTITION BY a)) from t2; - pg_typeof ------------ - bigint - bigint - bigint - bigint -(4 rows) - -SELECT pg_typeof(COUNT(ALL a) OVER (PARTITION BY a)) from t2; - pg_typeof ------------ - integer - integer - integer - integer -(4 rows) - -SELECT pg_typeof(COUNT_BIG(ALL a) OVER (PARTITION BY a)) from t2; - pg_typeof ------------ - bigint - bigint - bigint - bigint -(4 rows) - -SELECT COUNT(*) from t3; - count -------- - 7 -(1 row) - -SELECT a, b, COUNT(*) OVER () from t3; - a | b | count ------+---+------- - xyz | a | 7 - xyz | b | 7 - abc | a | 7 - abc | b | 7 - efg | a | 7 - efg | b | 7 - | | 7 -(7 rows) - --- The result for order by is different in sql server because we have --- an ordering issue for null type (JIRA: BABEL-788) -SELECT a, b, COUNT(*) OVER (ORDER BY a) from t3; - a | b | count ------+---+------- - abc | b | 2 - abc | a | 2 - efg | a | 4 - efg | b | 4 - xyz | a | 6 - xyz | b | 6 - | | 7 -(7 rows) - -SELECT a, b, COUNT(*) OVER (ORDER BY a DESC) from t3; - a | b | count ------+---+------- - | | 1 - xyz | b | 3 - xyz | a | 3 - efg | b | 5 - efg | a | 5 - abc | b | 7 - abc | a | 7 -(7 rows) - -SELECT a, b, COUNT(*) OVER(PARTITION BY a) from t3; - a | b | count ------+---+------- - abc | b | 2 - abc | a | 2 - efg | a | 2 - efg | b | 2 - xyz | a | 2 - xyz | b | 2 - | | 1 -(7 rows) - -SELECT a, b, COUNT(*) OVER(PARTITION BY a ORDER BY b) from t3; - a | b | count ------+---+------- - abc | a | 1 - abc | b | 2 - efg | a | 1 - efg | b | 2 - xyz | a | 1 - xyz | b | 2 - | | 1 -(7 rows) - -SELECT a, b, COUNT(*) OVER(PARTITION BY a ORDER BY b ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING) from t3; - a | b | count ------+---+------- - abc | a | 2 - abc | b | 1 - efg | a | 2 - efg | b | 1 - xyz | a | 2 - xyz | b | 1 - | | 1 -(7 rows) - -SELECT COUNT_BIG(*) from t3; - count_big ------------ - 7 -(1 row) - -SELECT a, b, COUNT_BIG(*) OVER () from t3; - a | b | count_big ------+---+----------- - xyz | a | 7 - xyz | b | 7 - abc | a | 7 - abc | b | 7 - efg | a | 7 - efg | b | 7 - | | 7 -(7 rows) - -SELECT a, b, COUNT_BIG(*) OVER (ORDER BY a) from t3; - a | b | count_big ------+---+----------- - abc | b | 2 - abc | a | 2 - efg | a | 4 - efg | b | 4 - xyz | a | 6 - xyz | b | 6 - | | 7 -(7 rows) - -SELECT a, b, COUNT_BIG(*) OVER (ORDER BY a DESC) from t3; - a | b | count_big ------+---+----------- - | | 1 - xyz | b | 3 - xyz | a | 3 - efg | b | 5 - efg | a | 5 - abc | b | 7 - abc | a | 7 -(7 rows) - -SELECT a, b, COUNT_BIG(*) OVER(PARTITION BY a) from t3; - a | b | count_big ------+---+----------- - abc | b | 2 - abc | a | 2 - efg | a | 2 - efg | b | 2 - xyz | a | 2 - xyz | b | 2 - | | 1 -(7 rows) - -SELECT a, b, COUNT_BIG(*) OVER(PARTITION BY a ORDER BY b) from t3; - a | b | count_big ------+---+----------- - abc | a | 1 - abc | b | 2 - efg | a | 1 - efg | b | 2 - xyz | a | 1 - xyz | b | 2 - | | 1 -(7 rows) - -SELECT a, b, COUNT_BIG(*) OVER(PARTITION BY a ORDER BY b ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING) from t3; - a | b | count_big ------+---+----------- - abc | a | 2 - abc | b | 1 - efg | a | 2 - efg | b | 1 - xyz | a | 2 - xyz | b | 1 - | | 1 -(7 rows) - --- COUNT(*) takes no parameters and does not support the use of DISTINC, expect error -SELECT COUNT(DISTINCT *) from t3; -ERROR: syntax error at or near "*" -LINE 1: SELECT COUNT(DISTINCT *) from t3; - ^ -SELECT COUNT(ALL *) from t3; -ERROR: syntax error at or near "*" -LINE 1: SELECT COUNT(ALL *) from t3; - ^ -DROP TABLE t2; -DROP TABLE t3; --- clean up -drop function test_func; -drop table employees; -drop table employee_audits; -drop function log_last_name_changes; -drop function test_increment; -drop function test_increment1; -drop table dateadd_table; -drop procedure dateadd_procedure; --- test inline table-valued functions --- simple case -create function itvf1 (@number int) returns table as return (select 1 as a, 2 as b); -select * from itvf1(5); - a | b ----+--- - 1 | 2 -(1 row) - --- should fail because column names are not specified -create function itvf2 (@number int) returns table as return (select 1, 2); -ERROR: CREATE FUNCTION failed because a column name is not specified for column 1 --- select from a table -create table example_table(name text, age int); -insert into example_table values('hello', 3); --- should have 'a' and 'b' as result column names -create function itvf3 (@number int) returns table as return (select name as a, age as b from example_table); -select * from itvf3(5); - a | b --------+--- - hello | 3 -(1 row) - --- test returning multiple rows -insert into example_table values('hello1', 4); -insert into example_table values('hello2', 5); -insert into example_table values('hello3', 6); -select * from itvf3(5); - a | b ---------+--- - hello | 3 - hello1 | 4 - hello2 | 5 - hello3 | 6 -(4 rows) - --- invoke a function -create function itvf4 (@number int) returns table as -return (select sys.serverproperty(N'collation') as property1, sys.serverproperty(N'IsSingleUser') as property2); -select * from itvf4(5); - property1 | property2 -------------------------------+----------- - sql_latin1_general_cp1_ci_as | 0 -(1 row) - --- case where the return table has only one column - Postgres considers these as --- scalar functions -create or replace function itvf5 (@number int) returns table as return (select 1 as a); -select * from itvf5(5); - a ---- - 1 -(1 row) - -create or replace function itvf6 (@number int) returns table as -return (select sys.serverproperty(N'collation') as property); -select * from itvf6(5); - property ------------------------------- - sql_latin1_general_cp1_ci_as -(1 row) - --- complex queries with use of function parameter -create table id_name(id int, name text); -insert into id_name values(1001, 'adam'); -insert into id_name values(1002, 'bob'); -insert into id_name values(1003, 'chaz'); -insert into id_name values(1004, 'dave'); -insert into id_name values(1005, 'ed'); -create table id_score(id int, score int); -insert into id_score values(1001, 90); -insert into id_score values(1001, 70); -insert into id_score values(1002, 90); -insert into id_score values(1002, 80); -insert into id_score values(1003, 80); -insert into id_score values(1003, 70); -insert into id_score values(1004, 80); -insert into id_score values(1004, 60); -insert into id_score values(1005, 80); -insert into id_score values(1005, 100); -create function itvf7 (@number int) returns table as return ( -select n.id, n.name as first_name, sum(s.score) as total_score -from id_name as n -join id_score as s -on n.id = s.id -where s.id <= @number -group by n.id, n.name -order by n.id -); -select * from itvf7(1004); - id | first_name | total_score -------+------------+------------- - 1001 | adam | 160 - 1002 | bob | 170 - 1003 | chaz | 150 - 1004 | dave | 140 -(4 rows) - --- test inline table-valued function with table-valued parameter -create type tableType as table( - a text not null, - b int primary key, - c int); -create function itvf8 (@number int, @tableVar tableType READONLY) returns table as return ( -select n.id, n.name as first_name, sum(s.score) as total_score -from id_name as n -join id_score as s -on n.id = s.id -where s.id <= @number and s.id in (select c from @tableVar) -group by n.id, n.name -order by n.id -); -create procedure itvf8_proc as -begin - declare @tableVariable tableType - insert into @tableVariable values('hello1', 1, 1001) - insert into @tableVariable values('hello2', 2, 1002) - select * from itvf8(1004, @tableVariable) -end; -call itvf8_proc(); - id | first_name | total_score -------+------------+------------- - 1001 | adam | 160 - 1002 | bob | 170 -(2 rows) - --- test using parameter in projection list -create function itvf9(@number int) returns table as return ( -select @number as a from id_name -); -select * from itvf9(1); - a ---- - 1 - 1 - 1 - 1 - 1 -(5 rows) - --- test invalid ITVFs --- function does not have RETURN QUERY -create function itvf10(@number int) returns table as BEGIN select * from id_name END; -ERROR: syntax error near 'BEGIN' at line 1 and character position 0 -CONTEXT: compilation of PL/tsql function "itvf10" near line 1 --- function has more than one RETURN QUERY -create function itvf11(@number int) returns table as -BEGIN - return select * from id_name - return select id from id_name -END; -ERROR: syntax error near 'BEGIN' at line 1 and character position 0 -CONTEXT: compilation of PL/tsql function "itvf11" near line 1 --- test creating ITVF in a transaction and rollback - should still work as --- normal despite the function validator's modification of the pg_proc entry -begin transaction; -create function itvf12(@number int) returns table as return ( -select @number as a from id_name -); -rollback; -select * from itvf12(1); -ERROR: function itvf12(integer) does not exist -LINE 1: select * from itvf12(1); - ^ -HINT: No function matches the given name and argument types. You might need to add explicit type casts. --- "AS" keyword is optional in TSQL function -\tsql on -create function babel651_f() returns int -begin - return 1 -end -go -create table babel651_t(a int); -go -create function babel651_itvf() returns table - return (select * from babel651_t) -go -create function babel651_mstvf(@i int) returns @tableVar table -( - a text not null -) -begin - insert into @tableVar values('hello1'); -end; -go -select babel651_f(); -go - babel651_f ------------- - 1 -(1 row) - -select * from babel651_itvf(); -go - a ---- -(0 rows) - -select * from babel651_mstvf(1); -go - a --------- - hello1 -(1 row) - -\tsql off --- clean up -drop function itvf1; -drop table example_table; -drop function itvf3; -drop function itvf4; -drop function itvf5; -drop function itvf6; -drop table id_name; -drop table id_score; -drop function itvf7; -drop procedure itvf8_proc; -drop function itvf8; -drop type tableType; -drop function itvf9; -drop table babel651_t; -drop function babel651_f; -drop function babel651_itvf; -drop function babel651_mstvf; --- test RETURN not followed by a semicolon -\tsql on -create function test_return1(@stringToSplit VARCHAR(MAX)) -RETURNS @returnList TABLE([Name] [nvarchar] (500)) -AS -BEGIN - RETURN -END -GO -select * from test_return1('test'); -GO - name ------- -(0 rows) - -drop function test_return1; -GO -create function test_return2(@stringToSplit VARCHAR(MAX)) -RETURNS @returnList TABLE([Name] [nvarchar] (500)) -AS -BEGIN - RETURN; -END -GO -select * from test_return2('test'); -GO - name ------- -(0 rows) - -drop function test_return2; -GO -create function test_return3(@a int) -RETURNS @returnList TABLE([Name] [nvarchar] (500)) -AS -BEGIN - IF @a = 1 - RETURN - SELECT @a = 2 - INSERT into @returnList values('abc') - RETURN -END -GO -select * from test_return3(1); -GO - name ------- -(0 rows) - -select * from test_return3(2); -GO - name ------- - abc -(1 row) - -drop function test_return3; -GO -create function test_return4(@a int) -RETURNS @returnList TABLE([Name] [nvarchar] (500)) -AS -BEGIN - IF @a = 1 - RETURN - ELSE - SELECT @a = 2 - INSERT into @returnList values('abc') - RETURN -END -GO -select * from test_return4(1); -GO - name ------- -(0 rows) - -select * from test_return4(2); -GO - name ------- - abc -(1 row) - -drop function test_return4; -GO -\tsql off diff --git a/test/JDBC/expected/babel_datatype.out b/test/JDBC/expected/babel_datatype.out index e92e1542df..2d9bf5db06 100644 --- a/test/JDBC/expected/babel_datatype.out +++ b/test/JDBC/expected/babel_datatype.out @@ -1477,16 +1477,6 @@ nchar --- [BABEL-257] test varchar defaults to sys.varchar in new --- database and new schema -SELECT current_database(); -GO -~~START~~ -varchar -jdbc_testdb -~~END~~ - - SELECT set_config('babelfishpg_tsql.sql_dialect', 'postgres', false); GO ~~START~~ diff --git a/test/JDBC/input/babel_datatype.sql b/test/JDBC/input/babel_datatype.sql index 14bfb4bacf..e85d5763ce 100644 --- a/test/JDBC/input/babel_datatype.sql +++ b/test/JDBC/input/babel_datatype.sql @@ -589,11 +589,6 @@ drop table test_nchar; GO --- [BABEL-257] test varchar defaults to sys.varchar in new --- database and new schema -SELECT current_database(); -GO - SELECT set_config('babelfishpg_tsql.sql_dialect', 'postgres', false); GO From 8a387d1fc486ee4b383de6d2f1aef3e196a7dd11 Mon Sep 17 00:00:00 2001 From: ZhenyeLee <73271404+ZhenyeLee@users.noreply.github.com> Date: Tue, 11 Apr 2023 12:35:03 -0700 Subject: [PATCH 052/363] Implement numeric representation of datetime (#1389) Before this PR, there is no conversion from numeric to datetime, and DATEADD function doesn't support numeric representation of datetime. The tests are failed in all CONVERT(DATETIME, source_type_value) and DATEADD(source_type_value, source_type_value), also failed in Datetime_proc1 and SMALLDatetime_proc1. When converting BIT to DATETIME implicitly, the test passes when BIT is an Integer number, but fails when BIT is represents as NUMERIC, the reason is we doesn't support implicit convert from NUMERIC to BIT. In this PR, we make casting from NUMERIC to BIT as implicit. This PR also adds numeric representation into babelfish_conv_string_to_datetime function to convert NUMERIC to DATETIME. The numeric representation pattern starts with an optional minus sign, followed by one or more digits, optionally followed by a decimal point and one or more digits. When the input matches numeric representation pattern, we added this numeric input with 1/1/1900. For DATEADD function, this PR adds a helper function to help adding numeric representation with DATETIME. Task: BABEL-323 Signed-off-by: Zhenye Li --- contrib/babelfishpg_common/Version.config | 2 +- contrib/babelfishpg_common/sql/bit.sql | 2 +- .../babelfishpg_common--3.1.0--3.2.0.sql | 10 + .../sql/sys_function_helpers.sql | 5 + .../babelfishpg_tsql/sql/sys_functions.sql | 77 + .../babelfishpg_tsql--3.1.0--3.2.0.sql | 672 +++++ ...ime-numeric-dateaddfunction-vu-prepare.out | 319 +++ ...time-numeric-dateaddfunction-vu-verify.out | 292 ++ ...time-numeric-representation-vu-prepare.out | 352 +++ ...etime-numeric-representation-vu-verify.out | 2426 +++++++++++++++++ test/JDBC/expected/babel_function.out | 2 +- ...ime-numeric-dateaddfunction-vu-prepare.sql | 273 ++ ...time-numeric-dateaddfunction-vu-verify.sql | 149 + ...time-numeric-representation-vu-prepare.sql | 286 ++ ...etime-numeric-representation-vu-verify.sql | 754 +++++ test/JDBC/upgrade/14_6/schedule | 1 + test/JDBC/upgrade/14_7/schedule | 1 + test/JDBC/upgrade/14_8/schedule | 1 + test/JDBC/upgrade/15_1/schedule | 1 + test/JDBC/upgrade/15_2/schedule | 1 + test/JDBC/upgrade/latest/schedule | 2 + .../expected_drop.out | 1 + .../expected_dependency.out | 4 - 23 files changed, 5626 insertions(+), 7 deletions(-) create mode 100644 contrib/babelfishpg_common/sql/upgrades/babelfishpg_common--3.1.0--3.2.0.sql create mode 100644 test/JDBC/expected/TestDatetime-numeric-dateaddfunction-vu-prepare.out create mode 100644 test/JDBC/expected/TestDatetime-numeric-dateaddfunction-vu-verify.out create mode 100644 test/JDBC/expected/TestDatetime-numeric-representation-vu-prepare.out create mode 100644 test/JDBC/expected/TestDatetime-numeric-representation-vu-verify.out create mode 100644 test/JDBC/input/datatypes/TestDatetime-numeric-dateaddfunction-vu-prepare.sql create mode 100644 test/JDBC/input/datatypes/TestDatetime-numeric-dateaddfunction-vu-verify.sql create mode 100644 test/JDBC/input/datatypes/TestDatetime-numeric-representation-vu-prepare.sql create mode 100644 test/JDBC/input/datatypes/TestDatetime-numeric-representation-vu-verify.sql diff --git a/contrib/babelfishpg_common/Version.config b/contrib/babelfishpg_common/Version.config index 4478f8ef3a..cee9736ce3 100644 --- a/contrib/babelfishpg_common/Version.config +++ b/contrib/babelfishpg_common/Version.config @@ -1,4 +1,4 @@ BBFPGCMN_MAJOR_VERSION=3 -BBFPGCMN_MINOR_VERSION=1 +BBFPGCMN_MINOR_VERSION=2 BBFPGCMN_MICRO_VERSION=0 diff --git a/contrib/babelfishpg_common/sql/bit.sql b/contrib/babelfishpg_common/sql/bit.sql index 31363bced5..3ae7daebe1 100644 --- a/contrib/babelfishpg_common/sql/bit.sql +++ b/contrib/babelfishpg_common/sql/bit.sql @@ -80,7 +80,7 @@ AS 'babelfishpg_common', 'numeric_bit' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; CREATE CAST (NUMERIC AS sys.BIT) -WITH FUNCTION sys.numeric_bit (NUMERIC) AS ASSIGNMENT; +WITH FUNCTION sys.numeric_bit (NUMERIC) AS IMPLICIT; CREATE OR REPLACE FUNCTION sys.bit2int2(sys.BIT) RETURNS INT2 diff --git a/contrib/babelfishpg_common/sql/upgrades/babelfishpg_common--3.1.0--3.2.0.sql b/contrib/babelfishpg_common/sql/upgrades/babelfishpg_common--3.1.0--3.2.0.sql new file mode 100644 index 0000000000..18c1491c8b --- /dev/null +++ b/contrib/babelfishpg_common/sql/upgrades/babelfishpg_common--3.1.0--3.2.0.sql @@ -0,0 +1,10 @@ +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION ""babelfishpg_common"" UPDATE TO '3.2.0'" to load this file. \quit + +SELECT set_config('search_path', 'sys, '||current_setting('search_path'), false); + +DROP CAST IF EXISTS(NUMERIC AS sys.BIT); +CREATE CAST (NUMERIC AS sys.BIT) WITH FUNCTION sys.numeric_bit (NUMERIC) AS IMPLICIT; + +-- Reset search_path to not affect any subsequent scripts +SELECT set_config('search_path', trim(leading 'sys, ' from current_setting('search_path')), false); diff --git a/contrib/babelfishpg_tsql/sql/sys_function_helpers.sql b/contrib/babelfishpg_tsql/sql/sys_function_helpers.sql index 80e7aca6fa..a0e9fb8719 100644 --- a/contrib/babelfishpg_tsql/sql/sys_function_helpers.sql +++ b/contrib/babelfishpg_tsql/sql/sys_function_helpers.sql @@ -1233,6 +1233,7 @@ DECLARE TIMEUNIT_REGEXP CONSTANT VARCHAR COLLATE "C" := '\s*\d{1,2}\s*'; FRACTSECS_REGEXP CONSTANT VARCHAR COLLATE "C" := '\s*\d{1,9}\s*'; DATATYPE_REGEXP CONSTANT VARCHAR COLLATE "C" := '^(DATETIME|SMALLDATETIME|DATETIME2)\s*(?:\()?\s*((?:-)?\d+)?\s*(?:\))?$'; + DIGITREPRESENT_REGEXP CONSTANT VARCHAR COLLATE "C" := '^\-?\d+\.?(?:\d+)?$'; HHMMSSFS_PART_REGEXP CONSTANT VARCHAR COLLATE "C" := concat(TIMEUNIT_REGEXP, AMPM_REGEXP, '|', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, AMPM_REGEXP, '?|', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '\.', FRACTSECS_REGEXP, AMPM_REGEXP, '?|', @@ -1650,6 +1651,10 @@ BEGIN v_day := '01'; v_month := '01'; v_year := '1900'; + ELSIF (v_datetimestring ~* DIGITREPRESENT_REGEXP) + THEN + v_resdatetime = CAST('1900-01-01 00:00:00.0' AS sys.DATETIME) + v_datetimestring::NUMERIC; + RETURN v_resdatetime; ELSE RAISE invalid_datetime_format; END IF; diff --git a/contrib/babelfishpg_tsql/sql/sys_functions.sql b/contrib/babelfishpg_tsql/sql/sys_functions.sql index 7dde13c043..a90640308c 100644 --- a/contrib/babelfishpg_tsql/sql/sys_functions.sql +++ b/contrib/babelfishpg_tsql/sql/sys_functions.sql @@ -1132,6 +1132,43 @@ END; $body$ LANGUAGE plpgsql IMMUTABLE; +CREATE OR REPLACE FUNCTION sys.dateadd(IN datepart PG_CATALOG.TEXT, IN num INTEGER, IN startdate sys.bit) RETURNS DATETIME +AS +$body$ +BEGIN + RAISE EXCEPTION 'Argument data type bit is invalid for argument 2 of dateadd function.'; +END; +$body$ +LANGUAGE plpgsql IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.dateadd(IN datepart PG_CATALOG.TEXT, IN num INTEGER, IN startdate numeric) RETURNS DATETIME +AS +$body$ +BEGIN + return sys.dateadd_numeric_representation_helper(datepart, num, startdate); +END; +$body$ +LANGUAGE plpgsql IMMUTABLE; + + +CREATE OR REPLACE FUNCTION sys.dateadd(IN datepart PG_CATALOG.TEXT, IN num INTEGER, IN startdate real) RETURNS DATETIME +AS +$body$ +BEGIN + return sys.dateadd_numeric_representation_helper(datepart, num, startdate); +END; +$body$ +LANGUAGE plpgsql IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.dateadd(IN datepart PG_CATALOG.TEXT, IN num INTEGER, IN startdate double precision) RETURNS DATETIME +AS +$body$ +BEGIN + return sys.dateadd_numeric_representation_helper(datepart, num, startdate); +END; +$body$ +LANGUAGE plpgsql IMMUTABLE; + CREATE OR REPLACE FUNCTION sys.dateadd(IN datepart PG_CATALOG.TEXT, IN num INTEGER, IN startdate ANYELEMENT) RETURNS ANYELEMENT AS $body$ @@ -1147,6 +1184,46 @@ END; $body$ LANGUAGE plpgsql IMMUTABLE; +CREATE OR REPLACE FUNCTION sys.dateadd_numeric_representation_helper(IN datepart PG_CATALOG.TEXT, IN num INTEGER, IN startdate ANYELEMENT) RETURNS DATETIME AS $$ +DECLARE + digit_to_startdate DATETIME; +BEGIN + IF pg_typeof(startdate) IN ('bigint'::regtype, 'int'::regtype, 'smallint'::regtype,'sys.tinyint'::regtype, + 'numeric'::regtype, 'float'::regtype,'double precision'::regtype, 'real'::regtype, 'sys.money'::regtype,'sys.smallmoney'::regtype) THEN + digit_to_startdate := CAST('1900-01-01 00:00:00.0' AS sys.DATETIME) + CAST(startdate as sys.DATETIME); + END IF; + + CASE datepart + WHEN 'year' THEN + RETURN digit_to_startdate + make_interval(years => num); + WHEN 'quarter' THEN + RETURN digit_to_startdate + make_interval(months => num * 3); + WHEN 'month' THEN + RETURN digit_to_startdate + make_interval(months => num); + WHEN 'dayofyear', 'y' THEN + RETURN digit_to_startdate + make_interval(days => num); + WHEN 'day' THEN + RETURN digit_to_startdate + make_interval(days => num); + WHEN 'week' THEN + RETURN digit_to_startdate + make_interval(weeks => num); + WHEN 'weekday' THEN + RETURN digit_to_startdate + make_interval(days => num); + WHEN 'hour' THEN + RETURN digit_to_startdate + make_interval(hours => num); + WHEN 'minute' THEN + RETURN digit_to_startdate + make_interval(mins => num); + WHEN 'second' THEN + RETURN digit_to_startdate + make_interval(secs => num); + WHEN 'millisecond' THEN + RETURN digit_to_startdate + make_interval(secs => (num::numeric) * 0.001); + ELSE + RAISE EXCEPTION 'The datepart % is not supported by date function dateadd for data type datetime.', datepart; + END CASE; +END; +$$ +STRICT +LANGUAGE plpgsql IMMUTABLE; + CREATE OR REPLACE FUNCTION sys.datepart_internal(IN datepart PG_CATALOG.TEXT, IN arg anyelement,IN df_tz INTEGER DEFAULT 0) RETURNS INTEGER AS $$ DECLARE result INTEGER; diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql index 3b60d6058e..140bce8956 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql @@ -55,6 +55,678 @@ SELECT FROM sys.babelfish_syslanguages; GRANT SELECT ON sys.syslanguages TO PUBLIC; +CREATE OR REPLACE FUNCTION sys.dateadd(IN datepart PG_CATALOG.TEXT, IN num INTEGER, IN startdate sys.bit) RETURNS DATETIME +AS +$body$ +BEGIN + RAISE EXCEPTION 'Argument data type bit is invalid for argument 2 of dateadd function.'; +END; +$body$ +LANGUAGE plpgsql IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.dateadd(IN datepart PG_CATALOG.TEXT, IN num INTEGER, IN startdate numeric) RETURNS DATETIME +AS +$body$ +BEGIN + return sys.dateadd_numeric_representation_helper(datepart, num, startdate); +END; +$body$ +LANGUAGE plpgsql IMMUTABLE; + + +CREATE OR REPLACE FUNCTION sys.dateadd(IN datepart PG_CATALOG.TEXT, IN num INTEGER, IN startdate real) RETURNS DATETIME +AS +$body$ +BEGIN + return sys.dateadd_numeric_representation_helper(datepart, num, startdate); +END; +$body$ +LANGUAGE plpgsql IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.dateadd(IN datepart PG_CATALOG.TEXT, IN num INTEGER, IN startdate double precision) RETURNS DATETIME +AS +$body$ +BEGIN + return sys.dateadd_numeric_representation_helper(datepart, num, startdate); +END; +$body$ +LANGUAGE plpgsql IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.dateadd_numeric_representation_helper(IN datepart PG_CATALOG.TEXT, IN num INTEGER, IN startdate ANYELEMENT) RETURNS DATETIME AS $$ +DECLARE + digit_to_startdate DATETIME; +BEGIN + IF pg_typeof(startdate) IN ('bigint'::regtype, 'int'::regtype, 'smallint'::regtype,'sys.tinyint'::regtype, + 'numeric'::regtype, 'float'::regtype,'double precision'::regtype, 'real'::regtype, 'sys.money'::regtype,'sys.smallmoney'::regtype,'sys.bit'::regtype) THEN + digit_to_startdate := CAST('1900-01-01 00:00:00.0' AS sys.DATETIME) + CAST(startdate as sys.DATETIME); + END IF; + + CASE datepart + WHEN 'year' THEN + RETURN digit_to_startdate + make_interval(years => num); + WHEN 'quarter' THEN + RETURN digit_to_startdate + make_interval(months => num * 3); + WHEN 'month' THEN + RETURN digit_to_startdate + make_interval(months => num); + WHEN 'dayofyear', 'y' THEN + RETURN digit_to_startdate + make_interval(days => num); + WHEN 'day' THEN + RETURN digit_to_startdate + make_interval(days => num); + WHEN 'week' THEN + RETURN digit_to_startdate + make_interval(weeks => num); + WHEN 'weekday' THEN + RETURN digit_to_startdate + make_interval(days => num); + WHEN 'hour' THEN + RETURN digit_to_startdate + make_interval(hours => num); + WHEN 'minute' THEN + RETURN digit_to_startdate + make_interval(mins => num); + WHEN 'second' THEN + RETURN digit_to_startdate + make_interval(secs => num); + WHEN 'millisecond' THEN + RETURN digit_to_startdate + make_interval(secs => (num::numeric) * 0.001); + ELSE + RAISE EXCEPTION 'The datepart % is not supported by date function dateadd for data type datetime.', datepart; + END CASE; +END; +$$ +STRICT +LANGUAGE plpgsql IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.babelfish_conv_string_to_datetime(IN p_datatype TEXT, + IN p_datetimestring TEXT, + IN p_style NUMERIC DEFAULT 0) +RETURNS TIMESTAMP WITHOUT TIME ZONE +AS +$BODY$ +DECLARE + v_day VARCHAR COLLATE "C"; + v_year VARCHAR COLLATE "C"; + v_month VARCHAR COLLATE "C"; + v_style SMALLINT; + v_scale SMALLINT; + v_hours VARCHAR COLLATE "C"; + v_hijridate DATE; + v_minutes VARCHAR COLLATE "C"; + v_seconds VARCHAR COLLATE "C"; + v_fseconds VARCHAR COLLATE "C"; + v_datatype VARCHAR COLLATE "C"; + v_timepart VARCHAR COLLATE "C"; + v_leftpart VARCHAR COLLATE "C"; + v_middlepart VARCHAR COLLATE "C"; + v_rightpart VARCHAR COLLATE "C"; + v_datestring VARCHAR COLLATE "C"; + v_err_message VARCHAR COLLATE "C"; + v_date_format VARCHAR COLLATE "C"; + v_res_datatype VARCHAR COLLATE "C"; + v_datetimestring VARCHAR COLLATE "C"; + v_datatype_groups TEXT[]; + v_regmatch_groups TEXT[]; + v_lang_metadata_json JSONB; + v_compmonth_regexp VARCHAR COLLATE "C"; + v_resdatetime TIMESTAMP(6) WITHOUT TIME ZONE; + CONVERSION_LANG CONSTANT VARCHAR COLLATE "C" := ''; + DATE_FORMAT CONSTANT VARCHAR COLLATE "C" := ''; + DAYMM_REGEXP CONSTANT VARCHAR COLLATE "C" := '(\d{1,2})'; + FULLYEAR_REGEXP CONSTANT VARCHAR COLLATE "C" := '(\d{4})'; + SHORTYEAR_REGEXP CONSTANT VARCHAR COLLATE "C" := '(\d{1,2})'; + COMPYEAR_REGEXP CONSTANT VARCHAR COLLATE "C" := '(\d{1,2}|\d{4})'; + AMPM_REGEXP CONSTANT VARCHAR COLLATE "C" := '(?:[AP]M)'; + MASKSEP_REGEXP CONSTANT VARCHAR COLLATE "C" := '(?:\.|-|/)'; + TIMEUNIT_REGEXP CONSTANT VARCHAR COLLATE "C" := '\s*\d{1,2}\s*'; + FRACTSECS_REGEXP CONSTANT VARCHAR COLLATE "C" := '\s*\d{1,9}\s*'; + DATATYPE_REGEXP CONSTANT VARCHAR COLLATE "C" := '^(DATETIME|SMALLDATETIME|DATETIME2)\s*(?:\()?\s*((?:-)?\d+)?\s*(?:\))?$'; + DIGITREPRESENT_REGEXP CONSTANT VARCHAR COLLATE "C" := '^\-?\d+\.?(?:\d+)?$'; + HHMMSSFS_PART_REGEXP CONSTANT VARCHAR COLLATE "C" := concat(TIMEUNIT_REGEXP, AMPM_REGEXP, '|', + TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, AMPM_REGEXP, '?|', + TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '\.', FRACTSECS_REGEXP, AMPM_REGEXP, '?|', + TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, AMPM_REGEXP, '?|', + TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '(?:\.|\:)', FRACTSECS_REGEXP, AMPM_REGEXP, '?'); + HHMMSSFS_DOT_PART_REGEXP CONSTANT VARCHAR COLLATE "C" := concat(TIMEUNIT_REGEXP, AMPM_REGEXP, '|', + TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, AMPM_REGEXP, '?|', + TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '\.', FRACTSECS_REGEXP, AMPM_REGEXP, '?|', + TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, AMPM_REGEXP, '?|', + TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '\:', TIMEUNIT_REGEXP, '(?:\.)', FRACTSECS_REGEXP, AMPM_REGEXP, '?'); + HHMMSSFS_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^(', HHMMSSFS_PART_REGEXP, ')$'); + DEFMASK1_0_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^(', HHMMSSFS_PART_REGEXP, ')?\s*', + MASKSEP_REGEXP, '*\s*($comp_month$)\s*', DAYMM_REGEXP, '\s+', COMPYEAR_REGEXP, + '\s*(', HHMMSSFS_PART_REGEXP, ')?$'); + DEFMASK1_1_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^', MASKSEP_REGEXP, '?\s*($comp_month$)\s*', DAYMM_REGEXP, '\s+', COMPYEAR_REGEXP, '$'); + DEFMASK1_2_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^', MASKSEP_REGEXP, '\s*($comp_month$)\s*', DAYMM_REGEXP, '\s+', COMPYEAR_REGEXP, '$'); + DEFMASK2_0_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^(', HHMMSSFS_PART_REGEXP, ')?\s*', + DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '*\s*($comp_month$)\s*', COMPYEAR_REGEXP, + '\s*(', HHMMSSFS_PART_REGEXP, ')?$'); + DEFMASK2_1_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '?\s*($comp_month$)\s*', COMPYEAR_REGEXP, '$'); + DEFMASK2_2_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*($comp_month$)\s*', COMPYEAR_REGEXP, '$'); + DEFMASK3_0_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^(', HHMMSSFS_PART_REGEXP, ')?\s*', + FULLYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '*\s*($comp_month$)\s*', DAYMM_REGEXP, + '\s*(', HHMMSSFS_PART_REGEXP, ')?$'); + DEFMASK3_1_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^', FULLYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '?\s*($comp_month$)\s*', DAYMM_REGEXP, '$'); + DEFMASK3_2_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^', FULLYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '\s*($comp_month$)\s*', DAYMM_REGEXP, '$'); + DEFMASK4_0_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^(', HHMMSSFS_PART_REGEXP, ')?\s*', + FULLYEAR_REGEXP, '\s+', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '*\s*($comp_month$)', + '\s*(', HHMMSSFS_PART_REGEXP, ')?$'); + DEFMASK4_1_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^', FULLYEAR_REGEXP, '\s+', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '?\s*($comp_month$)$'); + DEFMASK4_2_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^', FULLYEAR_REGEXP, '\s+', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*($comp_month$)$'); + DEFMASK5_0_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^(', HHMMSSFS_PART_REGEXP, ')?\s*', + DAYMM_REGEXP, '\s+', COMPYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '*\s*($comp_month$)', + '\s*(', HHMMSSFS_PART_REGEXP, ')?$'); + DEFMASK5_1_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^', DAYMM_REGEXP, '\s+', COMPYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '?\s*($comp_month$)$'); + DEFMASK5_2_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^', DAYMM_REGEXP, '\s+', COMPYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '\s*($comp_month$)$'); + DEFMASK6_0_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^(', HHMMSSFS_PART_REGEXP, ')?\s*', + MASKSEP_REGEXP, '*\s*($comp_month$)\s*', FULLYEAR_REGEXP, '\s+', DAYMM_REGEXP, + '\s*(', HHMMSSFS_PART_REGEXP, ')?$'); + DEFMASK6_1_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^', MASKSEP_REGEXP, '?\s*($comp_month$)\s*', FULLYEAR_REGEXP, '\s+', DAYMM_REGEXP, '$'); + DEFMASK6_2_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^', MASKSEP_REGEXP, '\s*($comp_month$)\s*', FULLYEAR_REGEXP, '\s+', DAYMM_REGEXP, '$'); + DEFMASK7_0_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^(', HHMMSSFS_PART_REGEXP, ')?\s*', + MASKSEP_REGEXP, '*\s*($comp_month$)\s*', DAYMM_REGEXP, '\s*,\s*', COMPYEAR_REGEXP, + '\s*(', HHMMSSFS_PART_REGEXP, ')?$'); + DEFMASK7_1_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^', MASKSEP_REGEXP, '?\s*($comp_month$)\s*', DAYMM_REGEXP, '\s*,\s*', COMPYEAR_REGEXP, '$'); + DEFMASK7_2_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^', MASKSEP_REGEXP, '\s*($comp_month$)\s*', DAYMM_REGEXP, '\s*,\s*', COMPYEAR_REGEXP, '$'); + DEFMASK8_0_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^(', HHMMSSFS_PART_REGEXP, ')?\s*', + FULLYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '*\s*($comp_month$)', + '\s*(', HHMMSSFS_PART_REGEXP, ')?$'); + DEFMASK8_1_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^', FULLYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '?\s*($comp_month$)$'); + DEFMASK8_2_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^', FULLYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '\s*($comp_month$)$'); + DEFMASK9_0_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^(', HHMMSSFS_PART_REGEXP, ')?\s*', + MASKSEP_REGEXP, '*\s*($comp_month$)\s*', FULLYEAR_REGEXP, + '\s*(', HHMMSSFS_PART_REGEXP, ')?$'); + DEFMASK9_1_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^', MASKSEP_REGEXP, '?\s*($comp_month$)\s*', FULLYEAR_REGEXP, '$'); + DEFMASK9_2_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^', MASKSEP_REGEXP, '\s*($comp_month$)\s*', FULLYEAR_REGEXP, '$'); + DEFMASK10_0_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^(', HHMMSSFS_PART_REGEXP, ')?\s*', + DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*($comp_month$)\s*', MASKSEP_REGEXP, '\s*', COMPYEAR_REGEXP, + '\s*(', HHMMSSFS_PART_REGEXP, ')?$'); + DEFMASK10_1_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*($comp_month$)\s*', MASKSEP_REGEXP, '\s*', COMPYEAR_REGEXP, '$'); + DOT_SLASH_DASH_COMPYEAR1_0_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^(', HHMMSSFS_PART_REGEXP, ')?\s*', + DAYMM_REGEXP, '\s*(?:\.|/|-)\s*', DAYMM_REGEXP, '\s*(?:\.|/|-)\s*', COMPYEAR_REGEXP, + '\s*(', HHMMSSFS_PART_REGEXP, ')?$'); + DOT_SLASH_DASH_COMPYEAR1_1_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*', COMPYEAR_REGEXP, '$'); + DOT_SLASH_DASH_SHORTYEAR_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*', SHORTYEAR_REGEXP, '$'); + DOT_SLASH_DASH_FULLYEAR1_0_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^(', HHMMSSFS_PART_REGEXP, ')?\s*', + DAYMM_REGEXP, '\s*(?:\.|/|-)\s*', DAYMM_REGEXP, '\s*(?:\.|/|-)\s*', FULLYEAR_REGEXP, + '\s*(', HHMMSSFS_PART_REGEXP, ')?$'); + DOT_SLASH_DASH_FULLYEAR1_1_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*', FULLYEAR_REGEXP, '$'); + FULLYEAR_DOT_SLASH_DASH1_0_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^(', HHMMSSFS_PART_REGEXP, ')?\s*', + FULLYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '\s*', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*', DAYMM_REGEXP, + '\s*(', HHMMSSFS_PART_REGEXP, ')?$'); + FULLYEAR_DOT_SLASH_DASH1_1_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^', FULLYEAR_REGEXP, '\s*', MASKSEP_REGEXP, '\s*', DAYMM_REGEXP, '\s*', MASKSEP_REGEXP, '\s*', DAYMM_REGEXP, '$'); + SHORT_DIGITMASK1_0_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^(', HHMMSSFS_PART_REGEXP, ')?\s*\d{6}\s*(', HHMMSSFS_PART_REGEXP, ')?$'); + FULL_DIGITMASK1_0_REGEXP CONSTANT VARCHAR COLLATE "C" := concat('^(', HHMMSSFS_PART_REGEXP, ')?\s*\d{8}\s*(', HHMMSSFS_PART_REGEXP, ')?$'); +BEGIN + v_datatype := trim(p_datatype); + v_datetimestring := upper(trim(p_datetimestring)); + v_style := floor(p_style)::SMALLINT; + + v_datatype_groups := regexp_matches(v_datatype, DATATYPE_REGEXP, 'gi'); + + v_res_datatype := upper(v_datatype_groups[1]); + v_scale := v_datatype_groups[2]::SMALLINT; + + IF (v_res_datatype IS NULL) THEN + RAISE datatype_mismatch; + ELSIF (v_res_datatype <> 'DATETIME2' AND v_scale IS NOT NULL) + THEN + RAISE invalid_indicator_parameter_value; + ELSIF (coalesce(v_scale, 0) NOT BETWEEN 0 AND 7) + THEN + RAISE interval_field_overflow; + ELSIF (v_scale IS NULL) THEN + v_scale := 7; + END IF; + + IF (scale(p_style) > 0) THEN + RAISE most_specific_type_mismatch; + ELSIF (NOT ((v_style BETWEEN 0 AND 14) OR + (v_style BETWEEN 20 AND 25) OR + (v_style BETWEEN 100 AND 114) OR + (v_style IN (120, 121, 126, 127, 130, 131))) AND + v_res_datatype = 'DATETIME2') + THEN + RAISE invalid_parameter_value; + END IF; + + v_timepart := trim(substring(v_datetimestring, HHMMSSFS_PART_REGEXP)); + v_datestring := trim(regexp_replace(v_datetimestring, HHMMSSFS_PART_REGEXP, '', 'gi')); + + BEGIN + v_lang_metadata_json := sys.babelfish_get_lang_metadata_json(CONVERSION_LANG); + EXCEPTION + WHEN OTHERS THEN + RAISE invalid_escape_sequence; + END; + + v_date_format := coalesce(nullif(DATE_FORMAT, ''), v_lang_metadata_json ->> 'date_format'); + + v_compmonth_regexp := array_to_string(array_cat(ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'months_shortnames')), + ARRAY(SELECT jsonb_array_elements_text(v_lang_metadata_json -> 'months_names'))), '|'); + + IF (v_datetimestring ~* pg_catalog.replace(DEFMASK1_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* pg_catalog.replace(DEFMASK2_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* pg_catalog.replace(DEFMASK3_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* pg_catalog.replace(DEFMASK4_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* pg_catalog.replace(DEFMASK5_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* pg_catalog.replace(DEFMASK6_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* pg_catalog.replace(DEFMASK7_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* pg_catalog.replace(DEFMASK8_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* pg_catalog.replace(DEFMASK9_0_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datetimestring ~* pg_catalog.replace(DEFMASK10_0_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + IF ((v_style IN (127, 130, 131) AND v_res_datatype IN ('DATETIME', 'SMALLDATETIME')) OR + (v_style IN (130, 131) AND v_res_datatype = 'DATETIME2')) + THEN + RAISE invalid_datetime_format; + END IF; + + IF ((v_datestring ~* pg_catalog.replace(DEFMASK1_2_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datestring ~* pg_catalog.replace(DEFMASK2_2_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datestring ~* pg_catalog.replace(DEFMASK3_2_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datestring ~* pg_catalog.replace(DEFMASK4_2_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datestring ~* pg_catalog.replace(DEFMASK5_2_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datestring ~* pg_catalog.replace(DEFMASK6_2_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datestring ~* pg_catalog.replace(DEFMASK7_2_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datestring ~* pg_catalog.replace(DEFMASK8_2_REGEXP, '$comp_month$', v_compmonth_regexp) OR + v_datestring ~* pg_catalog.replace(DEFMASK9_2_REGEXP, '$comp_month$', v_compmonth_regexp)) AND + v_res_datatype = 'DATETIME2') + THEN + RAISE invalid_datetime_format; + END IF; + + IF (v_datestring ~* pg_catalog.replace(DEFMASK1_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, pg_catalog.replace(DEFMASK1_1_REGEXP, '$comp_month$', v_compmonth_regexp), 'gi'); + v_day := v_regmatch_groups[2]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[1], v_lang_metadata_json); + v_year := sys.babelfish_get_full_year(v_regmatch_groups[3]); + + ELSIF (v_datestring ~* pg_catalog.replace(DEFMASK2_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, pg_catalog.replace(DEFMASK2_1_REGEXP, '$comp_month$', v_compmonth_regexp), 'gi'); + v_day := v_regmatch_groups[1]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + v_year := sys.babelfish_get_full_year(v_regmatch_groups[3]); + + ELSIF (v_datestring ~* pg_catalog.replace(DEFMASK3_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, pg_catalog.replace(DEFMASK3_1_REGEXP, '$comp_month$', v_compmonth_regexp), 'gi'); + v_day := v_regmatch_groups[3]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + v_year := v_regmatch_groups[1]; + + ELSIF (v_datestring ~* pg_catalog.replace(DEFMASK4_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, pg_catalog.replace(DEFMASK4_1_REGEXP, '$comp_month$', v_compmonth_regexp), 'gi'); + v_day := v_regmatch_groups[2]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[3], v_lang_metadata_json); + v_year := v_regmatch_groups[1]; + + ELSIF (v_datestring ~* pg_catalog.replace(DEFMASK5_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, pg_catalog.replace(DEFMASK5_1_REGEXP, '$comp_month$', v_compmonth_regexp), 'gi'); + v_day := v_regmatch_groups[1]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[3], v_lang_metadata_json); + v_year := sys.babelfish_get_full_year(v_regmatch_groups[2]); + + ELSIF (v_datestring ~* pg_catalog.replace(DEFMASK6_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, pg_catalog.replace(DEFMASK6_1_REGEXP, '$comp_month$', v_compmonth_regexp), 'gi'); + v_day := v_regmatch_groups[3]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[1], v_lang_metadata_json); + v_year := v_regmatch_groups[2]; + + ELSIF (v_datestring ~* pg_catalog.replace(DEFMASK7_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, pg_catalog.replace(DEFMASK7_1_REGEXP, '$comp_month$', v_compmonth_regexp), 'gi'); + v_day := v_regmatch_groups[2]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[1], v_lang_metadata_json); + v_year := sys.babelfish_get_full_year(v_regmatch_groups[3]); + + ELSIF (v_datestring ~* pg_catalog.replace(DEFMASK8_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, pg_catalog.replace(DEFMASK8_1_REGEXP, '$comp_month$', v_compmonth_regexp), 'gi'); + v_day := '01'; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + v_year := v_regmatch_groups[1]; + + ELSIF (v_datestring ~* pg_catalog.replace(DEFMASK9_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, pg_catalog.replace(DEFMASK9_1_REGEXP, '$comp_month$', v_compmonth_regexp), 'gi'); + v_day := '01'; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[1], v_lang_metadata_json); + v_year := v_regmatch_groups[2]; + + ELSIF (v_datestring ~* pg_catalog.replace(DEFMASK10_1_REGEXP, '$comp_month$', v_compmonth_regexp)) + THEN + v_regmatch_groups := regexp_matches(v_datestring, pg_catalog.replace(DEFMASK10_1_REGEXP, '$comp_month$', v_compmonth_regexp), 'gi'); + v_day := v_regmatch_groups[1]; + v_month := sys.babelfish_get_monthnum_by_name(v_regmatch_groups[2], v_lang_metadata_json); + v_year := sys.babelfish_get_full_year(v_regmatch_groups[3]); + ELSE + RAISE invalid_character_value_for_cast; + END IF; + ELSIF (v_datetimestring ~* DOT_SLASH_DASH_COMPYEAR1_0_REGEXP) + THEN + IF (v_style IN (6, 7, 8, 9, 12, 13, 14, 24, 100, 106, 107, 108, 109, 112, 113, 114, 130) AND + v_res_datatype = 'DATETIME2') + THEN + RAISE invalid_regular_expression; + END IF; + + v_regmatch_groups := regexp_matches(v_datestring, DOT_SLASH_DASH_COMPYEAR1_1_REGEXP, 'gi'); + v_leftpart := v_regmatch_groups[1]; + v_middlepart := v_regmatch_groups[2]; + v_rightpart := v_regmatch_groups[3]; + + IF (v_datestring ~* DOT_SLASH_DASH_SHORTYEAR_REGEXP) + THEN + IF ((v_style NOT IN (0, 1, 2, 3, 4, 5, 10, 11) AND v_res_datatype IN ('DATETIME', 'SMALLDATETIME')) OR + (v_style NOT IN (0, 1, 2, 3, 4, 5, 10, 11, 12) AND v_res_datatype = 'DATETIME2')) + THEN + RAISE invalid_datetime_format; + END IF; + + IF ((v_style IN (1, 10) AND v_date_format <> 'MDY' AND v_res_datatype IN ('DATETIME', 'SMALLDATETIME')) OR + (v_style IN (0, 1, 10) AND v_date_format NOT IN ('DMY', 'DYM', 'MYD', 'YMD', 'YDM') AND v_res_datatype IN ('DATETIME', 'SMALLDATETIME')) OR + (v_style IN (0, 1, 10, 22) AND v_date_format NOT IN ('DMY', 'DYM', 'MYD', 'YMD', 'YDM') AND v_res_datatype = 'DATETIME2') OR + (v_style IN (1, 10, 22) AND v_date_format IN ('DMY', 'DYM', 'MYD', 'YMD', 'YDM') AND v_res_datatype = 'DATETIME2')) + THEN + v_day := v_middlepart; + v_month := v_leftpart; + v_year := sys.babelfish_get_full_year(v_rightpart); + + ELSIF ((v_style IN (2, 11) AND v_date_format <> 'YMD') OR + (v_style IN (0, 2, 11) AND v_date_format = 'YMD')) + THEN + v_day := v_rightpart; + v_month := v_middlepart; + v_year := sys.babelfish_get_full_year(v_leftpart); + + ELSIF ((v_style IN (3, 4, 5) AND v_date_format <> 'DMY') OR + (v_style IN (0, 3, 4, 5) AND v_date_format = 'DMY')) + THEN + v_day := v_leftpart; + v_month := v_middlepart; + v_year := sys.babelfish_get_full_year(v_rightpart); + + ELSIF (v_style = 0 AND v_date_format = 'DYM') + THEN + v_day = v_leftpart; + v_month = v_rightpart; + v_year = sys.babelfish_get_full_year(v_middlepart); + + ELSIF (v_style = 0 AND v_date_format = 'MYD') + THEN + v_day := v_rightpart; + v_month := v_leftpart; + v_year = sys.babelfish_get_full_year(v_middlepart); + + ELSIF (v_style = 0 AND v_date_format = 'YDM') + THEN + IF (v_res_datatype = 'DATETIME2') THEN + RAISE character_not_in_repertoire; + END IF; + + v_day := v_middlepart; + v_month := v_rightpart; + v_year := sys.babelfish_get_full_year(v_leftpart); + ELSE + RAISE invalid_character_value_for_cast; + END IF; + ELSIF (v_datestring ~* DOT_SLASH_DASH_FULLYEAR1_1_REGEXP) + THEN + IF (v_style NOT IN (0, 20, 21, 101, 102, 103, 104, 105, 110, 111, 120, 121, 130, 131) AND + v_res_datatype IN ('DATETIME', 'SMALLDATETIME')) + THEN + RAISE invalid_datetime_format; + ELSIF (v_style IN (130, 131) AND v_res_datatype = 'SMALLDATETIME') THEN + RAISE invalid_character_value_for_cast; + END IF; + + v_year := v_rightpart; + IF (v_leftpart::SMALLINT <= 12) + THEN + IF ((v_style IN (103, 104, 105, 130, 131) AND v_date_format NOT IN ('DMY', 'DYM', 'YDM')) OR + (v_style IN (0, 103, 104, 105, 130, 131) AND ((v_date_format = 'DMY' AND v_res_datatype = 'DATETIME2') OR + (v_date_format IN ('DMY', 'DYM', 'YDM') AND v_res_datatype <> 'DATETIME2'))) OR + (v_style IN (103, 104, 105, 130, 131) AND v_date_format IN ('DMY', 'DYM', 'YDM') AND v_res_datatype = 'DATETIME2')) + THEN + v_day := v_leftpart; + v_month := v_middlepart; + + ELSIF ((v_style IN (20, 21, 101, 102, 110, 111, 120, 121) AND v_date_format IN ('DMY', 'DYM', 'YDM') AND v_res_datatype IN ('DATETIME', 'SMALLDATETIME')) OR + (v_style IN (0, 20, 21, 101, 102, 110, 111, 120, 121) AND v_date_format NOT IN ('DMY', 'DYM', 'YDM') AND v_res_datatype IN ('DATETIME', 'SMALLDATETIME')) OR + (v_style IN (101, 110) AND v_date_format IN ('DMY', 'DYM', 'MYD', 'YDM') AND v_res_datatype = 'DATETIME2') OR + (v_style IN (0, 101, 110) AND v_date_format NOT IN ('DMY', 'DYM', 'MYD', 'YDM') AND v_res_datatype = 'DATETIME2')) + THEN + v_day := v_middlepart; + v_month := v_leftpart; + END IF; + ELSE + IF ((v_style IN (103, 104, 105, 130, 131) AND v_date_format NOT IN ('DMY', 'DYM', 'YDM')) OR + (v_style IN (0, 103, 104, 105, 130, 131) AND ((v_date_format = 'DMY' AND v_res_datatype = 'DATETIME2') OR + (v_date_format IN ('DMY', 'DYM', 'YDM') AND v_res_datatype <> 'DATETIME2'))) OR + (v_style IN (103, 104, 105, 130, 131) AND v_date_format IN ('DMY', 'DYM', 'YDM') AND v_res_datatype = 'DATETIME2')) + THEN + v_day := v_leftpart; + v_month := v_middlepart; + ELSE + IF (v_res_datatype = 'DATETIME2') THEN + RAISE invalid_datetime_format; + END IF; + + RAISE invalid_character_value_for_cast; + END IF; + END IF; + END IF; + ELSIF (v_datetimestring ~* FULLYEAR_DOT_SLASH_DASH1_0_REGEXP) + THEN + IF (v_style NOT IN (0, 20, 21, 101, 102, 103, 104, 105, 110, 111, 120, 121, 130, 131) AND + v_res_datatype IN ('DATETIME', 'SMALLDATETIME')) + THEN + RAISE invalid_datetime_format; + ELSIF (v_style IN (6, 7, 8, 9, 12, 13, 14, 24, 100, 106, 107, 108, 109, 112, 113, 114, 130) AND + v_res_datatype = 'DATETIME2') + THEN + RAISE invalid_regular_expression; + ELSIF (v_style IN (130, 131) AND v_res_datatype = 'SMALLDATETIME') + THEN + RAISE invalid_character_value_for_cast; + END IF; + + v_regmatch_groups := regexp_matches(v_datestring, FULLYEAR_DOT_SLASH_DASH1_1_REGEXP, 'gi'); + v_year := v_regmatch_groups[1]; + v_middlepart := v_regmatch_groups[2]; + v_rightpart := v_regmatch_groups[3]; + + IF ((v_res_datatype IN ('DATETIME', 'SMALLDATETIME') AND v_rightpart::SMALLINT <= 12) OR v_res_datatype = 'DATETIME2') + THEN + IF ((v_style IN (20, 21, 101, 102, 110, 111, 120, 121) AND v_date_format IN ('DMY', 'DYM', 'YDM') AND v_res_datatype <> 'DATETIME2') OR + (v_style IN (0, 20, 21, 101, 102, 110, 111, 120, 121) AND v_date_format NOT IN ('DMY', 'DYM', 'YDM') AND v_res_datatype <> 'DATETIME2') OR + (v_style IN (0, 20, 21, 23, 25, 101, 102, 110, 111, 120, 121, 126, 127) AND v_res_datatype = 'DATETIME2')) + THEN + v_day := v_rightpart; + v_month := v_middlepart; + + ELSIF ((v_style IN (103, 104, 105, 130, 131) AND v_date_format NOT IN ('DMY', 'DYM', 'YDM')) OR + v_style IN (0, 103, 104, 105, 130, 131) AND v_date_format IN ('DMY', 'DYM', 'YDM')) + THEN + v_day := v_middlepart; + v_month := v_rightpart; + END IF; + ELSIF (v_res_datatype IN ('DATETIME', 'SMALLDATETIME') AND v_rightpart::SMALLINT > 12) + THEN + IF ((v_style IN (20, 21, 101, 102, 110, 111, 120, 121) AND v_date_format IN ('DMY', 'DYM', 'YDM')) OR + (v_style IN (0, 20, 21, 101, 102, 110, 111, 120, 121) AND v_date_format NOT IN ('DMY', 'DYM', 'YDM'))) + THEN + v_day := v_rightpart; + v_month := v_middlepart; + + ELSIF ((v_style IN (103, 104, 105, 130, 131) AND v_date_format NOT IN ('DMY', 'DYM', 'YDM')) OR + (v_style IN (0, 103, 104, 105, 130, 131) AND v_date_format IN ('DMY', 'DYM', 'YDM'))) + THEN + RAISE invalid_character_value_for_cast; + END IF; + END IF; + ELSIF (v_datetimestring ~* SHORT_DIGITMASK1_0_REGEXP OR + v_datetimestring ~* FULL_DIGITMASK1_0_REGEXP) + THEN + IF (v_style = 127 AND v_res_datatype <> 'DATETIME2') + THEN + RAISE invalid_datetime_format; + ELSIF (v_style IN (130, 131) AND v_res_datatype = 'SMALLDATETIME') + THEN + RAISE invalid_character_value_for_cast; + END IF; + + IF (v_datestring ~* '^\d{6}$') + THEN + v_day := substr(v_datestring, 5, 2); + v_month := substr(v_datestring, 3, 2); + v_year := sys.babelfish_get_full_year(substr(v_datestring, 1, 2)); + + ELSIF (v_datestring ~* '^\d{8}$') + THEN + v_day := substr(v_datestring, 7, 2); + v_month := substr(v_datestring, 5, 2); + v_year := substr(v_datestring, 1, 4); + END IF; + ELSIF (v_datetimestring ~* HHMMSSFS_REGEXP) + THEN + v_day := '01'; + v_month := '01'; + v_year := '1900'; + ELSIF (v_datetimestring ~* DIGITREPRESENT_REGEXP) + THEN + v_resdatetime = CAST('1900-01-01 00:00:00.0' AS sys.DATETIME) + v_datetimestring::NUMERIC; + RETURN v_resdatetime; + ELSE + RAISE invalid_datetime_format; + END IF; + + IF (((v_datetimestring ~* HHMMSSFS_PART_REGEXP AND v_res_datatype = 'DATETIME2') OR + (v_datetimestring ~* SHORT_DIGITMASK1_0_REGEXP OR v_datetimestring ~* FULL_DIGITMASK1_0_REGEXP OR + v_datetimestring ~* FULLYEAR_DOT_SLASH_DASH1_0_REGEXP OR v_datetimestring ~* DOT_SLASH_DASH_FULLYEAR1_0_REGEXP)) AND + v_style IN (130, 131)) + THEN + v_hijridate := sys.babelfish_conv_hijri_to_greg(v_day, v_month, v_year) - 1; + v_day = to_char(v_hijridate, 'DD'); + v_month = to_char(v_hijridate, 'MM'); + v_year = to_char(v_hijridate, 'YYYY'); + END IF; + + v_hours := coalesce(sys.babelfish_get_timeunit_from_string(v_timepart, 'HOURS'), '0'); + v_minutes := coalesce(sys.babelfish_get_timeunit_from_string(v_timepart, 'MINUTES'), '0'); + v_seconds := coalesce(sys.babelfish_get_timeunit_from_string(v_timepart, 'SECONDS'), '0'); + v_fseconds := coalesce(sys.babelfish_get_timeunit_from_string(v_timepart, 'FRACTSECONDS'), '0'); + + IF ((v_res_datatype IN ('DATETIME', 'SMALLDATETIME') OR + (v_res_datatype = 'DATETIME2' AND v_timepart !~* HHMMSSFS_DOT_PART_REGEXP)) AND + char_length(v_fseconds) > 3) + THEN + RAISE invalid_datetime_format; + END IF; + + BEGIN + IF (v_res_datatype IN ('DATETIME', 'SMALLDATETIME')) + THEN + v_resdatetime := sys.datetimefromparts(v_year, v_month, v_day, + v_hours, v_minutes, v_seconds, + rpad(v_fseconds, 3, '0')); + IF (v_res_datatype = 'SMALLDATETIME' AND + to_char(v_resdatetime, 'SS') <> '00') + THEN + IF (to_char(v_resdatetime, 'SS')::SMALLINT >= 30) THEN + v_resdatetime := v_resdatetime + INTERVAL '1 minute'; + END IF; + + v_resdatetime := to_timestamp(to_char(v_resdatetime, 'DD.MM.YYYY.HH24.MI'), 'DD.MM.YYYY.HH24.MI'); + END IF; + ELSIF (v_res_datatype = 'DATETIME2') + THEN + v_fseconds := sys.babelfish_get_microsecs_from_fractsecs(v_fseconds, v_scale); + v_seconds := concat_ws('.', v_seconds, v_fseconds); + v_resdatetime := make_timestamp(v_year::SMALLINT, v_month::SMALLINT, v_day::SMALLINT, + v_hours::SMALLINT, v_minutes::SMALLINT, v_seconds::NUMERIC); + END IF; + EXCEPTION + WHEN datetime_field_overflow THEN + RAISE invalid_datetime_format; + WHEN OTHERS THEN + GET STACKED DIAGNOSTICS v_err_message = MESSAGE_TEXT; + + IF (v_err_message ~* 'Cannot construct data type') THEN + RAISE invalid_character_value_for_cast; + END IF; + END; + + RETURN v_resdatetime; +EXCEPTION + WHEN most_specific_type_mismatch THEN + RAISE USING MESSAGE := 'Argument data type NUMERIC is invalid for argument 3 of conv_string_to_datetime function.', + DETAIL := 'Use of incorrect "style" parameter value during conversion process.', + HINT := 'Change "style" parameter to the proper value and try again.'; + + WHEN invalid_parameter_value THEN + RAISE USING MESSAGE := pg_catalog.format('The style %s is not supported for conversions from VARCHAR to %s.', v_style, v_res_datatype), + DETAIL := 'Use of incorrect "style" parameter value during conversion process.', + HINT := 'Change "style" parameter to the proper value and try again.'; + + WHEN invalid_regular_expression THEN + RAISE USING MESSAGE := pg_catalog.format('The input character string doesn''t follow style %s.', v_style), + DETAIL := 'Selected "style" param value isn''t valid for conversion of passed character string.', + HINT := 'Either change the input character string or use a different style.'; + + WHEN datatype_mismatch THEN + RAISE USING MESSAGE := 'Data type should be one of these values: ''DATETIME'', ''SMALLDATETIME'', ''DATETIME2''/''DATETIME2(n)''.', + DETAIL := 'Use of incorrect "datatype" parameter value during conversion process.', + HINT := 'Change "datatype" parameter to the proper value and try again.'; + + WHEN invalid_indicator_parameter_value THEN + RAISE USING MESSAGE := pg_catalog.format('Invalid attributes specified for data type %s.', v_res_datatype), + DETAIL := 'Use of incorrect scale value, which is not corresponding to specified data type.', + HINT := 'Change data type scale component or select different data type and try again.'; + + WHEN interval_field_overflow THEN + RAISE USING MESSAGE := pg_catalog.format('Specified scale %s is invalid.', v_scale), + DETAIL := 'Use of incorrect data type scale value during conversion process.', + HINT := 'Change scale component of data type parameter to be in range [0..7] and try again.'; + + WHEN invalid_datetime_format THEN + RAISE USING MESSAGE := CASE v_res_datatype + WHEN 'SMALLDATETIME' THEN 'Conversion failed when converting character string to SMALLDATETIME data type.' + ELSE 'Conversion failed when converting date and time from character string.' + END, + DETAIL := 'Incorrect using of pair of input parameters values during conversion process.', + HINT := 'Check the input parameters values, correct them if needed, and try again.'; + + WHEN invalid_character_value_for_cast THEN + RAISE USING MESSAGE := 'The conversion of a VARCHAR data type to a DATETIME data type resulted in an out-of-range value.', + DETAIL := 'Use of incorrect pair of input parameter values during conversion process.', + HINT := 'Check input parameter values, correct them if needed, and try again.'; + + WHEN character_not_in_repertoire THEN + RAISE USING MESSAGE := 'The YDM date format isn''t supported when converting from this string format to date and time.', + DETAIL := 'Use of incorrect DATE_FORMAT constant value regarding string format parameter during conversion process.', + HINT := 'Change DATE_FORMAT constant to one of these values: MDY|DMY|DYM, recompile function and try again.'; + + WHEN invalid_escape_sequence THEN + RAISE USING MESSAGE := pg_catalog.format('Invalid CONVERSION_LANG constant value - ''%s''. Allowed values are: ''English'', ''Deutsch'', etc.', + CONVERSION_LANG), + DETAIL := 'Compiled incorrect CONVERSION_LANG constant value in function''s body.', + HINT := 'Correct CONVERSION_LANG constant value in function''s body, recompile it and try again.'; + + WHEN invalid_text_representation THEN + GET STACKED DIAGNOSTICS v_err_message = MESSAGE_TEXT; + v_err_message := substring(lower(v_err_message), 'integer\:\s\"(.*)\"'); + + RAISE USING MESSAGE := pg_catalog.format('Error while trying to convert "%s" value to SMALLINT data type.', + v_err_message), + DETAIL := 'Passed argument value contains illegal characters.', + HINT := 'Correct passed argument value, remove all illegal characters.'; +END; +$BODY$ +LANGUAGE plpgsql +STABLE +RETURNS NULL ON NULL INPUT; + -- Mark babelfish_authid_user_ext as configuration table SELECT pg_catalog.pg_extension_config_dump('sys.babelfish_authid_user_ext', ''); diff --git a/test/JDBC/expected/TestDatetime-numeric-dateaddfunction-vu-prepare.out b/test/JDBC/expected/TestDatetime-numeric-dateaddfunction-vu-prepare.out new file mode 100644 index 0000000000..1745959ec9 --- /dev/null +++ b/test/JDBC/expected/TestDatetime-numeric-dateaddfunction-vu-prepare.out @@ -0,0 +1,319 @@ +CREATE VIEW Datetime_view3 +AS( + SELECT + CONVERT(DATETIME, CAST(2.5 as BIT)) as re1, + CONVERT(DATETIME, CAST(2.5 as DECIMAL))as re2, + CONVERT(DATETIME, CAST(2.5 as NUMERIC(30,8)))as re3, + CONVERT(DATETIME, CAST(2.5 as FLOAT))as re4, + CONVERT(DATETIME, CAST(2.5 as REAL))as re5, + CONVERT(DATETIME, CAST(2.5 as INT))as re6, + CONVERT(DATETIME, CAST(2.5 as BIGINT))as re7, + CONVERT(DATETIME, CAST(2.5 as SMALLINT))as re8, + CONVERT(DATETIME, CAST(2.5 as TINYINT))as re9, + CONVERT(DATETIME, CAST(2.5 as MONEY))as re10, + CONVERT(DATETIME, CAST(2.5 as SMALLMONEY))as re11, + CONVERT(DATETIME, CAST(-2.5 as BIT)) as re12, + CONVERT(DATETIME, CAST(-2.5 as DECIMAL))as re13, + CONVERT(DATETIME, CAST(-2.5 as NUMERIC(30,8)))as re14, + CONVERT(DATETIME, CAST(-2.5 as FLOAT))as re15, + CONVERT(DATETIME, CAST(-2.5 as REAL))as re16, + CONVERT(DATETIME, CAST(-2.5 as INT))as re17, + CONVERT(DATETIME, CAST(-2.5 as BIGINT))as re18, + CONVERT(DATETIME, CAST(-2.5 as SMALLINT))as re19, + CONVERT(DATETIME, CAST(-2.5 as MONEY))as re20, + CONVERT(DATETIME, CAST(-2.5 as SMALLMONEY))as re21, + CONVERT(DATETIME, NULL)as res22 +); +GO + +CREATE VIEW Datetime_view4 +AS( + SELECT + CONVERT(SMALLDATETIME, CAST(2.5 as BIT)) as re1, + CONVERT(SMALLDATETIME, CAST(2.5 as DECIMAL)) as re2, + CONVERT(SMALLDATETIME, CAST(2.5 as NUMERIC(30,8))) as re3, + CONVERT(SMALLDATETIME, CAST(2.5 as FLOAT)) as re4, + CONVERT(SMALLDATETIME, CAST(2.5 as REAL)) as re5, + CONVERT(SMALLDATETIME, CAST(2.5 as INT)) as re6, + CONVERT(SMALLDATETIME, CAST(2.5 as BIGINT)) as re7, + CONVERT(SMALLDATETIME, CAST(2.5 as SMALLINT)) as re8, + CONVERT(SMALLDATETIME, CAST(2.5 as TINYINT)) as re9, + CONVERT(SMALLDATETIME, CAST(2.5 as MONEY)) as re10, + CONVERT(SMALLDATETIME, CAST(2.5 as SMALLMONEY)) as re11, + CONVERT(SMALLDATETIME, CAST(-2.5 as BIT)) as re12, + CONVERT(SMALLDATETIME, NULL) as res13 +); +GO + +-- Should all fail +SELECT CONVERT(SMALLDATETIME, CAST(-2.5 as DECIMAL)) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + +SELECT CONVERT(SMALLDATETIME, CAST(-2.5 as NUMERIC(30,8))) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + +SELECT CONVERT(SMALLDATETIME, CAST(-2.5 as FLOAT)) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + +SELECT CONVERT(SMALLDATETIME, CAST(-2.5 as REAL)) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + +SELECT CONVERT(SMALLDATETIME, CAST(-2.5 as INT)) +GO +~~START~~ +smalldatetime +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + +SELECT CONVERT(SMALLDATETIME, CAST(-2.5 as BIGINT)) +GO +~~START~~ +smalldatetime +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + +SELECT CONVERT(SMALLDATETIME, CAST(-2.5 as SMALLINT)) +GO +~~START~~ +smalldatetime +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + +SELECT CONVERT(SMALLDATETIME, CAST(-2.5 as MONEY)) +GO +~~START~~ +smalldatetime +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + +SELECT CONVERT(SMALLDATETIME, CAST(-2.5 as SMALLMONEY)) +GO +~~START~~ +smalldatetime +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + + + +CREATE VIEW Datetime_view5 as ( + SELECT + DATEADD(minute, CAST(1 as DECIMAL), CAST(2.5 as DECIMAL)) as re1, + DATEADD(minute, CAST(1 as NUMERIC(30,8)), CAST(2.5 as NUMERIC(30,8))) as re2, + DATEADD(minute, CAST(1 as FLOAT), CAST(2.5 as FLOAT)) as re3, + DATEADD(minute, CAST(1 as REAL), CAST(2.5 as REAL)) as re4, + DATEADD(minute, CAST(1 as INT), CAST(2.5 as INT)) as re5, + DATEADD(minute, CAST(1 as BIGINT), CAST(2.5 as BIGINT)) as re6, + DATEADD(minute, CAST(1 as SMALLINT), CAST(2.5 as SMALLINT)) as re7, + DATEADD(minute, CAST(1 as TINYINT), CAST(2.5 as TINYINT)) as re8, + DATEADD(minute, CAST(1 as MONEY), CAST(2.5 as MONEY)) as re9, + DATEADD(minute, CAST(1 as SMALLMONEY), CAST(2.5 as SMALLMONEY)) as re10, + DATEADD(minute, CAST(-1 as DECIMAL), CAST(-2.5 as DECIMAL)) as re11, + DATEADD(minute, CAST(-1 as NUMERIC(30,8)), CAST(-2.5 as NUMERIC(30,8))) as re12, + DATEADD(minute, CAST(-1 as FLOAT), CAST(-2.5 as FLOAT)) as re13, + DATEADD(minute, CAST(-1 as REAL), CAST(-2.5 as REAL)) as re14, + DATEADD(minute, CAST(-1 as INT), CAST(-2.5 as INT)) as re15, + DATEADD(minute, CAST(-1 as BIGINT), CAST(-2.5 as BIGINT)) as re16, + DATEADD(minute, CAST(-1 as SMALLINT), CAST(-2.5 as SMALLINT)) as re17, + DATEADD(minute, CAST(-1 as MONEY), CAST(-2.5 as MONEY)) as re18, + DATEADD(minute, CAST(-1 as SMALLMONEY), CAST(-2.5 as SMALLMONEY)) as re19 +); +GO + +CREATE PROCEDURE Datetime_proc1 (@a DATETIME, @b BIT) AS +BEGIN + DECLARE @c DATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE SMALLDatetime_proc1 (@a SMALLDATETIME, @b BIT) AS +BEGIN + DECLARE @c SMALLDATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE VIEW dateadd_numeric_representation_helper_year_view AS +SELECT +dateadd_numeric_representation_helper('year',1,cast(1.5 as BIGINT)) AS BIT_INT, +dateadd_numeric_representation_helper('year',1,cast(1.5 as INT)) AS REG_INT, +dateadd_numeric_representation_helper('year',1,cast(1.5 as SMALLINT)) AS SMALL_INT, +dateadd_numeric_representation_helper('year',1,cast(1.5 as TINYINT)) AS TINY_INT, +dateadd_numeric_representation_helper('year',1,cast(1.5 as NUMERIC)) AS NUMERIC_REP, +dateadd_numeric_representation_helper('year',1,cast(1.5 as FLOAT)) AS FLOAT_REP, +dateadd_numeric_representation_helper('year',1,cast(1.5 as REAL)) AS REAL_REP, +dateadd_numeric_representation_helper('year',1,cast(1.5 as MONEY)) AS MONEY_REP, +dateadd_numeric_representation_helper('year',1,cast(1.5 as SMALLMONEY)) AS SMALLMONEY_REP +GO + +CREATE VIEW dateadd_numeric_representation_helper_quarter_view AS +SELECT +dateadd_numeric_representation_helper('quarter',1,cast(1.5 as BIGINT)) AS BIT_INT, +dateadd_numeric_representation_helper('quarter',1,cast(1.5 as INT)) AS REG_INT, +dateadd_numeric_representation_helper('quarter',1,cast(1.5 as SMALLINT)) AS SMALL_INT, +dateadd_numeric_representation_helper('quarter',1,cast(1.5 as TINYINT)) AS TINY_INT, +dateadd_numeric_representation_helper('quarter',1,cast(1.5 as NUMERIC)) AS NUMERIC_REP, +dateadd_numeric_representation_helper('quarter',1,cast(1.5 as FLOAT)) AS FLOAT_REP, +dateadd_numeric_representation_helper('quarter',1,cast(1.5 as REAL)) AS REAL_REP, +dateadd_numeric_representation_helper('quarter',1,cast(1.5 as MONEY)) AS MONEY_REP, +dateadd_numeric_representation_helper('quarter',1,cast(1.5 as SMALLMONEY)) AS SMALLMONEY_REP +GO + +CREATE VIEW dateadd_numeric_representation_helper_month_view AS +SELECT +dateadd_numeric_representation_helper('month',1,cast(1.5 as BIGINT)) AS BIT_INT, +dateadd_numeric_representation_helper('month',1,cast(1.5 as INT)) AS REG_INT, +dateadd_numeric_representation_helper('month',1,cast(1.5 as SMALLINT)) AS SMALL_INT, +dateadd_numeric_representation_helper('month',1,cast(1.5 as TINYINT)) AS TINY_INT, +dateadd_numeric_representation_helper('month',1,cast(1.5 as NUMERIC)) AS NUMERIC_REP, +dateadd_numeric_representation_helper('month',1,cast(1.5 as FLOAT)) AS FLOAT_REP, +dateadd_numeric_representation_helper('month',1,cast(1.5 as REAL)) AS REAL_REP, +dateadd_numeric_representation_helper('month',1,cast(1.5 as MONEY)) AS MONEY_REP, +dateadd_numeric_representation_helper('month',1,cast(1.5 as SMALLMONEY)) AS SMALLMONEY_REP +GO + +CREATE VIEW dateadd_numeric_representation_helper_dayofyear_view AS +SELECT +dateadd_numeric_representation_helper('dayofyear',1,cast(1.5 as BIGINT)) AS BIT_INT, +dateadd_numeric_representation_helper('dayofyear',1,cast(1.5 as INT)) AS REG_INT, +dateadd_numeric_representation_helper('dayofyear',1,cast(1.5 as SMALLINT)) AS SMALL_INT, +dateadd_numeric_representation_helper('dayofyear',1,cast(1.5 as TINYINT)) AS TINY_INT, +dateadd_numeric_representation_helper('dayofyear',1,cast(1.5 as NUMERIC)) AS NUMERIC_REP, +dateadd_numeric_representation_helper('dayofyear',1,cast(1.5 as FLOAT)) AS FLOAT_REP, +dateadd_numeric_representation_helper('dayofyear',1,cast(1.5 as REAL)) AS REAL_REP, +dateadd_numeric_representation_helper('dayofyear',1,cast(1.5 as MONEY)) AS MONEY_REP, +dateadd_numeric_representation_helper('dayofyear',1,cast(1.5 as SMALLMONEY)) AS SMALLMONEY_REP +GO + +CREATE VIEW dateadd_numeric_representation_helper_day_view AS +SELECT +dateadd_numeric_representation_helper('day',1,cast(1.5 as BIGINT)) AS BIT_INT, +dateadd_numeric_representation_helper('day',1,cast(1.5 as INT)) AS REG_INT, +dateadd_numeric_representation_helper('day',1,cast(1.5 as SMALLINT)) AS SMALL_INT, +dateadd_numeric_representation_helper('day',1,cast(1.5 as TINYINT)) AS TINY_INT, +dateadd_numeric_representation_helper('day',1,cast(1.5 as NUMERIC)) AS NUMERIC_REP, +dateadd_numeric_representation_helper('day',1,cast(1.5 as FLOAT)) AS FLOAT_REP, +dateadd_numeric_representation_helper('day',1,cast(1.5 as REAL)) AS REAL_REP, +dateadd_numeric_representation_helper('day',1,cast(1.5 as MONEY)) AS MONEY_REP, +dateadd_numeric_representation_helper('day',1,cast(1.5 as SMALLMONEY)) AS SMALLMONEY_REP +GO + +CREATE VIEW dateadd_numeric_representation_helper_week_view AS +SELECT +dateadd_numeric_representation_helper('week',1,cast(1.5 as BIGINT)) AS BIT_INT, +dateadd_numeric_representation_helper('week',1,cast(1.5 as INT)) AS REG_INT, +dateadd_numeric_representation_helper('week',1,cast(1.5 as SMALLINT)) AS SMALL_INT, +dateadd_numeric_representation_helper('week',1,cast(1.5 as TINYINT)) AS TINY_INT, +dateadd_numeric_representation_helper('week',1,cast(1.5 as NUMERIC)) AS NUMERIC_REP, +dateadd_numeric_representation_helper('week',1,cast(1.5 as FLOAT)) AS FLOAT_REP, +dateadd_numeric_representation_helper('week',1,cast(1.5 as REAL)) AS REAL_REP, +dateadd_numeric_representation_helper('week',1,cast(1.5 as MONEY)) AS MONEY_REP, +dateadd_numeric_representation_helper('week',1,cast(1.5 as SMALLMONEY)) AS SMALLMONEY_REP +GO + +CREATE VIEW dateadd_numeric_representation_helper_weekday_view AS +SELECT +dateadd_numeric_representation_helper('weekday',1,cast(1.5 as BIGINT)) AS BIT_INT, +dateadd_numeric_representation_helper('weekday',1,cast(1.5 as INT)) AS REG_INT, +dateadd_numeric_representation_helper('weekday',1,cast(1.5 as SMALLINT)) AS SMALL_INT, +dateadd_numeric_representation_helper('weekday',1,cast(1.5 as TINYINT)) AS TINY_INT, +dateadd_numeric_representation_helper('weekday',1,cast(1.5 as NUMERIC)) AS NUMERIC_REP, +dateadd_numeric_representation_helper('weekday',1,cast(1.5 as FLOAT)) AS FLOAT_REP, +dateadd_numeric_representation_helper('weekday',1,cast(1.5 as REAL)) AS REAL_REP, +dateadd_numeric_representation_helper('weekday',1,cast(1.5 as MONEY)) AS MONEY_REP, +dateadd_numeric_representation_helper('weekday',1,cast(1.5 as SMALLMONEY)) AS SMALLMONEY_REP +GO + +CREATE VIEW dateadd_numeric_representation_helper_hour_view AS +SELECT +dateadd_numeric_representation_helper('hour',1,cast(1.5 as BIGINT)) AS BIT_INT, +dateadd_numeric_representation_helper('hour',1,cast(1.5 as INT)) AS REG_INT, +dateadd_numeric_representation_helper('hour',1,cast(1.5 as SMALLINT)) AS SMALL_INT, +dateadd_numeric_representation_helper('hour',1,cast(1.5 as TINYINT)) AS TINY_INT, +dateadd_numeric_representation_helper('hour',1,cast(1.5 as NUMERIC)) AS NUMERIC_REP, +dateadd_numeric_representation_helper('hour',1,cast(1.5 as FLOAT)) AS FLOAT_REP, +dateadd_numeric_representation_helper('hour',1,cast(1.5 as REAL)) AS REAL_REP, +dateadd_numeric_representation_helper('hour',1,cast(1.5 as MONEY)) AS MONEY_REP, +dateadd_numeric_representation_helper('hour',1,cast(1.5 as SMALLMONEY)) AS SMALLMONEY_REP +GO + +CREATE VIEW dateadd_numeric_representation_helper_minute_view AS +SELECT +dateadd_numeric_representation_helper('minute',1,cast(1.5 as BIGINT)) AS BIT_INT, +dateadd_numeric_representation_helper('minute',1,cast(1.5 as INT)) AS REG_INT, +dateadd_numeric_representation_helper('minute',1,cast(1.5 as SMALLINT)) AS SMALL_INT, +dateadd_numeric_representation_helper('minute',1,cast(1.5 as TINYINT)) AS TINY_INT, +dateadd_numeric_representation_helper('minute',1,cast(1.5 as NUMERIC)) AS NUMERIC_REP, +dateadd_numeric_representation_helper('minute',1,cast(1.5 as FLOAT)) AS FLOAT_REP, +dateadd_numeric_representation_helper('minute',1,cast(1.5 as REAL)) AS REAL_REP, +dateadd_numeric_representation_helper('minute',1,cast(1.5 as MONEY)) AS MONEY_REP, +dateadd_numeric_representation_helper('minute',1,cast(1.5 as SMALLMONEY)) AS SMALLMONEY_REP +GO + +CREATE VIEW dateadd_numeric_representation_helper_second_view AS +SELECT +dateadd_numeric_representation_helper('second',1,cast(1.5 as BIGINT)) AS BIT_INT, +dateadd_numeric_representation_helper('second',1,cast(1.5 as INT)) AS REG_INT, +dateadd_numeric_representation_helper('second',1,cast(1.5 as SMALLINT)) AS SMALL_INT, +dateadd_numeric_representation_helper('second',1,cast(1.5 as TINYINT)) AS TINY_INT, +dateadd_numeric_representation_helper('second',1,cast(1.5 as NUMERIC)) AS NUMERIC_REP, +dateadd_numeric_representation_helper('second',1,cast(1.5 as FLOAT)) AS FLOAT_REP, +dateadd_numeric_representation_helper('second',1,cast(1.5 as REAL)) AS REAL_REP, +dateadd_numeric_representation_helper('second',1,cast(1.5 as MONEY)) AS MONEY_REP, +dateadd_numeric_representation_helper('second',1,cast(1.5 as SMALLMONEY)) AS SMALLMONEY_REP +GO + +CREATE VIEW dateadd_numeric_representation_helper_millisecond_view AS +SELECT +dateadd_numeric_representation_helper('millisecond',1,cast(1.5 as BIGINT)) AS BIT_INT, +dateadd_numeric_representation_helper('millisecond',1,cast(1.5 as INT)) AS REG_INT, +dateadd_numeric_representation_helper('millisecond',1,cast(1.5 as SMALLINT)) AS SMALL_INT, +dateadd_numeric_representation_helper('millisecond',1,cast(1.5 as TINYINT)) AS TINY_INT, +dateadd_numeric_representation_helper('millisecond',1,cast(1.5 as NUMERIC)) AS NUMERIC_REP, +dateadd_numeric_representation_helper('millisecond',1,cast(1.5 as FLOAT)) AS FLOAT_REP, +dateadd_numeric_representation_helper('millisecond',1,cast(1.5 as REAL)) AS REAL_REP, +dateadd_numeric_representation_helper('millisecond',1,cast(1.5 as MONEY)) AS MONEY_REP, +dateadd_numeric_representation_helper('millisecond',1,cast(1.5 as SMALLMONEY)) AS SMALLMONEY_REP +GO + + +CREATE VIEW dateadd_view_1 AS +SELECT * FROM sys.dateadd('year',1,cast(1.5 as REAL)) +GO + +CREATE VIEW dateadd_view_2 AS +SELECT * FROM sys.dateadd('year',1,cast(1.5 as NUMERIC(30,8))) +GO + +CREATE VIEW dateadd_view_3 AS +SELECT * FROM sys.dateadd('year',1,cast(1.5 as DECIMAL)) +GO + +CREATE VIEW dateadd_view_4 AS +SELECT * FROM sys.dateadd('year',1,cast(1 as BIT)) +GO + +CREATE VIEW dateadd_view_5 AS +SELECT * FROM sys.dateadd('year',1,cast(1.5 as FLOAT)) +GO + +CREATE VIEW dateadd_view_6 AS +SELECT * FROM sys.dateadd('year',1,cast(1.5 as FLOAT)) +GO diff --git a/test/JDBC/expected/TestDatetime-numeric-dateaddfunction-vu-verify.out b/test/JDBC/expected/TestDatetime-numeric-dateaddfunction-vu-verify.out new file mode 100644 index 0000000000..37aabe2233 --- /dev/null +++ b/test/JDBC/expected/TestDatetime-numeric-dateaddfunction-vu-verify.out @@ -0,0 +1,292 @@ +-- output from SQL Server : +-- 1900-01-02 00:00:00.000 1900-01-04 00:00:00.000 1900-01-03 12:00:00.000 1900-01-03 12:00:00.000 1900-01-03 12:00:00.000 1900-01-03 00:00:00.000 1900-01-03 00:00:00.000 1900-01-03 00:00:00.000 1900-01-03 00:00:00.000 1900-01-03 12:00:00.000 1900-01-03 12:00:00.000 1900-01-02 00:00:00.000 1899-12-29 00:00:00.000 1899-12-29 12:00:00.000 1899-12-29 12:00:00.000 1899-12-29 12:00:00.000 1899-12-30 00:00:00.000 1899-12-30 00:00:00.000 1899-12-30 00:00:00.000 1899-12-29 12:00:00.000 1899-12-29 12:00:00.000 null +SELECT * FROM Datetime_view3 +GO +~~START~~ +datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime +1900-01-02 00:00:00.0#!#1900-01-04 00:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-03 00:00:00.0#!#1900-01-03 00:00:00.0#!#1900-01-03 00:00:00.0#!#1900-01-03 00:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-02 00:00:00.0#!#1899-12-29 00:00:00.0#!#1899-12-29 12:00:00.0#!#1899-12-29 12:00:00.0#!#1899-12-29 12:00:00.0#!#1899-12-30 00:00:00.0#!#1899-12-30 00:00:00.0#!#1899-12-30 00:00:00.0#!#1899-12-29 12:00:00.0#!#1899-12-29 12:00:00.0#!# +~~END~~ + +DROP VIEW Datetime_view3 +GO + +-- output from SQL Server : +-- 1900-01-02 00:00 1900-01-04 00:00 1900-01-03 12:00 1900-01-03 12:00 1900-01-03 12:00 1900-01-03 00:00 1900-01-03 00:00 1900-01-03 00:00 1900-01-03 00:00 1900-01-03 12:00 1900-01-03 12:00 1900-01-02 00:00 null +SELECT * FROM Datetime_view4 +GO +~~START~~ +smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime +1900-01-02 00:00:00.0#!#1900-01-04 00:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-03 00:00:00.0#!#1900-01-03 00:00:00.0#!#1900-01-03 00:00:00.0#!#1900-01-03 00:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-02 00:00:00.0#!# +~~END~~ + +DROP VIEW Datetime_view4 +GO + +-- Should throw ERROR : Argument data type bit is invalid for argument 2 of dateadd function. +SELECT DATEADD(minute, CAST(1 as BIT), CAST(2.5 as BIT)) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type bit is invalid for argument 2 of dateadd function.)~~ + + +-- output from SQL Server : +-- 1900-01-04 00:01:00.000 1900-01-03 12:01:00.000 1900-01-03 12:01:00.000 1900-01-03 12:01:00.000 1900-01-03 00:01:00.000 1900-01-03 00:01:00.000 1900-01-03 00:01:00.000 1900-01-03 00:01:00.000 1900-01-03 12:01:00.000 1900-01-03 12:01:00.000 1899-12-28 23:59:00.000 1899-12-29 11:59:00.000 1899-12-29 11:59:00.000 1899-12-29 11:59:00.000 1899-12-29 23:59:00.000 1899-12-29 23:59:00.000 1899-12-29 23:59:00.000 1899-12-29 11:59:00.000 1899-12-29 11:59:00.000 +SELECT * FROM Datetime_view5 +GO +~~START~~ +datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime +1900-01-04 00:01:00.0#!#1900-01-03 12:01:00.0#!#1900-01-03 12:01:00.0#!#1900-01-03 12:01:00.0#!#1900-01-03 00:01:00.0#!#1900-01-03 00:01:00.0#!#1900-01-03 00:01:00.0#!#1900-01-03 00:01:00.0#!#1900-01-03 12:01:00.0#!#1900-01-03 12:01:00.0#!#1899-12-28 23:59:00.0#!#1899-12-29 11:59:00.0#!#1899-12-29 11:59:00.0#!#1899-12-29 11:59:00.0#!#1899-12-29 23:59:00.0#!#1899-12-29 23:59:00.0#!#1899-12-29 23:59:00.0#!#1899-12-29 11:59:00.0#!#1899-12-29 11:59:00.0 +~~END~~ + +DROP VIEW Datetime_view5 +GO + +-- Procedures +EXEC Datetime_proc1 '1900-01-02 00:00:00', 3.1 +GO +~~START~~ +text +pass +~~END~~ + +EXEC Datetime_proc1 '1900-01-02 00:00:00', 2 +GO +~~START~~ +text +pass +~~END~~ + +EXEC Datetime_proc1 '1900-01-01 00:00:00', 0 +GO +~~START~~ +text +pass +~~END~~ + +EXEC Datetime_proc1 '1900-01-02 00:00:00', -3.1 +GO +~~START~~ +text +pass +~~END~~ + +DROP PROCEDURE Datetime_proc1 +GO + +EXEC SMALLDatetime_proc1 '1900-01-02 00:00:00', 3.1 +GO +~~START~~ +text +pass +~~END~~ + +EXEC SMALLDatetime_proc1 '1900-01-02 00:00:00', 2 +GO +~~START~~ +text +pass +~~END~~ + +EXEC SMALLDatetime_proc1 '1900-01-01 00:00:00', 0 +GO +~~START~~ +text +pass +~~END~~ + +EXEC SMALLDatetime_proc1 '1900-01-02 00:00:00', -3.1 +GO +~~START~~ +text +pass +~~END~~ + +DROP PROCEDURE SMALLDatetime_proc1 +GO + +SELECT * FROM dateadd_numeric_representation_helper_year_view +GO +~~START~~ +datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime +1901-01-02 00:00:00.0#!#1901-01-02 00:00:00.0#!#1901-01-02 00:00:00.0#!#1901-01-02 00:00:00.0#!#1901-01-03 00:00:00.0#!#1901-01-02 12:00:00.0#!#1901-01-02 12:00:00.0#!#1901-01-02 12:00:00.0#!#1901-01-02 12:00:00.0 +~~END~~ + + +DROP VIEW dateadd_numeric_representation_helper_year_view +GO + +SELECT * FROM dateadd_numeric_representation_helper_quarter_view +GO +~~START~~ +datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime +1900-04-02 00:00:00.0#!#1900-04-02 00:00:00.0#!#1900-04-02 00:00:00.0#!#1900-04-02 00:00:00.0#!#1900-04-03 00:00:00.0#!#1900-04-02 12:00:00.0#!#1900-04-02 12:00:00.0#!#1900-04-02 12:00:00.0#!#1900-04-02 12:00:00.0 +~~END~~ + + +DROP VIEW dateadd_numeric_representation_helper_quarter_view +GO + +SELECT * FROM dateadd_numeric_representation_helper_month_view +GO +~~START~~ +datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime +1900-02-02 00:00:00.0#!#1900-02-02 00:00:00.0#!#1900-02-02 00:00:00.0#!#1900-02-02 00:00:00.0#!#1900-02-03 00:00:00.0#!#1900-02-02 12:00:00.0#!#1900-02-02 12:00:00.0#!#1900-02-02 12:00:00.0#!#1900-02-02 12:00:00.0 +~~END~~ + + +DROP VIEW dateadd_numeric_representation_helper_month_view +GO + +SELECT * FROM dateadd_numeric_representation_helper_dayofyear_view +GO +~~START~~ +datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime +1900-01-03 00:00:00.0#!#1900-01-03 00:00:00.0#!#1900-01-03 00:00:00.0#!#1900-01-03 00:00:00.0#!#1900-01-04 00:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-03 12:00:00.0 +~~END~~ + + +DROP VIEW dateadd_numeric_representation_helper_dayofyear_view +GO + +SELECT * FROM dateadd_numeric_representation_helper_day_view +GO +~~START~~ +datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime +1900-01-03 00:00:00.0#!#1900-01-03 00:00:00.0#!#1900-01-03 00:00:00.0#!#1900-01-03 00:00:00.0#!#1900-01-04 00:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-03 12:00:00.0 +~~END~~ + + +DROP VIEW dateadd_numeric_representation_helper_day_view +GO + +SELECT * FROM dateadd_numeric_representation_helper_week_view +GO +~~START~~ +datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime +1900-01-09 00:00:00.0#!#1900-01-09 00:00:00.0#!#1900-01-09 00:00:00.0#!#1900-01-09 00:00:00.0#!#1900-01-10 00:00:00.0#!#1900-01-09 12:00:00.0#!#1900-01-09 12:00:00.0#!#1900-01-09 12:00:00.0#!#1900-01-09 12:00:00.0 +~~END~~ + + +DROP VIEW dateadd_numeric_representation_helper_week_view +GO + +SELECT * FROM dateadd_numeric_representation_helper_weekday_view +GO +~~START~~ +datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime +1900-01-03 00:00:00.0#!#1900-01-03 00:00:00.0#!#1900-01-03 00:00:00.0#!#1900-01-03 00:00:00.0#!#1900-01-04 00:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-03 12:00:00.0 +~~END~~ + + +DROP VIEW dateadd_numeric_representation_helper_weekday_view +GO + +SELECT * FROM dateadd_numeric_representation_helper_hour_view +GO +~~START~~ +datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime +1900-01-02 01:00:00.0#!#1900-01-02 01:00:00.0#!#1900-01-02 01:00:00.0#!#1900-01-02 01:00:00.0#!#1900-01-03 01:00:00.0#!#1900-01-02 13:00:00.0#!#1900-01-02 13:00:00.0#!#1900-01-02 13:00:00.0#!#1900-01-02 13:00:00.0 +~~END~~ + + +DROP VIEW dateadd_numeric_representation_helper_hour_view +GO + +SELECT * FROM dateadd_numeric_representation_helper_minute_view +GO +~~START~~ +datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime +1900-01-02 00:01:00.0#!#1900-01-02 00:01:00.0#!#1900-01-02 00:01:00.0#!#1900-01-02 00:01:00.0#!#1900-01-03 00:01:00.0#!#1900-01-02 12:01:00.0#!#1900-01-02 12:01:00.0#!#1900-01-02 12:01:00.0#!#1900-01-02 12:01:00.0 +~~END~~ + + +DROP VIEW dateadd_numeric_representation_helper_minute_view +GO + +SELECT * FROM dateadd_numeric_representation_helper_second_view +GO +~~START~~ +datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime +1900-01-02 00:00:01.0#!#1900-01-02 00:00:01.0#!#1900-01-02 00:00:01.0#!#1900-01-02 00:00:01.0#!#1900-01-03 00:00:01.0#!#1900-01-02 12:00:01.0#!#1900-01-02 12:00:01.0#!#1900-01-02 12:00:01.0#!#1900-01-02 12:00:01.0 +~~END~~ + + +DROP VIEW dateadd_numeric_representation_helper_second_view +GO + +SELECT * FROM dateadd_numeric_representation_helper_millisecond_view +GO +~~START~~ +datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime +1900-01-02 00:00:00.0#!#1900-01-02 00:00:00.0#!#1900-01-02 00:00:00.0#!#1900-01-02 00:00:00.0#!#1900-01-03 00:00:00.0#!#1900-01-02 12:00:00.0#!#1900-01-02 12:00:00.0#!#1900-01-02 12:00:00.0#!#1900-01-02 12:00:00.0 +~~END~~ + + +DROP VIEW dateadd_numeric_representation_helper_millisecond_view +GO + +SELECT * FROM dateadd_view_1 +GO +~~START~~ +datetime +1901-01-02 12:00:00.0 +~~END~~ + + +DROP VIEW dateadd_view_1 +GO + +SELECT * FROM dateadd_view_2 +GO +~~START~~ +datetime +1901-01-02 12:00:00.0 +~~END~~ + + +DROP VIEW dateadd_view_2 +GO + +SELECT * FROM dateadd_view_3 +GO +~~START~~ +datetime +1901-01-03 00:00:00.0 +~~END~~ + + +DROP VIEW dateadd_view_3 +GO + +SELECT * FROM dateadd_view_4 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type bit is invalid for argument 2 of dateadd function.)~~ + + +DROP VIEW dateadd_view_4 +GO + +SELECT * FROM dateadd_view_5 +GO +~~START~~ +datetime +1901-01-02 12:00:00.0 +~~END~~ + + +DROP VIEW dateadd_view_5 +GO + +SELECT * FROM dateadd_view_6 +GO +~~START~~ +datetime +1901-01-02 12:00:00.0 +~~END~~ + + +DROP VIEW dateadd_view_6 +GO diff --git a/test/JDBC/expected/TestDatetime-numeric-representation-vu-prepare.out b/test/JDBC/expected/TestDatetime-numeric-representation-vu-prepare.out new file mode 100644 index 0000000000..86d888189a --- /dev/null +++ b/test/JDBC/expected/TestDatetime-numeric-representation-vu-prepare.out @@ -0,0 +1,352 @@ +CREATE VIEW Datetime_view1 +AS( + SELECT + CAST(CAST(2.5 as BIT) as DATETIME) as re1, + CAST(CAST(2.5 as DECIMAL) as DATETIME)as re2, + CAST(CAST(2.5 as NUMERIC(30,8)) as DATETIME)as re3, + CAST(CAST(2.5 as FLOAT) as DATETIME)as re4, + CAST(CAST(2.5 as REAL) as DATETIME)as re5, + CAST(CAST(2.5 as INT) as DATETIME)as re6, + CAST(CAST(2.5 as BIGINT) as DATETIME)as re7, + CAST(CAST(2.5 as SMALLINT) as DATETIME)as re8, + CAST(CAST(2.5 as TINYINT) as DATETIME)as re9, + CAST(CAST(2.5 as MONEY) as DATETIME)as re10, + CAST(CAST(2.5 as SMALLMONEY) as DATETIME)as re11, + CAST(CAST(-2.5 as BIT) as DATETIME) as re12, + CAST(CAST(-2.5 as DECIMAL) as DATETIME)as re13, + CAST(CAST(-2.5 as NUMERIC(30,8)) as DATETIME)as re14, + CAST(CAST(-2.5 as FLOAT) as DATETIME)as re15, + CAST(CAST(-2.5 as REAL) as DATETIME)as re16, + CAST(CAST(-2.5 as INT) as DATETIME)as re17, + CAST(CAST(-2.5 as BIGINT) as DATETIME)as re18, + CAST(CAST(-2.5 as SMALLINT) as DATETIME)as re19, + CAST(CAST(-2.5 as MONEY) as DATETIME)as re20, + CAST(CAST(-2.5 as SMALLMONEY) as DATETIME)as re21, + CAST(NULL as DATETIME)as res22 +); +GO + +CREATE VIEW Datetime_view2 +AS( + SELECT + CAST(CAST(2.5 as BIT) as SMALLDATETIME) as re1, + CAST(CAST(2.5 as DECIMAL) as SMALLDATETIME)as re2, + CAST(CAST(2.5 as NUMERIC(30,8)) as SMALLDATETIME)as re3, + CAST(CAST(2.5 as FLOAT) as SMALLDATETIME)as re4, + CAST(CAST(2.5 as REAL) as SMALLDATETIME)as re5, + CAST(CAST(2.5 as INT) as SMALLDATETIME)as re6, + CAST(CAST(2.5 as BIGINT) as SMALLDATETIME)as re7, + CAST(CAST(2.5 as SMALLINT) as SMALLDATETIME)as re8, + CAST(CAST(2.5 as TINYINT) as SMALLDATETIME)as re9, + CAST(CAST(2.5 as MONEY) as SMALLDATETIME)as re10, + CAST(CAST(2.5 as SMALLMONEY) as SMALLDATETIME)as re11, + CAST(CAST(-2.5 as BIT) as SMALLDATETIME) as re12, + CAST(NULL as SMALLDATETIME)as res13 +); +GO + +-- Should all fail +SELECT CAST(CAST(-2.5 as NUMERIC(30,8)) as SMALLDATETIME) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + +SELECT CAST(CAST(-2.5 as FLOAT) as SMALLDATETIME) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + +SELECT CAST(CAST(-2.5 as REAL) as SMALLDATETIME) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + +SELECT CAST(CAST(-2.5 as INT) as SMALLDATETIME) +GO +~~START~~ +smalldatetime +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + +SELECT CAST(CAST(-2.5 as BIGINT) as SMALLDATETIME) +GO +~~START~~ +smalldatetime +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + +SELECT CAST(CAST(-2.5 as SMALLINT) as SMALLDATETIME) +GO +~~START~~ +smalldatetime +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + +SELECT CAST(CAST(-2.5 as MONEY) as SMALLDATETIME) +GO +~~START~~ +smalldatetime +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + +SELECT CAST(CAST(-2.5 as SMALLMONEY) as SMALLDATETIME) +GO +~~START~~ +smalldatetime +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + + +CREATE VIEW Datetime_view6 as ( + SELECT + DATEDIFF(minute, CAST(1 as BIT), CAST(2.5 AS BIT)) as re1, + DATEDIFF(minute, CAST(1 as DECIMAL), CAST(2.5 AS DECIMAL)) as re2, + DATEDIFF(minute, CAST(1 as NUMERIC(30,8)), CAST(2.5 AS NUMERIC(30,8))) as re3, + DATEDIFF(minute, CAST(1 as FLOAT), CAST(2.5 AS FLOAT)) as re4, + DATEDIFF(minute, CAST(1 as REAL), CAST(2.5 AS REAL)) as re5, + DATEDIFF(minute, CAST(1 as INT), CAST(2.5 AS INT)) as re6, + DATEDIFF(minute, CAST(1 as BIGINT), CAST(2.5 AS BIGINT)) as re7, + DATEDIFF(minute, CAST(1 as SMALLINT), CAST(2.5 AS SMALLINT)) as re8, + DATEDIFF(minute, CAST(1 as TINYINT), CAST(2.5 AS TINYINT)) as re9, + DATEDIFF(minute, CAST(1 as MONEY), CAST(2.5 AS MONEY)) as re10, + DATEDIFF(minute, CAST(1 as SMALLMONEY), CAST(-2.5 AS SMALLMONEY)) as re11, + DATEDIFF(minute, CAST(-1 as BIT), CAST(-2.5 AS BIT)) as re12, + DATEDIFF(minute, CAST(-1 as DECIMAL), CAST(-2.5 AS DECIMAL)) as re13, + DATEDIFF(minute, CAST(-1 as NUMERIC(30,8)), CAST(-2.5 AS NUMERIC(30,8))) as re14, + DATEDIFF(minute, CAST(-1 as FLOAT), CAST(-2.5 AS FLOAT)) as re15, + DATEDIFF(minute, CAST(-1 as REAL), CAST(-2.5 AS REAL)) as re16, + DATEDIFF(minute, CAST(-1 as INT), CAST(-2.5 AS INT)) as re17, + DATEDIFF(minute, CAST(-1 as BIGINT), CAST(-2.5 AS BIGINT)) as re18, + DATEDIFF(minute, CAST(-1 as SMALLINT), CAST(-2.5 AS SMALLINT)) as re19, + DATEDIFF(minute, CAST(-1 as MONEY), CAST(-2.5 AS MONEY)) as re20, + DATEDIFF(minute, CAST(-1 as SMALLMONEY), CAST(-2.5 AS SMALLMONEY)) as re21 +); +GO + + +CREATE TABLE Datetime_Operators_tbl1 (col DATETIME) +GO +INSERT INTO Datetime_Operators_tbl1 VALUES('1900-01-05 00:00:00.000'); +INSERT INTO Datetime_Operators_tbl1 VALUES('1900-01-05 23:40:30.000'); +INSERT INTO Datetime_Operators_tbl1 VALUES('1900-01-01 23:40:30.000'); +INSERT INTO Datetime_Operators_tbl1 VALUES('1900-01-02 00:00:00.000'); +INSERT INTO Datetime_Operators_tbl1 VALUES(NULL); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +CREATE TABLE Datetime_Operators_tbl2 (col SMALLDATETIME) +GO +INSERT INTO Datetime_Operators_tbl2 VALUES('1900-01-05 00:00:00.000'); +INSERT INTO Datetime_Operators_tbl2 VALUES('1900-01-05 23:40:30.000'); +INSERT INTO Datetime_Operators_tbl2 VALUES('1900-01-01 23:40:30.000'); +INSERT INTO Datetime_Operators_tbl2 VALUES('1900-01-02 00:00:00.000'); +INSERT INTO Datetime_Operators_tbl2 VALUES(NULL); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +CREATE TABLE Datetime_tbl1 (c1 DATETIME, c2 as DATEDIFF(day,'1900-01-01 00:00:00.000',c1)) +GO + +CREATE TABLE Datetime_tbl2 (c1 SMALLDATETIME, c2 as DATEDIFF(day,'1900-01-01 00:00:00.000',c1)) +GO + +CREATE PROCEDURE Datetime_proc2 (@a DATETIME, @b DECIMAL) AS +BEGIN + DECLARE @c DATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE Datetime_proc3 (@a DATETIME, @b NUMERIC(30,8)) AS +BEGIN + DECLARE @c DATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE Datetime_proc4 (@a DATETIME, @b FLOAT) AS +BEGIN + DECLARE @c DATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE Datetime_proc5 (@a DATETIME, @b REAL) AS +BEGIN + DECLARE @c DATETIME = @b; + SELECT (@a) as result1; + SELECT (@c) as result2; +END +GO + +CREATE PROCEDURE Datetime_proc6 (@a DATETIME, @b INT) AS +BEGIN + DECLARE @c DATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE Datetime_proc7 (@a DATETIME, @b BIGINT) AS +BEGIN + DECLARE @c DATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE Datetime_proc8 (@a DATETIME, @b SMALLINT) AS +BEGIN + DECLARE @c DATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE Datetime_proc9 (@a DATETIME, @b TINYINT) AS +BEGIN + DECLARE @c DATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE Datetime_proc10 (@a DATETIME, @b MONEY) AS +BEGIN + DECLARE @c DATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE Datetime_proc11 (@a DATETIME, @b SMALLMONEY) AS +BEGIN + DECLARE @c DATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE SMALLDatetime_proc2 (@a SMALLDATETIME, @b DECIMAL) AS +BEGIN + DECLARE @c SMALLDATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE SMALLDatetime_proc3 (@a SMALLDATETIME, @b NUMERIC(30,8)) AS +BEGIN + DECLARE @c SMALLDATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE SMALLDatetime_proc4 (@a SMALLDATETIME, @b FLOAT) AS +BEGIN + DECLARE @c SMALLDATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE SMALLDatetime_proc5 (@a SMALLDATETIME, @b REAL) AS +BEGIN + DECLARE @c SMALLDATETIME = @b; + SELECT (@a) as result1; + SELECT (@c) as result2; +END +GO + +CREATE PROCEDURE SMALLDatetime_proc6 (@a SMALLDATETIME, @b INT) AS +BEGIN + DECLARE @c SMALLDATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE SMALLDatetime_proc7 (@a SMALLDATETIME, @b BIGINT) AS +BEGIN + DECLARE @c SMALLDATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE SMALLDatetime_proc8 (@a SMALLDATETIME, @b SMALLINT) AS +BEGIN + DECLARE @c SMALLDATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE SMALLDatetime_proc9 (@a SMALLDATETIME, @b TINYINT) AS +BEGIN + DECLARE @c SMALLDATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE SMALLDatetime_proc10 (@a SMALLDATETIME, @b MONEY) AS +BEGIN + DECLARE @c SMALLDATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE SMALLDatetime_proc11 (@a SMALLDATETIME, @b SMALLMONEY) AS +BEGIN + DECLARE @c SMALLDATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + + +CREATE TABLE Datetime_target_type_table ( + datetimetype datetime, + smalldatetimetype smalldatetime +); +GO + +CREATE TABLE Datetime_source_type_table ( + bittype bit, + decimaltype decimal, + numerictype numeric(30,8), + floattype float, + realtype real, + inttype int, + biginttype bigint, + smallinttype smallint, + tinyinttype tinyint, + moneytype money, + smallmonettype smallmoney, + nulltype int +); +GO + +INSERT INTO Datetime_target_type_table VALUES ('20120618 10:34:09 AM', '2018-07-24 06:30:50.000'); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO Datetime_source_type_table VALUES (0,1.9,2.0,3.1,4.2,5.4,6.2,7,8,9,10,null); +GO +~~ROW COUNT: 1~~ + diff --git a/test/JDBC/expected/TestDatetime-numeric-representation-vu-verify.out b/test/JDBC/expected/TestDatetime-numeric-representation-vu-verify.out new file mode 100644 index 0000000000..5ea96622ef --- /dev/null +++ b/test/JDBC/expected/TestDatetime-numeric-representation-vu-verify.out @@ -0,0 +1,2426 @@ +-- output from SQL Server : +-- 1900-01-02 00:00:00.000 1900-01-04 00:00:00.000 1900-01-03 12:00:00.000 1900-01-03 12:00:00.000 1900-01-03 12:00:00.000 1900-01-03 00:00:00.000 1900-01-03 00:00:00.000 1900-01-03 00:00:00.000 1900-01-03 00:00:00.000 1900-01-03 12:00:00.000 1900-01-03 12:00:00.000 1900-01-02 00:00:00.000 1899-12-29 00:00:00.000 1899-12-29 12:00:00.000 1899-12-29 12:00:00.000 1899-12-29 12:00:00.000 1899-12-30 00:00:00.000 1899-12-30 00:00:00.000 1899-12-30 00:00:00.000 1899-12-29 12:00:00.000 1899-12-29 12:00:00.000 null +SELECT * FROM Datetime_view1 +GO +~~START~~ +datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime +1900-01-02 00:00:00.0#!#1900-01-04 00:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-03 00:00:00.0#!#1900-01-03 00:00:00.0#!#1900-01-03 00:00:00.0#!#1900-01-03 00:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-02 00:00:00.0#!#1899-12-29 00:00:00.0#!#1899-12-29 12:00:00.0#!#1899-12-29 12:00:00.0#!#1899-12-29 12:00:00.0#!#1899-12-30 00:00:00.0#!#1899-12-30 00:00:00.0#!#1899-12-30 00:00:00.0#!#1899-12-29 12:00:00.0#!#1899-12-29 12:00:00.0#!# +~~END~~ + +DROP VIEW Datetime_view1 +GO + +-- output from SQL Server : +-- 1900-01-02 00:00 1900-01-04 00:00 1900-01-03 12:00 1900-01-03 12:00 1900-01-03 12:00 1900-01-03 00:00 1900-01-03 00:00 1900-01-03 00:00 1900-01-03 00:00 1900-01-03 12:00 1900-01-03 12:00 1900-01-02 00:00 null +SELECT * FROM Datetime_view2 +GO +~~START~~ +smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime +1900-01-02 00:00:00.0#!#1900-01-04 00:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-03 00:00:00.0#!#1900-01-03 00:00:00.0#!#1900-01-03 00:00:00.0#!#1900-01-03 00:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-03 12:00:00.0#!#1900-01-02 00:00:00.0#!# +~~END~~ + +DROP VIEW Datetime_view2 +GO + +-- output from SQL Server : +-- 0 2880 2160 2160 2160 1440 1440 1440 1440 2160 -5040 0 -2880 -2160 -2160 -2160 -1440 -1440 -1440 -2160 -2160 +SELECT * FROM Datetime_view6 +GO +~~START~~ +int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int +0#!#2880#!#2160#!#2160#!#2160#!#1440#!#1440#!#1440#!#1440#!#2160#!#-5040#!#0#!#-2880#!#-2160#!#-2160#!#-2160#!#-1440#!#-1440#!#-1440#!#-2160#!#-2160 +~~END~~ + +DROP VIEW Datetime_view6 +GO + +-- Operators +SELECT * FROM Datetime_Operators_tbl1 WHERE col = CAST(4 as BIT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col > CAST(4 as BIT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col >= CAST(4 as BIT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col < CAST(4 as BIT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col <= CAST(4 as BIT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col != CAST(4 as BIT); +GO +~~START~~ +datetime +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 00:00:00.0 +1900-01-05 23:40:30.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 00:00:00.0 +1900-01-05 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-01 23:40:30.0 +~~END~~ + +~~START~~ +datetime +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 00:00:00.0 +1900-01-05 23:40:30.0 +1900-01-01 23:40:30.0 +~~END~~ + + +SELECT * FROM Datetime_Operators_tbl1 WHERE col = CAST(4 as DECIMAL); +SELECT * FROM Datetime_Operators_tbl1 WHERE col > CAST(4 as DECIMAL); +SELECT * FROM Datetime_Operators_tbl1 WHERE col >= CAST(4 as DECIMAL); +SELECT * FROM Datetime_Operators_tbl1 WHERE col < CAST(4 as DECIMAL); +SELECT * FROM Datetime_Operators_tbl1 WHERE col <= CAST(4 as DECIMAL); +SELECT * FROM Datetime_Operators_tbl1 WHERE col != CAST(4 as DECIMAL); +GO +~~START~~ +datetime +1900-01-05 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 23:40:30.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 00:00:00.0 +1900-01-05 23:40:30.0 +~~END~~ + +~~START~~ +datetime +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 00:00:00.0 +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 23:40:30.0 +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + + +SELECT * FROM Datetime_Operators_tbl1 WHERE col = CAST(4 as NUMERIC); +SELECT * FROM Datetime_Operators_tbl1 WHERE col > CAST(4 as NUMERIC); +SELECT * FROM Datetime_Operators_tbl1 WHERE col >= CAST(4 as NUMERIC); +SELECT * FROM Datetime_Operators_tbl1 WHERE col < CAST(4 as NUMERIC); +SELECT * FROM Datetime_Operators_tbl1 WHERE col <= CAST(4 as NUMERIC); +SELECT * FROM Datetime_Operators_tbl1 WHERE col != CAST(4 as NUMERIC); +GO +~~START~~ +datetime +1900-01-05 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 23:40:30.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 00:00:00.0 +1900-01-05 23:40:30.0 +~~END~~ + +~~START~~ +datetime +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 00:00:00.0 +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 23:40:30.0 +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + + +SELECT * FROM Datetime_Operators_tbl1 WHERE col = CAST(4 as FLOAT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col > CAST(4 as FLOAT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col >= CAST(4 as FLOAT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col < CAST(4 as FLOAT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col <= CAST(4 as FLOAT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col != CAST(4 as FLOAT); +GO +~~START~~ +datetime +1900-01-05 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 23:40:30.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 00:00:00.0 +1900-01-05 23:40:30.0 +~~END~~ + +~~START~~ +datetime +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 00:00:00.0 +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 23:40:30.0 +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + + +SELECT * FROM Datetime_Operators_tbl1 WHERE col = CAST(4 as REAL); +SELECT * FROM Datetime_Operators_tbl1 WHERE col > CAST(4 as REAL); +SELECT * FROM Datetime_Operators_tbl1 WHERE col >= CAST(4 as REAL); +SELECT * FROM Datetime_Operators_tbl1 WHERE col < CAST(4 as REAL); +SELECT * FROM Datetime_Operators_tbl1 WHERE col <= CAST(4 as REAL); +SELECT * FROM Datetime_Operators_tbl1 WHERE col != CAST(4 as REAL); +GO +~~START~~ +datetime +1900-01-05 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 23:40:30.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 00:00:00.0 +1900-01-05 23:40:30.0 +~~END~~ + +~~START~~ +datetime +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 00:00:00.0 +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 23:40:30.0 +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + + +SELECT * FROM Datetime_Operators_tbl1 WHERE col = CAST(4 as INT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col > CAST(4 as INT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col >= CAST(4 as INT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col < CAST(4 as INT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col <= CAST(4 as INT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col != CAST(4 as INT); +GO +~~START~~ +datetime +1900-01-05 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 23:40:30.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 00:00:00.0 +1900-01-05 23:40:30.0 +~~END~~ + +~~START~~ +datetime +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 00:00:00.0 +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 23:40:30.0 +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + + +SELECT * FROM Datetime_Operators_tbl1 WHERE col = CAST(4 as BIGINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col > CAST(4 as BIGINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col >= CAST(4 as BIGINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col < CAST(4 as BIGINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col <= CAST(4 as BIGINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col != CAST(4 as BIGINT); +GO +~~START~~ +datetime +1900-01-05 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 23:40:30.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 00:00:00.0 +1900-01-05 23:40:30.0 +~~END~~ + +~~START~~ +datetime +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 00:00:00.0 +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 23:40:30.0 +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + + +SELECT * FROM Datetime_Operators_tbl1 WHERE col = CAST(4 as SMALLINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col > CAST(4 as SMALLINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col >= CAST(4 as SMALLINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col < CAST(4 as SMALLINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col <= CAST(4 as SMALLINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col != CAST(4 as SMALLINT); +GO +~~START~~ +datetime +1900-01-05 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 23:40:30.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 00:00:00.0 +1900-01-05 23:40:30.0 +~~END~~ + +~~START~~ +datetime +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 00:00:00.0 +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 23:40:30.0 +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + + +SELECT * FROM Datetime_Operators_tbl1 WHERE col = CAST(4 as TINYINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col > CAST(4 as TINYINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col >= CAST(4 as TINYINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col < CAST(4 as TINYINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col <= CAST(4 as TINYINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col != CAST(4 as TINYINT); +GO +~~START~~ +datetime +1900-01-05 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 23:40:30.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 00:00:00.0 +1900-01-05 23:40:30.0 +~~END~~ + +~~START~~ +datetime +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 00:00:00.0 +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 23:40:30.0 +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + + +SELECT * FROM Datetime_Operators_tbl1 WHERE col = CAST(4 as MONEY); +SELECT * FROM Datetime_Operators_tbl1 WHERE col > CAST(4 as MONEY); +SELECT * FROM Datetime_Operators_tbl1 WHERE col >= CAST(4 as MONEY); +SELECT * FROM Datetime_Operators_tbl1 WHERE col < CAST(4 as MONEY); +SELECT * FROM Datetime_Operators_tbl1 WHERE col <= CAST(4 as MONEY); +SELECT * FROM Datetime_Operators_tbl1 WHERE col != CAST(4 as MONEY); +GO +~~START~~ +datetime +1900-01-05 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 23:40:30.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 00:00:00.0 +1900-01-05 23:40:30.0 +~~END~~ + +~~START~~ +datetime +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 00:00:00.0 +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 23:40:30.0 +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + + +SELECT * FROM Datetime_Operators_tbl1 WHERE col = CAST(4 as SMALLMONEY); +SELECT * FROM Datetime_Operators_tbl1 WHERE col > CAST(4 as SMALLMONEY); +SELECT * FROM Datetime_Operators_tbl1 WHERE col >= CAST(4 as SMALLMONEY); +SELECT * FROM Datetime_Operators_tbl1 WHERE col < CAST(4 as SMALLMONEY); +SELECT * FROM Datetime_Operators_tbl1 WHERE col <= CAST(4 as SMALLMONEY); +SELECT * FROM Datetime_Operators_tbl1 WHERE col != CAST(4 as SMALLMONEY); +GO +~~START~~ +datetime +1900-01-05 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 23:40:30.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 00:00:00.0 +1900-01-05 23:40:30.0 +~~END~~ + +~~START~~ +datetime +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 00:00:00.0 +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-05 23:40:30.0 +1900-01-01 23:40:30.0 +1900-01-02 00:00:00.0 +~~END~~ + + +SELECT * FROM Datetime_Operators_tbl1 WHERE col = NULL; +SELECT * FROM Datetime_Operators_tbl1 WHERE col > NULL; +SELECT * FROM Datetime_Operators_tbl1 WHERE col >= NULL; +SELECT * FROM Datetime_Operators_tbl1 WHERE col < NULL; +SELECT * FROM Datetime_Operators_tbl1 WHERE col <= NULL; +SELECT * FROM Datetime_Operators_tbl1 WHERE col != NULL; +GO +~~START~~ +datetime +~~END~~ + +~~START~~ +datetime +~~END~~ + +~~START~~ +datetime +~~END~~ + +~~START~~ +datetime +~~END~~ + +~~START~~ +datetime +~~END~~ + +~~START~~ +datetime +~~END~~ + + +DROP TABLE Datetime_Operators_tbl1 +GO + +SELECT * FROM Datetime_Operators_tbl2 WHERE col = CAST(4 as BIT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col > CAST(4 as BIT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col >= CAST(4 as BIT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col < CAST(4 as BIT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col <= CAST(4 as BIT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col != CAST(4 as BIT); +GO +~~START~~ +smalldatetime +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +1900-01-05 23:41:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +1900-01-05 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-01 23:41:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +1900-01-05 23:41:00.0 +1900-01-01 23:41:00.0 +~~END~~ + + +SELECT * FROM Datetime_Operators_tbl2 WHERE col = CAST(4 as DECIMAL); +SELECT * FROM Datetime_Operators_tbl2 WHERE col > CAST(4 as DECIMAL); +SELECT * FROM Datetime_Operators_tbl2 WHERE col >= CAST(4 as DECIMAL); +SELECT * FROM Datetime_Operators_tbl2 WHERE col < CAST(4 as DECIMAL); +SELECT * FROM Datetime_Operators_tbl2 WHERE col <= CAST(4 as DECIMAL); +SELECT * FROM Datetime_Operators_tbl2 WHERE col != CAST(4 as DECIMAL); +GO +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 23:41:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +1900-01-05 23:41:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 23:41:00.0 +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + + +SELECT * FROM Datetime_Operators_tbl2 WHERE col = CAST(4 as NUMERIC); +SELECT * FROM Datetime_Operators_tbl2 WHERE col > CAST(4 as NUMERIC); +SELECT * FROM Datetime_Operators_tbl2 WHERE col >= CAST(4 as NUMERIC); +SELECT * FROM Datetime_Operators_tbl2 WHERE col < CAST(4 as NUMERIC); +SELECT * FROM Datetime_Operators_tbl2 WHERE col <= CAST(4 as NUMERIC); +SELECT * FROM Datetime_Operators_tbl2 WHERE col != CAST(4 as NUMERIC); +GO +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 23:41:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +1900-01-05 23:41:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 23:41:00.0 +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + + +SELECT * FROM Datetime_Operators_tbl2 WHERE col = CAST(4 as FLOAT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col > CAST(4 as FLOAT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col >= CAST(4 as FLOAT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col < CAST(4 as FLOAT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col <= CAST(4 as FLOAT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col != CAST(4 as FLOAT); +GO +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 23:41:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +1900-01-05 23:41:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 23:41:00.0 +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + + +SELECT * FROM Datetime_Operators_tbl2 WHERE col = CAST(4 as REAL); +SELECT * FROM Datetime_Operators_tbl2 WHERE col > CAST(4 as REAL); +SELECT * FROM Datetime_Operators_tbl2 WHERE col >= CAST(4 as REAL); +SELECT * FROM Datetime_Operators_tbl2 WHERE col < CAST(4 as REAL); +SELECT * FROM Datetime_Operators_tbl2 WHERE col <= CAST(4 as REAL); +SELECT * FROM Datetime_Operators_tbl2 WHERE col != CAST(4 as REAL); +GO +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 23:41:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +1900-01-05 23:41:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 23:41:00.0 +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + + +SELECT * FROM Datetime_Operators_tbl2 WHERE col = CAST(4 as INT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col > CAST(4 as INT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col >= CAST(4 as INT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col < CAST(4 as INT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col <= CAST(4 as INT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col != CAST(4 as INT); +GO +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 23:41:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +1900-01-05 23:41:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 23:41:00.0 +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + + +SELECT * FROM Datetime_Operators_tbl2 WHERE col = CAST(4 as BIGINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col > CAST(4 as BIGINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col >= CAST(4 as BIGINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col < CAST(4 as BIGINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col <= CAST(4 as BIGINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col != CAST(4 as BIGINT); +GO +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 23:41:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +1900-01-05 23:41:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 23:41:00.0 +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + + +SELECT * FROM Datetime_Operators_tbl2 WHERE col = CAST(4 as SMALLINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col > CAST(4 as SMALLINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col >= CAST(4 as SMALLINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col < CAST(4 as SMALLINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col <= CAST(4 as SMALLINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col != CAST(4 as SMALLINT); +GO +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 23:41:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +1900-01-05 23:41:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 23:41:00.0 +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + + +SELECT * FROM Datetime_Operators_tbl2 WHERE col = CAST(4 as TINYINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col > CAST(4 as TINYINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col >= CAST(4 as TINYINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col < CAST(4 as TINYINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col <= CAST(4 as TINYINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col != CAST(4 as TINYINT); +GO +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 23:41:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +1900-01-05 23:41:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 23:41:00.0 +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + + +SELECT * FROM Datetime_Operators_tbl2 WHERE col = CAST(4 as MONEY); +SELECT * FROM Datetime_Operators_tbl2 WHERE col > CAST(4 as MONEY); +SELECT * FROM Datetime_Operators_tbl2 WHERE col >= CAST(4 as MONEY); +SELECT * FROM Datetime_Operators_tbl2 WHERE col < CAST(4 as MONEY); +SELECT * FROM Datetime_Operators_tbl2 WHERE col <= CAST(4 as MONEY); +SELECT * FROM Datetime_Operators_tbl2 WHERE col != CAST(4 as MONEY); +GO +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 23:41:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +1900-01-05 23:41:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 23:41:00.0 +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + + +SELECT * FROM Datetime_Operators_tbl2 WHERE col = CAST(4 as SMALLMONEY); +SELECT * FROM Datetime_Operators_tbl2 WHERE col > CAST(4 as SMALLMONEY); +SELECT * FROM Datetime_Operators_tbl2 WHERE col >= CAST(4 as SMALLMONEY); +SELECT * FROM Datetime_Operators_tbl2 WHERE col < CAST(4 as SMALLMONEY); +SELECT * FROM Datetime_Operators_tbl2 WHERE col <= CAST(4 as SMALLMONEY); +SELECT * FROM Datetime_Operators_tbl2 WHERE col != CAST(4 as SMALLMONEY); +GO +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 23:41:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +1900-01-05 23:41:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 00:00:00.0 +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-05 23:41:00.0 +1900-01-01 23:41:00.0 +1900-01-02 00:00:00.0 +~~END~~ + + +SELECT * FROM Datetime_Operators_tbl2 WHERE col = NULL; +SELECT * FROM Datetime_Operators_tbl2 WHERE col > NULL; +SELECT * FROM Datetime_Operators_tbl2 WHERE col >= NULL; +SELECT * FROM Datetime_Operators_tbl2 WHERE col < NULL; +SELECT * FROM Datetime_Operators_tbl2 WHERE col <= NULL; +SELECT * FROM Datetime_Operators_tbl2 WHERE col != NULL; +GO +~~START~~ +smalldatetime +~~END~~ + +~~START~~ +smalldatetime +~~END~~ + +~~START~~ +smalldatetime +~~END~~ + +~~START~~ +smalldatetime +~~END~~ + +~~START~~ +smalldatetime +~~END~~ + +~~START~~ +smalldatetime +~~END~~ + + +DROP TABLE Datetime_Operators_tbl2 +GO + +-- Tables +ALTER TABLE Datetime_tbl1 ADD CONSTRAINT Datetime_constraint1 DEFAULT CAST(0 as BIT) FOR c1 +INSERT INTO Datetime_tbl1 VALUES(DEFAULT) +INSERT INTO Datetime_tbl1 VALUES(CAST(1.5 as BIT)) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM Datetime_tbl1 +GO +~~START~~ +datetime#!#int +1900-01-01 00:00:00.0#!#0 +1900-01-02 00:00:00.0#!#1 +~~END~~ + +DELETE FROM Datetime_tbl1 WHERE c1 IS NOT NULL +GO +~~ROW COUNT: 2~~ + + + +ALTER TABLE Datetime_tbl1 ADD CONSTRAINT Datetime_constraint2 DEFAULT CAST(2 as DECIMAL) FOR c1 +GO +INSERT INTO Datetime_tbl1 VALUES(DEFAULT) +INSERT INTO Datetime_tbl1 VALUES(CAST(1.5 as DECIMAL)) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM Datetime_tbl1 +GO +~~START~~ +datetime#!#int +1900-01-03 00:00:00.0#!#2 +1900-01-03 00:00:00.0#!#2 +~~END~~ + +DELETE FROM Datetime_tbl1 WHERE c1 IS NOT NULL +GO +~~ROW COUNT: 2~~ + + +ALTER TABLE Datetime_tbl1 ADD CONSTRAINT Datetime_constraint3 DEFAULT CAST(2 as NUMERIC) FOR c1 +GO +INSERT INTO Datetime_tbl1 VALUES(DEFAULT) +INSERT INTO Datetime_tbl1 VALUES(CAST(1.5 as NUMERIC)) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM Datetime_tbl1 +GO +~~START~~ +datetime#!#int +1900-01-03 00:00:00.0#!#2 +1900-01-03 00:00:00.0#!#2 +~~END~~ + +DELETE FROM Datetime_tbl1 WHERE c1 IS NOT NULL +GO +~~ROW COUNT: 2~~ + + +ALTER TABLE Datetime_tbl1 ADD CONSTRAINT Datetime_constraint4 DEFAULT CAST(2 as FLOAT) FOR c1 +GO +INSERT INTO Datetime_tbl1 VALUES(DEFAULT) +INSERT INTO Datetime_tbl1 VALUES(CAST(1.5 as FLOAT)) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM Datetime_tbl1 +GO +~~START~~ +datetime#!#int +1900-01-03 00:00:00.0#!#2 +1900-01-02 12:00:00.0#!#1 +~~END~~ + +DELETE FROM Datetime_tbl1 WHERE c1 IS NOT NULL +GO +~~ROW COUNT: 2~~ + + +ALTER TABLE Datetime_tbl1 ADD CONSTRAINT Datetime_constraint5 DEFAULT CAST(2 as REAL) FOR c1 +GO +INSERT INTO Datetime_tbl1 VALUES(DEFAULT) +INSERT INTO Datetime_tbl1 VALUES(CAST(1.5 as REAL)) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM Datetime_tbl1 +GO +~~START~~ +datetime#!#int +1900-01-03 00:00:00.0#!#2 +1900-01-02 12:00:00.0#!#1 +~~END~~ + +DELETE FROM Datetime_tbl1 WHERE c1 IS NOT NULL +GO +~~ROW COUNT: 2~~ + + +ALTER TABLE Datetime_tbl1 ADD CONSTRAINT Datetime_constraint6 DEFAULT CAST(2 as INT) FOR c1 +GO +INSERT INTO Datetime_tbl1 VALUES(DEFAULT) +INSERT INTO Datetime_tbl1 VALUES(CAST(1.5 as INT)) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM Datetime_tbl1 +GO +~~START~~ +datetime#!#int +1900-01-03 00:00:00.0#!#2 +1900-01-02 00:00:00.0#!#1 +~~END~~ + +DELETE FROM Datetime_tbl1 WHERE c1 IS NOT NULL +GO +~~ROW COUNT: 2~~ + + +ALTER TABLE Datetime_tbl1 ADD CONSTRAINT Datetime_constraint7 DEFAULT CAST(2 as BIGINT) FOR c1 +GO +INSERT INTO Datetime_tbl1 VALUES(DEFAULT) +INSERT INTO Datetime_tbl1 VALUES(CAST(1.5 as BIGINT)) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM Datetime_tbl1 +GO +~~START~~ +datetime#!#int +1900-01-03 00:00:00.0#!#2 +1900-01-02 00:00:00.0#!#1 +~~END~~ + +DELETE FROM Datetime_tbl1 WHERE c1 IS NOT NULL +GO +~~ROW COUNT: 2~~ + + +ALTER TABLE Datetime_tbl1 ADD CONSTRAINT Datetime_constraint8 DEFAULT CAST(2 as SMALLINT) FOR c1 +GO +INSERT INTO Datetime_tbl1 VALUES(DEFAULT) +INSERT INTO Datetime_tbl1 VALUES(CAST(1.5 as SMALLINT)) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM Datetime_tbl1 +GO +~~START~~ +datetime#!#int +1900-01-03 00:00:00.0#!#2 +1900-01-02 00:00:00.0#!#1 +~~END~~ + +DELETE FROM Datetime_tbl1 WHERE c1 IS NOT NULL +GO +~~ROW COUNT: 2~~ + + +ALTER TABLE Datetime_tbl1 ADD CONSTRAINT Datetime_constraint9 DEFAULT CAST(2 as TINYINT) FOR c1 +GO +INSERT INTO Datetime_tbl1 VALUES(DEFAULT) +INSERT INTO Datetime_tbl1 VALUES(CAST(1.5 as TINYINT)) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM Datetime_tbl1 +GO +~~START~~ +datetime#!#int +1900-01-03 00:00:00.0#!#2 +1900-01-02 00:00:00.0#!#1 +~~END~~ + +DELETE FROM Datetime_tbl1 WHERE c1 IS NOT NULL +GO +~~ROW COUNT: 2~~ + + +ALTER TABLE Datetime_tbl1 ADD CONSTRAINT Datetime_constraint10 DEFAULT CAST(2 as MONEY) FOR c1 +GO +INSERT INTO Datetime_tbl1 VALUES(DEFAULT) +INSERT INTO Datetime_tbl1 VALUES(CAST(1.5 as MONEY)) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM Datetime_tbl1 +GO +~~START~~ +datetime#!#int +1900-01-03 00:00:00.0#!#2 +1900-01-02 12:00:00.0#!#1 +~~END~~ + +DELETE FROM Datetime_tbl1 WHERE c1 IS NOT NULL +GO +~~ROW COUNT: 2~~ + + +ALTER TABLE Datetime_tbl1 ADD CONSTRAINT Datetime_constraint11 DEFAULT CAST(2 as SMALLMONEY) FOR c1 +GO +INSERT INTO Datetime_tbl1 VALUES(DEFAULT) +INSERT INTO Datetime_tbl1 VALUES(CAST(1.5 as SMALLMONEY)) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM Datetime_tbl1 +GO +~~START~~ +datetime#!#int +1900-01-03 00:00:00.0#!#2 +1900-01-02 12:00:00.0#!#1 +~~END~~ + +DELETE FROM Datetime_tbl1 WHERE c1 IS NOT NULL +GO +~~ROW COUNT: 2~~ + + +ALTER TABLE Datetime_tbl1 ADD CONSTRAINT Datetime_constraint12 DEFAULT NULL FOR c1 +GO +INSERT INTO Datetime_tbl1 VALUES(DEFAULT) +INSERT INTO Datetime_tbl1 VALUES(NULL) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM Datetime_tbl1 +GO +~~START~~ +datetime#!#int +#!# +#!# +~~END~~ + +DELETE FROM Datetime_tbl1 WHERE c1 IS NOT NULL +GO + +DROP TABLE datetime_tbl1 +GO + +ALTER TABLE Datetime_tbl2 ADD CONSTRAINT Datetime_constraint13 DEFAULT CAST(0 as BIT) FOR c1 +INSERT INTO Datetime_tbl2 VALUES(DEFAULT) +INSERT INTO Datetime_tbl2 VALUES(CAST(1.5 as BIT)) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM Datetime_tbl2 +GO +~~START~~ +smalldatetime#!#int +1900-01-01 00:00:00.0#!#0 +1900-01-02 00:00:00.0#!#1 +~~END~~ + +DELETE FROM Datetime_tbl2 WHERE c1 IS NOT NULL +GO +~~ROW COUNT: 2~~ + + + +ALTER TABLE Datetime_tbl2 ADD CONSTRAINT Datetime_constraint14 DEFAULT CAST(2 as DECIMAL) FOR c1 +GO +INSERT INTO Datetime_tbl2 VALUES(DEFAULT) +INSERT INTO Datetime_tbl2 VALUES(CAST(1.5 as DECIMAL)) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM Datetime_tbl2 +GO +~~START~~ +smalldatetime#!#int +1900-01-03 00:00:00.0#!#2 +1900-01-03 00:00:00.0#!#2 +~~END~~ + +DELETE FROM Datetime_tbl2 WHERE c1 IS NOT NULL +GO +~~ROW COUNT: 2~~ + + +ALTER TABLE Datetime_tbl2 ADD CONSTRAINT Datetime_constraint15 DEFAULT CAST(2 as NUMERIC) FOR c1 +GO +INSERT INTO Datetime_tbl2 VALUES(DEFAULT) +INSERT INTO Datetime_tbl2 VALUES(CAST(1.5 as NUMERIC)) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM Datetime_tbl2 +GO +~~START~~ +smalldatetime#!#int +1900-01-03 00:00:00.0#!#2 +1900-01-03 00:00:00.0#!#2 +~~END~~ + +DELETE FROM Datetime_tbl2 WHERE c1 IS NOT NULL +GO +~~ROW COUNT: 2~~ + + +ALTER TABLE Datetime_tbl2 ADD CONSTRAINT Datetime_constrain16 DEFAULT CAST(2 as FLOAT) FOR c1 +GO +INSERT INTO Datetime_tbl2 VALUES(DEFAULT) +INSERT INTO Datetime_tbl2 VALUES(CAST(1.5 as FLOAT)) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM Datetime_tbl2 +GO +~~START~~ +smalldatetime#!#int +1900-01-03 00:00:00.0#!#2 +1900-01-02 12:00:00.0#!#1 +~~END~~ + +DELETE FROM Datetime_tbl2 WHERE c1 IS NOT NULL +GO +~~ROW COUNT: 2~~ + + +ALTER TABLE Datetime_tbl2 ADD CONSTRAINT Datetime_constraint17 DEFAULT CAST(2 as REAL) FOR c1 +GO +INSERT INTO Datetime_tbl2 VALUES(DEFAULT) +INSERT INTO Datetime_tbl2 VALUES(CAST(1.5 as REAL)) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM Datetime_tbl2 +GO +~~START~~ +smalldatetime#!#int +1900-01-03 00:00:00.0#!#2 +1900-01-02 12:00:00.0#!#1 +~~END~~ + +DELETE FROM Datetime_tbl2 WHERE c1 IS NOT NULL +GO +~~ROW COUNT: 2~~ + + +ALTER TABLE Datetime_tbl2 ADD CONSTRAINT Datetime_constraint18 DEFAULT CAST(2 as INT) FOR c1 +GO +INSERT INTO Datetime_tbl2 VALUES(DEFAULT) +INSERT INTO Datetime_tbl2 VALUES(CAST(1.5 as INT)) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM Datetime_tbl2 +GO +~~START~~ +smalldatetime#!#int +1900-01-03 00:00:00.0#!#2 +1900-01-02 00:00:00.0#!#1 +~~END~~ + +DELETE FROM Datetime_tbl2 WHERE c1 IS NOT NULL +GO +~~ROW COUNT: 2~~ + + +ALTER TABLE Datetime_tbl2 ADD CONSTRAINT Datetime_constraint19 DEFAULT CAST(2 as BIGINT) FOR c1 +GO +INSERT INTO Datetime_tbl2 VALUES(DEFAULT) +INSERT INTO Datetime_tbl2 VALUES(CAST(1.5 as BIGINT)) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM Datetime_tbl2 +GO +~~START~~ +smalldatetime#!#int +1900-01-03 00:00:00.0#!#2 +1900-01-02 00:00:00.0#!#1 +~~END~~ + +DELETE FROM Datetime_tbl2 WHERE c1 IS NOT NULL +GO +~~ROW COUNT: 2~~ + + +ALTER TABLE Datetime_tbl2 ADD CONSTRAINT Datetime_constraint20 DEFAULT CAST(2 as SMALLINT) FOR c1 +GO +INSERT INTO Datetime_tbl2 VALUES(DEFAULT) +INSERT INTO Datetime_tbl2 VALUES(CAST(1.5 as SMALLINT)) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM Datetime_tbl2 +GO +~~START~~ +smalldatetime#!#int +1900-01-03 00:00:00.0#!#2 +1900-01-02 00:00:00.0#!#1 +~~END~~ + +DELETE FROM Datetime_tbl2 WHERE c1 IS NOT NULL +GO +~~ROW COUNT: 2~~ + + +ALTER TABLE Datetime_tbl2 ADD CONSTRAINT Datetime_constraint21 DEFAULT CAST(2 as TINYINT) FOR c1 +GO +INSERT INTO Datetime_tbl2 VALUES(DEFAULT) +INSERT INTO Datetime_tbl2 VALUES(CAST(1.5 as TINYINT)) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM Datetime_tbl2 +GO +~~START~~ +smalldatetime#!#int +1900-01-03 00:00:00.0#!#2 +1900-01-02 00:00:00.0#!#1 +~~END~~ + +DELETE FROM Datetime_tbl2 WHERE c1 IS NOT NULL +GO +~~ROW COUNT: 2~~ + + +ALTER TABLE Datetime_tbl2 ADD CONSTRAINT Datetime_constraint22 DEFAULT CAST(2 as MONEY) FOR c1 +GO +INSERT INTO Datetime_tbl2 VALUES(DEFAULT) +INSERT INTO Datetime_tbl2 VALUES(CAST(1.5 as MONEY)) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM Datetime_tbl2 +GO +~~START~~ +smalldatetime#!#int +1900-01-03 00:00:00.0#!#2 +1900-01-02 12:00:00.0#!#1 +~~END~~ + +DELETE FROM Datetime_tbl2 WHERE c1 IS NOT NULL +GO +~~ROW COUNT: 2~~ + + +ALTER TABLE Datetime_tbl2 ADD CONSTRAINT Datetime_constraint23 DEFAULT CAST(2 as SMALLMONEY) FOR c1 +GO +INSERT INTO Datetime_tbl2 VALUES(DEFAULT) +INSERT INTO Datetime_tbl2 VALUES(CAST(1.5 as SMALLMONEY)) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM Datetime_tbl2 +GO +~~START~~ +smalldatetime#!#int +1900-01-03 00:00:00.0#!#2 +1900-01-02 12:00:00.0#!#1 +~~END~~ + +DELETE FROM Datetime_tbl2 WHERE c1 IS NOT NULL +GO +~~ROW COUNT: 2~~ + + +ALTER TABLE Datetime_tbl2 ADD CONSTRAINT Datetime_constraint24 DEFAULT NULL FOR c1 +GO +INSERT INTO Datetime_tbl2 VALUES(DEFAULT) +INSERT INTO Datetime_tbl2 VALUES(NULL) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +SELECT * FROM Datetime_tbl2 +GO +~~START~~ +smalldatetime#!#int +#!# +#!# +~~END~~ + +DELETE FROM Datetime_tbl2 WHERE c1 IS NOT NULL +GO + +DROP TABLE datetime_tbl2 +GO + +-- Procedures +EXEC Datetime_proc2 '1900-01-04 00:00:00', 3.1 +GO +~~START~~ +text +pass +~~END~~ + +EXEC Datetime_proc2 '1900-01-01 00:00:00', 0 +GO +~~START~~ +text +pass +~~END~~ + +EXEC Datetime_proc2 '1900-01-04 00:00:00', 2.5 +GO +~~START~~ +text +pass +~~END~~ + +EXEC Datetime_proc2 '1899-12-29 00:00:00', -2.5 +GO +~~START~~ +text +pass +~~END~~ + +DROP PROCEDURE Datetime_proc2 +GO + +EXEC Datetime_proc3 '1900-01-04 02:24:00', 3.1 +GO +~~START~~ +text +pass +~~END~~ + +EXEC Datetime_proc3 '1900-01-01 00:00:00', 0 +GO +~~START~~ +text +pass +~~END~~ + +EXEC Datetime_proc3 '1900-01-03 12:00:00', 2.5 +GO +~~START~~ +text +pass +~~END~~ + +EXEC Datetime_proc3 '1899-12-29 12:00:00', -2.5 +GO +~~START~~ +text +pass +~~END~~ + +DROP PROCEDURE Datetime_proc3 +GO + +EXEC Datetime_proc4 '1900-01-02 09:36:00', 1.4 +GO +~~START~~ +text +pass +~~END~~ + +EXEC Datetime_proc4 '1900-01-04 02:24:00', 3.1 +GO +~~START~~ +text +pass +~~END~~ + +EXEC Datetime_proc4 '1899-12-28 21:36:00', -3.1 +GO +~~START~~ +text +pass +~~END~~ + +DROP PROCEDURE Datetime_proc4 +GO + +EXEC Datetime_proc5 '1900-01-02 09:35:59.997', 1.4 +GO +~~START~~ +datetime +1900-01-02 09:35:59.997 +~~END~~ + +~~START~~ +datetime +1900-01-02 09:35:59.997 +~~END~~ + +EXEC Datetime_proc5 '1900-01-04 02:23:59.99', 3.1 +GO +~~START~~ +datetime +1900-01-04 02:23:59.99 +~~END~~ + +~~START~~ +datetime +1900-01-04 02:23:59.99 +~~END~~ + +EXEC Datetime_proc5 '1900-01-01 00:00:00.000', 0 +GO +~~START~~ +datetime +1900-01-01 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-01 00:00:00.0 +~~END~~ + +EXEC Datetime_proc5 '1900-01-02 00:00:00.000', 1 +GO +~~START~~ +datetime +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +datetime +1900-01-02 00:00:00.0 +~~END~~ + +EXEC Datetime_proc5 '1899-12-28 21:36:00.007', -3.1 +GO +~~START~~ +datetime +1899-12-28 21:36:00.007 +~~END~~ + +~~START~~ +datetime +1899-12-28 21:36:00.007 +~~END~~ + +DROP PROCEDURE Datetime_proc5 +GO + +EXEC Datetime_proc6 '1900-01-02 00:00:00.000', 1.4 +GO +~~START~~ +text +pass +~~END~~ + +EXEC Datetime_proc6 '1900-01-04 00:00:00.000', 3.1 +GO +~~START~~ +text +pass +~~END~~ + +EXEC Datetime_proc6 '1899-12-30 00:00:00.000', -2.5 +GO +~~START~~ +text +pass +~~END~~ + +DROP PROCEDURE Datetime_proc6 +GO + +EXEC Datetime_proc7 '1900-01-02 00:00:00.000', 1.4 +GO +~~START~~ +text +pass +~~END~~ + +EXEC Datetime_proc7 '1900-01-04 00:00:00.000', 3.1 +GO +~~START~~ +text +pass +~~END~~ + +EXEC Datetime_proc7 '1899-12-30 00:00:00.000', -2.5 +GO +~~START~~ +text +pass +~~END~~ + +DROP PROCEDURE Datetime_proc7 +GO + +EXEC Datetime_proc8 '1900-01-02 00:00:00.000', 1.4 +GO +~~START~~ +text +pass +~~END~~ + +EXEC Datetime_proc8 '1989-09-18 00:00:00.000', 32767 +GO +~~START~~ +text +pass +~~END~~ + +EXEC Datetime_proc8 '1989-09-18 00:00:00.000', 32768 +GO +~~ERROR (Code: 220)~~ + +~~ERROR (Message: smallint out of range)~~ + +DROP PROCEDURE Datetime_proc8 +GO + +EXEC Datetime_proc9 '1900-01-02 00:00:00.000', 1.4 +GO +~~START~~ +text +pass +~~END~~ + +EXEC Datetime_proc9 '1900-09-13 00:00:00.000', 255 +GO +~~START~~ +text +pass +~~END~~ + +EXEC Datetime_proc9 '1900-09-13 00:00:00.000', 256 +GO +~~ERROR (Code: 220)~~ + +~~ERROR (Message: value for domain tinyint violates check constraint "tinyint_check")~~ + +DROP PROCEDURE Datetime_proc9 +GO + +EXEC Datetime_proc10 '1900-01-02 09:36:00.000', 1.4 +GO +~~START~~ +text +pass +~~END~~ + +EXEC Datetime_proc10 '1900-01-04 02:24:00.000', 3.1 +GO +~~START~~ +text +pass +~~END~~ + +EXEC Datetime_proc10 '1899-12-29 12:00:00.000', -2.5 +GO +~~START~~ +text +pass +~~END~~ + +DROP PROCEDURE Datetime_proc10 +GO + +EXEC Datetime_proc11 '1900-01-02 09:36:00.000', 1.4 +GO +~~START~~ +text +pass +~~END~~ + +EXEC Datetime_proc11 '1900-01-04 02:24:00.000', 3.1 +GO +~~START~~ +text +pass +~~END~~ + +EXEC Datetime_proc11 '1899-12-29 12:00:00.000', -2.5 +GO +~~START~~ +text +pass +~~END~~ + + +EXEC Datetime_proc11 '1900-01-02 09:36:00.000', NULL +GO +~~START~~ +text +fail +~~END~~ + +EXEC Datetime_proc11 '1900-01-04 02:24:00.000', NULL +GO +~~START~~ +text +fail +~~END~~ + +DROP PROCEDURE Datetime_proc11 +GO + +EXEC SMALLDatetime_proc2 '1900-01-04 00:00:00', 3.1 +GO +~~START~~ +text +pass +~~END~~ + +EXEC SMALLDatetime_proc2 '1900-01-01 00:00:00', 0 +GO +~~START~~ +text +pass +~~END~~ + +EXEC SMALLDatetime_proc2 '1900-01-04 00:00:00', 2.5 +GO +~~START~~ +text +pass +~~END~~ + +EXEC SMALLDatetime_proc2 '1899-12-29 00:00:00', -2.5 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + +DROP PROCEDURE SMALLDatetime_proc2 +GO + +EXEC SMALLDatetime_proc3 '1900-01-04 02:24:00', 3.1 +GO +~~START~~ +text +pass +~~END~~ + +EXEC SMALLDatetime_proc3 '1900-01-01 00:00:00', 0 +GO +~~START~~ +text +pass +~~END~~ + +EXEC SMALLDatetime_proc3 '1900-01-03 12:00:00', 2.5 +GO +~~START~~ +text +pass +~~END~~ + +DROP PROCEDURE SMALLDatetime_proc3 +GO + +-- Incorrect +EXEC SMALLDatetime_proc4 '1900-01-02 09:36:00', 1.4 +GO +~~START~~ +text +fail +~~END~~ + +EXEC SMALLDatetime_proc4 '1900-01-04 02:24:00', 3.1 +GO +~~START~~ +text +pass +~~END~~ + +EXEC SMALLDatetime_proc4 '1899-12-28 21:36:00', -3.1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + +DROP PROCEDURE SMALLDatetime_proc4 +GO + +EXEC SMALLDatetime_proc5 '1900-01-02 09:35:59.997', 1.4 +GO +~~START~~ +smalldatetime +1900-01-02 09:36:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-02 09:36:00.0 +~~END~~ + +EXEC SMALLDatetime_proc5 '1900-01-04 02:23:59.99', 3.1 +GO +~~START~~ +smalldatetime +1900-01-04 02:24:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-04 02:24:00.0 +~~END~~ + +EXEC SMALLDatetime_proc5 '1900-01-01 00:00:00.000', 0 +GO +~~START~~ +smalldatetime +1900-01-01 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-01 00:00:00.0 +~~END~~ + +EXEC SMALLDatetime_proc5 '1900-01-02 00:00:00.000', 1 +GO +~~START~~ +smalldatetime +1900-01-02 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-02 00:00:00.0 +~~END~~ + +EXEC SMALLDatetime_proc5 '1899-12-28 21:36:00.007', -3.1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + +DROP PROCEDURE SMALLDatetime_proc5 +GO + +EXEC SMALLDatetime_proc6 '1900-01-02 00:00:00.000', 1.4 +GO +~~START~~ +text +pass +~~END~~ + +EXEC SMALLDatetime_proc6 '1900-01-04 00:00:00.000', 3.1 +GO +~~START~~ +text +pass +~~END~~ + +EXEC SMALLDatetime_proc6 '1899-12-30 00:00:00.000', -2.5 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + +DROP PROCEDURE SMALLDatetime_proc6 +GO + +EXEC SMALLDatetime_proc7 '1900-01-02 00:00:00.000', 1.4 +GO +~~START~~ +text +pass +~~END~~ + +EXEC SMALLDatetime_proc7 '1900-01-04 00:00:00.000', 3.1 +GO +~~START~~ +text +pass +~~END~~ + +EXEC SMALLDatetime_proc7 '1899-12-30 00:00:00.000', -2.5 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + +DROP PROCEDURE SMALLDatetime_proc7 +GO + +EXEC SMALLDatetime_proc8 '1900-01-02 00:00:00.000', 1.4 +GO +~~START~~ +text +pass +~~END~~ + +EXEC SMALLDatetime_proc8 '1989-09-18 00:00:00.000', 32767 +GO +~~START~~ +text +pass +~~END~~ + +EXEC SMALLDatetime_proc8 '1989-09-18 00:00:00.000', 32768 +GO +~~ERROR (Code: 220)~~ + +~~ERROR (Message: smallint out of range)~~ + +DROP PROCEDURE SMALLDatetime_proc8 +GO + +EXEC SMALLDatetime_proc9 '1900-01-02 00:00:00.000', 1.4 +GO +~~START~~ +text +pass +~~END~~ + +EXEC SMALLDatetime_proc9 '1900-09-13 00:00:00.000', 255 +GO +~~START~~ +text +pass +~~END~~ + +EXEC SMALLDatetime_proc9 '1900-09-13 00:00:00.000', 256 +GO +~~ERROR (Code: 220)~~ + +~~ERROR (Message: value for domain tinyint violates check constraint "tinyint_check")~~ + +DROP PROCEDURE SMALLDatetime_proc9 +GO + +-- Incorrect +EXEC SMALLDatetime_proc10 '1900-01-02 09:36:00.000', 1.4 +GO +~~START~~ +text +fail +~~END~~ + +EXEC SMALLDatetime_proc10 '1900-01-04 02:24:00.000', 3.1 +GO +~~START~~ +text +pass +~~END~~ + +EXEC SMALLDatetime_proc10 '1899-12-29 12:00:00.000', -2.5 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + +DROP PROCEDURE SMALLDatetime_proc10 +GO + + +--Incorrect +EXEC SMALLDatetime_proc11 '1900-01-02 09:36:00.000', 1.4 +GO +~~START~~ +text +fail +~~END~~ + +EXEC SMALLDatetime_proc11 '1900-01-04 02:24:00.000', 3.1 +GO +~~START~~ +text +pass +~~END~~ + +EXEC SMALLDatetime_proc11 '1899-12-29 12:00:00.000', -2.5 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + + +EXEC SMALLDatetime_proc11 '1900-01-02 09:36:00.000', NULL +GO +~~START~~ +text +fail +~~END~~ + +EXEC SMALLDatetime_proc11 '1900-01-04 02:24:00.000', NULL +GO +~~START~~ +text +fail +~~END~~ + +DROP PROCEDURE SMALLDatetime_proc11 +GO + +-- Union +SELECT datetimetype FROM Datetime_target_type_table UNION SELECT bittype FROM Datetime_source_type_table +GO +~~START~~ +datetime +1900-01-01 00:00:00.0 +2012-06-18 10:34:09.0 +~~END~~ + + +SELECT datetimetype FROM Datetime_target_type_table UNION SELECT decimaltype FROM Datetime_source_type_table +GO +~~START~~ +datetime +2012-06-18 10:34:09.0 +1900-01-03 00:00:00.0 +~~END~~ + + +SELECT datetimetype FROM Datetime_target_type_table UNION SELECT numerictype FROM Datetime_source_type_table +GO +~~START~~ +datetime +2012-06-18 10:34:09.0 +1900-01-03 00:00:00.0 +~~END~~ + + +SELECT datetimetype FROM Datetime_target_type_table UNION SELECT floattype FROM Datetime_source_type_table +GO +~~START~~ +datetime +2012-06-18 10:34:09.0 +1900-01-04 02:24:00.0 +~~END~~ + + +SELECT datetimetype FROM Datetime_target_type_table UNION SELECT realtype FROM Datetime_source_type_table +GO +~~START~~ +datetime +2012-06-18 10:34:09.0 +1900-01-05 04:47:59.983 +~~END~~ + + +SELECT datetimetype FROM Datetime_target_type_table UNION SELECT inttype FROM Datetime_source_type_table +GO +~~START~~ +datetime +1900-01-06 00:00:00.0 +2012-06-18 10:34:09.0 +~~END~~ + + +SELECT datetimetype FROM Datetime_target_type_table UNION SELECT biginttype FROM Datetime_source_type_table +GO +~~START~~ +datetime +1900-01-07 00:00:00.0 +2012-06-18 10:34:09.0 +~~END~~ + + +SELECT datetimetype FROM Datetime_target_type_table UNION SELECT smallinttype FROM Datetime_source_type_table +GO +~~START~~ +datetime +1900-01-08 00:00:00.0 +2012-06-18 10:34:09.0 +~~END~~ + + +SELECT datetimetype FROM Datetime_target_type_table UNION SELECT tinyinttype FROM Datetime_source_type_table +GO +~~START~~ +datetime +1900-01-09 00:00:00.0 +2012-06-18 10:34:09.0 +~~END~~ + + +SELECT datetimetype FROM Datetime_target_type_table UNION SELECT moneytype FROM Datetime_source_type_table +GO +~~START~~ +datetime +1900-01-10 00:00:00.0 +2012-06-18 10:34:09.0 +~~END~~ + + +SELECT datetimetype FROM Datetime_target_type_table UNION SELECT smallmonettype FROM Datetime_source_type_table +GO +~~START~~ +datetime +1900-01-11 00:00:00.0 +2012-06-18 10:34:09.0 +~~END~~ + + +SELECT datetimetype FROM Datetime_target_type_table UNION SELECT nulltype FROM Datetime_source_type_table +GO +~~START~~ +datetime + +2012-06-18 10:34:09.0 +~~END~~ + + +SELECT smalldatetimetype FROM Datetime_target_type_table UNION SELECT bittype FROM Datetime_source_type_table +GO +~~START~~ +smalldatetime +1900-01-01 00:00:00.0 +2018-07-24 06:31:00.0 +~~END~~ + + +SELECT smalldatetimetype FROM Datetime_target_type_table UNION SELECT decimaltype FROM Datetime_source_type_table +GO +~~START~~ +smalldatetime +2018-07-24 06:31:00.0 +1900-01-03 00:00:00.0 +~~END~~ + + +SELECT smalldatetimetype FROM Datetime_target_type_table UNION SELECT numerictype FROM Datetime_source_type_table +GO +~~START~~ +smalldatetime +2018-07-24 06:31:00.0 +1900-01-03 00:00:00.0 +~~END~~ + + +SELECT smalldatetimetype FROM Datetime_target_type_table UNION SELECT floattype FROM Datetime_source_type_table +GO +~~START~~ +smalldatetime +2018-07-24 06:31:00.0 +1900-01-04 02:24:00.0 +~~END~~ + + +SELECT smalldatetimetype FROM Datetime_target_type_table UNION SELECT realtype FROM Datetime_source_type_table +GO +~~START~~ +smalldatetime +2018-07-24 06:31:00.0 +1900-01-05 04:48:00.0 +~~END~~ + + +SELECT smalldatetimetype FROM Datetime_target_type_table UNION SELECT inttype FROM Datetime_source_type_table +GO +~~START~~ +smalldatetime +1900-01-06 00:00:00.0 +2018-07-24 06:31:00.0 +~~END~~ + + +SELECT smalldatetimetype FROM Datetime_target_type_table UNION SELECT biginttype FROM Datetime_source_type_table +GO +~~START~~ +smalldatetime +1900-01-07 00:00:00.0 +2018-07-24 06:31:00.0 +~~END~~ + + +SELECT smalldatetimetype FROM Datetime_target_type_table UNION SELECT smallinttype FROM Datetime_source_type_table +GO +~~START~~ +smalldatetime +1900-01-08 00:00:00.0 +2018-07-24 06:31:00.0 +~~END~~ + + +SELECT smalldatetimetype FROM Datetime_target_type_table UNION SELECT tinyinttype FROM Datetime_source_type_table +GO +~~START~~ +smalldatetime +1900-01-09 00:00:00.0 +2018-07-24 06:31:00.0 +~~END~~ + + +SELECT smalldatetimetype FROM Datetime_target_type_table UNION SELECT moneytype FROM Datetime_source_type_table +GO +~~START~~ +smalldatetime +1900-01-10 00:00:00.0 +2018-07-24 06:31:00.0 +~~END~~ + + +SELECT smalldatetimetype FROM Datetime_target_type_table UNION SELECT smallmonettype FROM Datetime_source_type_table +GO +~~START~~ +smalldatetime +1900-01-11 00:00:00.0 +2018-07-24 06:31:00.0 +~~END~~ + + +SELECT smalldatetimetype FROM Datetime_target_type_table UNION SELECT nulltype FROM Datetime_source_type_table +GO +~~START~~ +smalldatetime + +2018-07-24 06:31:00.0 +~~END~~ + + +DROP TABLE Datetime_target_type_table +GO + +DROP TABLE Datetime_source_type_table +GO diff --git a/test/JDBC/expected/babel_function.out b/test/JDBC/expected/babel_function.out index aa012b1833..856f181042 100644 --- a/test/JDBC/expected/babel_function.out +++ b/test/JDBC/expected/babel_function.out @@ -334,7 +334,7 @@ select TRY_CONVERT(datetime, 123); GO ~~START~~ datetime - +1900-05-04 00:00:00.0 ~~END~~ select TRY_CONVERT(money, 'asdf'); diff --git a/test/JDBC/input/datatypes/TestDatetime-numeric-dateaddfunction-vu-prepare.sql b/test/JDBC/input/datatypes/TestDatetime-numeric-dateaddfunction-vu-prepare.sql new file mode 100644 index 0000000000..10f6f41e0f --- /dev/null +++ b/test/JDBC/input/datatypes/TestDatetime-numeric-dateaddfunction-vu-prepare.sql @@ -0,0 +1,273 @@ +CREATE VIEW Datetime_view3 +AS( + SELECT + CONVERT(DATETIME, CAST(2.5 as BIT)) as re1, + CONVERT(DATETIME, CAST(2.5 as DECIMAL))as re2, + CONVERT(DATETIME, CAST(2.5 as NUMERIC(30,8)))as re3, + CONVERT(DATETIME, CAST(2.5 as FLOAT))as re4, + CONVERT(DATETIME, CAST(2.5 as REAL))as re5, + CONVERT(DATETIME, CAST(2.5 as INT))as re6, + CONVERT(DATETIME, CAST(2.5 as BIGINT))as re7, + CONVERT(DATETIME, CAST(2.5 as SMALLINT))as re8, + CONVERT(DATETIME, CAST(2.5 as TINYINT))as re9, + CONVERT(DATETIME, CAST(2.5 as MONEY))as re10, + CONVERT(DATETIME, CAST(2.5 as SMALLMONEY))as re11, + CONVERT(DATETIME, CAST(-2.5 as BIT)) as re12, + CONVERT(DATETIME, CAST(-2.5 as DECIMAL))as re13, + CONVERT(DATETIME, CAST(-2.5 as NUMERIC(30,8)))as re14, + CONVERT(DATETIME, CAST(-2.5 as FLOAT))as re15, + CONVERT(DATETIME, CAST(-2.5 as REAL))as re16, + CONVERT(DATETIME, CAST(-2.5 as INT))as re17, + CONVERT(DATETIME, CAST(-2.5 as BIGINT))as re18, + CONVERT(DATETIME, CAST(-2.5 as SMALLINT))as re19, + CONVERT(DATETIME, CAST(-2.5 as MONEY))as re20, + CONVERT(DATETIME, CAST(-2.5 as SMALLMONEY))as re21, + CONVERT(DATETIME, NULL)as res22 +); +GO + +CREATE VIEW Datetime_view4 +AS( + SELECT + CONVERT(SMALLDATETIME, CAST(2.5 as BIT)) as re1, + CONVERT(SMALLDATETIME, CAST(2.5 as DECIMAL)) as re2, + CONVERT(SMALLDATETIME, CAST(2.5 as NUMERIC(30,8))) as re3, + CONVERT(SMALLDATETIME, CAST(2.5 as FLOAT)) as re4, + CONVERT(SMALLDATETIME, CAST(2.5 as REAL)) as re5, + CONVERT(SMALLDATETIME, CAST(2.5 as INT)) as re6, + CONVERT(SMALLDATETIME, CAST(2.5 as BIGINT)) as re7, + CONVERT(SMALLDATETIME, CAST(2.5 as SMALLINT)) as re8, + CONVERT(SMALLDATETIME, CAST(2.5 as TINYINT)) as re9, + CONVERT(SMALLDATETIME, CAST(2.5 as MONEY)) as re10, + CONVERT(SMALLDATETIME, CAST(2.5 as SMALLMONEY)) as re11, + CONVERT(SMALLDATETIME, CAST(-2.5 as BIT)) as re12, + CONVERT(SMALLDATETIME, NULL) as res13 +); +GO + +-- Should all fail +SELECT CONVERT(SMALLDATETIME, CAST(-2.5 as DECIMAL)) +GO +SELECT CONVERT(SMALLDATETIME, CAST(-2.5 as NUMERIC(30,8))) +GO +SELECT CONVERT(SMALLDATETIME, CAST(-2.5 as FLOAT)) +GO +SELECT CONVERT(SMALLDATETIME, CAST(-2.5 as REAL)) +GO +SELECT CONVERT(SMALLDATETIME, CAST(-2.5 as INT)) +GO +SELECT CONVERT(SMALLDATETIME, CAST(-2.5 as BIGINT)) +GO +SELECT CONVERT(SMALLDATETIME, CAST(-2.5 as SMALLINT)) +GO +SELECT CONVERT(SMALLDATETIME, CAST(-2.5 as MONEY)) +GO +SELECT CONVERT(SMALLDATETIME, CAST(-2.5 as SMALLMONEY)) +GO + + +CREATE VIEW Datetime_view5 as ( + SELECT + DATEADD(minute, CAST(1 as DECIMAL), CAST(2.5 as DECIMAL)) as re1, + DATEADD(minute, CAST(1 as NUMERIC(30,8)), CAST(2.5 as NUMERIC(30,8))) as re2, + DATEADD(minute, CAST(1 as FLOAT), CAST(2.5 as FLOAT)) as re3, + DATEADD(minute, CAST(1 as REAL), CAST(2.5 as REAL)) as re4, + DATEADD(minute, CAST(1 as INT), CAST(2.5 as INT)) as re5, + DATEADD(minute, CAST(1 as BIGINT), CAST(2.5 as BIGINT)) as re6, + DATEADD(minute, CAST(1 as SMALLINT), CAST(2.5 as SMALLINT)) as re7, + DATEADD(minute, CAST(1 as TINYINT), CAST(2.5 as TINYINT)) as re8, + DATEADD(minute, CAST(1 as MONEY), CAST(2.5 as MONEY)) as re9, + DATEADD(minute, CAST(1 as SMALLMONEY), CAST(2.5 as SMALLMONEY)) as re10, + DATEADD(minute, CAST(-1 as DECIMAL), CAST(-2.5 as DECIMAL)) as re11, + DATEADD(minute, CAST(-1 as NUMERIC(30,8)), CAST(-2.5 as NUMERIC(30,8))) as re12, + DATEADD(minute, CAST(-1 as FLOAT), CAST(-2.5 as FLOAT)) as re13, + DATEADD(minute, CAST(-1 as REAL), CAST(-2.5 as REAL)) as re14, + DATEADD(minute, CAST(-1 as INT), CAST(-2.5 as INT)) as re15, + DATEADD(minute, CAST(-1 as BIGINT), CAST(-2.5 as BIGINT)) as re16, + DATEADD(minute, CAST(-1 as SMALLINT), CAST(-2.5 as SMALLINT)) as re17, + DATEADD(minute, CAST(-1 as MONEY), CAST(-2.5 as MONEY)) as re18, + DATEADD(minute, CAST(-1 as SMALLMONEY), CAST(-2.5 as SMALLMONEY)) as re19 +); +GO + +CREATE PROCEDURE Datetime_proc1 (@a DATETIME, @b BIT) AS +BEGIN + DECLARE @c DATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE SMALLDatetime_proc1 (@a SMALLDATETIME, @b BIT) AS +BEGIN + DECLARE @c SMALLDATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE VIEW dateadd_numeric_representation_helper_year_view AS +SELECT +dateadd_numeric_representation_helper('year',1,cast(1.5 as BIGINT)) AS BIT_INT, +dateadd_numeric_representation_helper('year',1,cast(1.5 as INT)) AS REG_INT, +dateadd_numeric_representation_helper('year',1,cast(1.5 as SMALLINT)) AS SMALL_INT, +dateadd_numeric_representation_helper('year',1,cast(1.5 as TINYINT)) AS TINY_INT, +dateadd_numeric_representation_helper('year',1,cast(1.5 as NUMERIC)) AS NUMERIC_REP, +dateadd_numeric_representation_helper('year',1,cast(1.5 as FLOAT)) AS FLOAT_REP, +dateadd_numeric_representation_helper('year',1,cast(1.5 as REAL)) AS REAL_REP, +dateadd_numeric_representation_helper('year',1,cast(1.5 as MONEY)) AS MONEY_REP, +dateadd_numeric_representation_helper('year',1,cast(1.5 as SMALLMONEY)) AS SMALLMONEY_REP +GO + +CREATE VIEW dateadd_numeric_representation_helper_quarter_view AS +SELECT +dateadd_numeric_representation_helper('quarter',1,cast(1.5 as BIGINT)) AS BIT_INT, +dateadd_numeric_representation_helper('quarter',1,cast(1.5 as INT)) AS REG_INT, +dateadd_numeric_representation_helper('quarter',1,cast(1.5 as SMALLINT)) AS SMALL_INT, +dateadd_numeric_representation_helper('quarter',1,cast(1.5 as TINYINT)) AS TINY_INT, +dateadd_numeric_representation_helper('quarter',1,cast(1.5 as NUMERIC)) AS NUMERIC_REP, +dateadd_numeric_representation_helper('quarter',1,cast(1.5 as FLOAT)) AS FLOAT_REP, +dateadd_numeric_representation_helper('quarter',1,cast(1.5 as REAL)) AS REAL_REP, +dateadd_numeric_representation_helper('quarter',1,cast(1.5 as MONEY)) AS MONEY_REP, +dateadd_numeric_representation_helper('quarter',1,cast(1.5 as SMALLMONEY)) AS SMALLMONEY_REP +GO + +CREATE VIEW dateadd_numeric_representation_helper_month_view AS +SELECT +dateadd_numeric_representation_helper('month',1,cast(1.5 as BIGINT)) AS BIT_INT, +dateadd_numeric_representation_helper('month',1,cast(1.5 as INT)) AS REG_INT, +dateadd_numeric_representation_helper('month',1,cast(1.5 as SMALLINT)) AS SMALL_INT, +dateadd_numeric_representation_helper('month',1,cast(1.5 as TINYINT)) AS TINY_INT, +dateadd_numeric_representation_helper('month',1,cast(1.5 as NUMERIC)) AS NUMERIC_REP, +dateadd_numeric_representation_helper('month',1,cast(1.5 as FLOAT)) AS FLOAT_REP, +dateadd_numeric_representation_helper('month',1,cast(1.5 as REAL)) AS REAL_REP, +dateadd_numeric_representation_helper('month',1,cast(1.5 as MONEY)) AS MONEY_REP, +dateadd_numeric_representation_helper('month',1,cast(1.5 as SMALLMONEY)) AS SMALLMONEY_REP +GO + +CREATE VIEW dateadd_numeric_representation_helper_dayofyear_view AS +SELECT +dateadd_numeric_representation_helper('dayofyear',1,cast(1.5 as BIGINT)) AS BIT_INT, +dateadd_numeric_representation_helper('dayofyear',1,cast(1.5 as INT)) AS REG_INT, +dateadd_numeric_representation_helper('dayofyear',1,cast(1.5 as SMALLINT)) AS SMALL_INT, +dateadd_numeric_representation_helper('dayofyear',1,cast(1.5 as TINYINT)) AS TINY_INT, +dateadd_numeric_representation_helper('dayofyear',1,cast(1.5 as NUMERIC)) AS NUMERIC_REP, +dateadd_numeric_representation_helper('dayofyear',1,cast(1.5 as FLOAT)) AS FLOAT_REP, +dateadd_numeric_representation_helper('dayofyear',1,cast(1.5 as REAL)) AS REAL_REP, +dateadd_numeric_representation_helper('dayofyear',1,cast(1.5 as MONEY)) AS MONEY_REP, +dateadd_numeric_representation_helper('dayofyear',1,cast(1.5 as SMALLMONEY)) AS SMALLMONEY_REP +GO + +CREATE VIEW dateadd_numeric_representation_helper_day_view AS +SELECT +dateadd_numeric_representation_helper('day',1,cast(1.5 as BIGINT)) AS BIT_INT, +dateadd_numeric_representation_helper('day',1,cast(1.5 as INT)) AS REG_INT, +dateadd_numeric_representation_helper('day',1,cast(1.5 as SMALLINT)) AS SMALL_INT, +dateadd_numeric_representation_helper('day',1,cast(1.5 as TINYINT)) AS TINY_INT, +dateadd_numeric_representation_helper('day',1,cast(1.5 as NUMERIC)) AS NUMERIC_REP, +dateadd_numeric_representation_helper('day',1,cast(1.5 as FLOAT)) AS FLOAT_REP, +dateadd_numeric_representation_helper('day',1,cast(1.5 as REAL)) AS REAL_REP, +dateadd_numeric_representation_helper('day',1,cast(1.5 as MONEY)) AS MONEY_REP, +dateadd_numeric_representation_helper('day',1,cast(1.5 as SMALLMONEY)) AS SMALLMONEY_REP +GO + +CREATE VIEW dateadd_numeric_representation_helper_week_view AS +SELECT +dateadd_numeric_representation_helper('week',1,cast(1.5 as BIGINT)) AS BIT_INT, +dateadd_numeric_representation_helper('week',1,cast(1.5 as INT)) AS REG_INT, +dateadd_numeric_representation_helper('week',1,cast(1.5 as SMALLINT)) AS SMALL_INT, +dateadd_numeric_representation_helper('week',1,cast(1.5 as TINYINT)) AS TINY_INT, +dateadd_numeric_representation_helper('week',1,cast(1.5 as NUMERIC)) AS NUMERIC_REP, +dateadd_numeric_representation_helper('week',1,cast(1.5 as FLOAT)) AS FLOAT_REP, +dateadd_numeric_representation_helper('week',1,cast(1.5 as REAL)) AS REAL_REP, +dateadd_numeric_representation_helper('week',1,cast(1.5 as MONEY)) AS MONEY_REP, +dateadd_numeric_representation_helper('week',1,cast(1.5 as SMALLMONEY)) AS SMALLMONEY_REP +GO + +CREATE VIEW dateadd_numeric_representation_helper_weekday_view AS +SELECT +dateadd_numeric_representation_helper('weekday',1,cast(1.5 as BIGINT)) AS BIT_INT, +dateadd_numeric_representation_helper('weekday',1,cast(1.5 as INT)) AS REG_INT, +dateadd_numeric_representation_helper('weekday',1,cast(1.5 as SMALLINT)) AS SMALL_INT, +dateadd_numeric_representation_helper('weekday',1,cast(1.5 as TINYINT)) AS TINY_INT, +dateadd_numeric_representation_helper('weekday',1,cast(1.5 as NUMERIC)) AS NUMERIC_REP, +dateadd_numeric_representation_helper('weekday',1,cast(1.5 as FLOAT)) AS FLOAT_REP, +dateadd_numeric_representation_helper('weekday',1,cast(1.5 as REAL)) AS REAL_REP, +dateadd_numeric_representation_helper('weekday',1,cast(1.5 as MONEY)) AS MONEY_REP, +dateadd_numeric_representation_helper('weekday',1,cast(1.5 as SMALLMONEY)) AS SMALLMONEY_REP +GO + +CREATE VIEW dateadd_numeric_representation_helper_hour_view AS +SELECT +dateadd_numeric_representation_helper('hour',1,cast(1.5 as BIGINT)) AS BIT_INT, +dateadd_numeric_representation_helper('hour',1,cast(1.5 as INT)) AS REG_INT, +dateadd_numeric_representation_helper('hour',1,cast(1.5 as SMALLINT)) AS SMALL_INT, +dateadd_numeric_representation_helper('hour',1,cast(1.5 as TINYINT)) AS TINY_INT, +dateadd_numeric_representation_helper('hour',1,cast(1.5 as NUMERIC)) AS NUMERIC_REP, +dateadd_numeric_representation_helper('hour',1,cast(1.5 as FLOAT)) AS FLOAT_REP, +dateadd_numeric_representation_helper('hour',1,cast(1.5 as REAL)) AS REAL_REP, +dateadd_numeric_representation_helper('hour',1,cast(1.5 as MONEY)) AS MONEY_REP, +dateadd_numeric_representation_helper('hour',1,cast(1.5 as SMALLMONEY)) AS SMALLMONEY_REP +GO + +CREATE VIEW dateadd_numeric_representation_helper_minute_view AS +SELECT +dateadd_numeric_representation_helper('minute',1,cast(1.5 as BIGINT)) AS BIT_INT, +dateadd_numeric_representation_helper('minute',1,cast(1.5 as INT)) AS REG_INT, +dateadd_numeric_representation_helper('minute',1,cast(1.5 as SMALLINT)) AS SMALL_INT, +dateadd_numeric_representation_helper('minute',1,cast(1.5 as TINYINT)) AS TINY_INT, +dateadd_numeric_representation_helper('minute',1,cast(1.5 as NUMERIC)) AS NUMERIC_REP, +dateadd_numeric_representation_helper('minute',1,cast(1.5 as FLOAT)) AS FLOAT_REP, +dateadd_numeric_representation_helper('minute',1,cast(1.5 as REAL)) AS REAL_REP, +dateadd_numeric_representation_helper('minute',1,cast(1.5 as MONEY)) AS MONEY_REP, +dateadd_numeric_representation_helper('minute',1,cast(1.5 as SMALLMONEY)) AS SMALLMONEY_REP +GO + +CREATE VIEW dateadd_numeric_representation_helper_second_view AS +SELECT +dateadd_numeric_representation_helper('second',1,cast(1.5 as BIGINT)) AS BIT_INT, +dateadd_numeric_representation_helper('second',1,cast(1.5 as INT)) AS REG_INT, +dateadd_numeric_representation_helper('second',1,cast(1.5 as SMALLINT)) AS SMALL_INT, +dateadd_numeric_representation_helper('second',1,cast(1.5 as TINYINT)) AS TINY_INT, +dateadd_numeric_representation_helper('second',1,cast(1.5 as NUMERIC)) AS NUMERIC_REP, +dateadd_numeric_representation_helper('second',1,cast(1.5 as FLOAT)) AS FLOAT_REP, +dateadd_numeric_representation_helper('second',1,cast(1.5 as REAL)) AS REAL_REP, +dateadd_numeric_representation_helper('second',1,cast(1.5 as MONEY)) AS MONEY_REP, +dateadd_numeric_representation_helper('second',1,cast(1.5 as SMALLMONEY)) AS SMALLMONEY_REP +GO + +CREATE VIEW dateadd_numeric_representation_helper_millisecond_view AS +SELECT +dateadd_numeric_representation_helper('millisecond',1,cast(1.5 as BIGINT)) AS BIT_INT, +dateadd_numeric_representation_helper('millisecond',1,cast(1.5 as INT)) AS REG_INT, +dateadd_numeric_representation_helper('millisecond',1,cast(1.5 as SMALLINT)) AS SMALL_INT, +dateadd_numeric_representation_helper('millisecond',1,cast(1.5 as TINYINT)) AS TINY_INT, +dateadd_numeric_representation_helper('millisecond',1,cast(1.5 as NUMERIC)) AS NUMERIC_REP, +dateadd_numeric_representation_helper('millisecond',1,cast(1.5 as FLOAT)) AS FLOAT_REP, +dateadd_numeric_representation_helper('millisecond',1,cast(1.5 as REAL)) AS REAL_REP, +dateadd_numeric_representation_helper('millisecond',1,cast(1.5 as MONEY)) AS MONEY_REP, +dateadd_numeric_representation_helper('millisecond',1,cast(1.5 as SMALLMONEY)) AS SMALLMONEY_REP +GO + + +CREATE VIEW dateadd_view_1 AS +SELECT * FROM sys.dateadd('year',1,cast(1.5 as REAL)) +GO + +CREATE VIEW dateadd_view_2 AS +SELECT * FROM sys.dateadd('year',1,cast(1.5 as NUMERIC(30,8))) +GO + +CREATE VIEW dateadd_view_3 AS +SELECT * FROM sys.dateadd('year',1,cast(1.5 as DECIMAL)) +GO + +CREATE VIEW dateadd_view_4 AS +SELECT * FROM sys.dateadd('year',1,cast(1 as BIT)) +GO + +CREATE VIEW dateadd_view_5 AS +SELECT * FROM sys.dateadd('year',1,cast(1.5 as FLOAT)) +GO + +CREATE VIEW dateadd_view_6 AS +SELECT * FROM sys.dateadd('year',1,cast(1.5 as FLOAT)) +GO diff --git a/test/JDBC/input/datatypes/TestDatetime-numeric-dateaddfunction-vu-verify.sql b/test/JDBC/input/datatypes/TestDatetime-numeric-dateaddfunction-vu-verify.sql new file mode 100644 index 0000000000..d2c26c069d --- /dev/null +++ b/test/JDBC/input/datatypes/TestDatetime-numeric-dateaddfunction-vu-verify.sql @@ -0,0 +1,149 @@ +-- output from SQL Server : +-- 1900-01-02 00:00:00.000 1900-01-04 00:00:00.000 1900-01-03 12:00:00.000 1900-01-03 12:00:00.000 1900-01-03 12:00:00.000 1900-01-03 00:00:00.000 1900-01-03 00:00:00.000 1900-01-03 00:00:00.000 1900-01-03 00:00:00.000 1900-01-03 12:00:00.000 1900-01-03 12:00:00.000 1900-01-02 00:00:00.000 1899-12-29 00:00:00.000 1899-12-29 12:00:00.000 1899-12-29 12:00:00.000 1899-12-29 12:00:00.000 1899-12-30 00:00:00.000 1899-12-30 00:00:00.000 1899-12-30 00:00:00.000 1899-12-29 12:00:00.000 1899-12-29 12:00:00.000 null +SELECT * FROM Datetime_view3 +GO +DROP VIEW Datetime_view3 +GO + +-- output from SQL Server : +-- 1900-01-02 00:00 1900-01-04 00:00 1900-01-03 12:00 1900-01-03 12:00 1900-01-03 12:00 1900-01-03 00:00 1900-01-03 00:00 1900-01-03 00:00 1900-01-03 00:00 1900-01-03 12:00 1900-01-03 12:00 1900-01-02 00:00 null +SELECT * FROM Datetime_view4 +GO +DROP VIEW Datetime_view4 +GO + +-- Should throw ERROR : Argument data type bit is invalid for argument 2 of dateadd function. +SELECT DATEADD(minute, CAST(1 as BIT), CAST(2.5 as BIT)) +GO + +-- output from SQL Server : +-- 1900-01-04 00:01:00.000 1900-01-03 12:01:00.000 1900-01-03 12:01:00.000 1900-01-03 12:01:00.000 1900-01-03 00:01:00.000 1900-01-03 00:01:00.000 1900-01-03 00:01:00.000 1900-01-03 00:01:00.000 1900-01-03 12:01:00.000 1900-01-03 12:01:00.000 1899-12-28 23:59:00.000 1899-12-29 11:59:00.000 1899-12-29 11:59:00.000 1899-12-29 11:59:00.000 1899-12-29 23:59:00.000 1899-12-29 23:59:00.000 1899-12-29 23:59:00.000 1899-12-29 11:59:00.000 1899-12-29 11:59:00.000 +SELECT * FROM Datetime_view5 +GO +DROP VIEW Datetime_view5 +GO + +-- Procedures +EXEC Datetime_proc1 '1900-01-02 00:00:00', 3.1 +GO +EXEC Datetime_proc1 '1900-01-02 00:00:00', 2 +GO +EXEC Datetime_proc1 '1900-01-01 00:00:00', 0 +GO +EXEC Datetime_proc1 '1900-01-02 00:00:00', -3.1 +GO +DROP PROCEDURE Datetime_proc1 +GO + +EXEC SMALLDatetime_proc1 '1900-01-02 00:00:00', 3.1 +GO +EXEC SMALLDatetime_proc1 '1900-01-02 00:00:00', 2 +GO +EXEC SMALLDatetime_proc1 '1900-01-01 00:00:00', 0 +GO +EXEC SMALLDatetime_proc1 '1900-01-02 00:00:00', -3.1 +GO +DROP PROCEDURE SMALLDatetime_proc1 +GO + +SELECT * FROM dateadd_numeric_representation_helper_year_view +GO + +DROP VIEW dateadd_numeric_representation_helper_year_view +GO + +SELECT * FROM dateadd_numeric_representation_helper_quarter_view +GO + +DROP VIEW dateadd_numeric_representation_helper_quarter_view +GO + +SELECT * FROM dateadd_numeric_representation_helper_month_view +GO + +DROP VIEW dateadd_numeric_representation_helper_month_view +GO + +SELECT * FROM dateadd_numeric_representation_helper_dayofyear_view +GO + +DROP VIEW dateadd_numeric_representation_helper_dayofyear_view +GO + +SELECT * FROM dateadd_numeric_representation_helper_day_view +GO + +DROP VIEW dateadd_numeric_representation_helper_day_view +GO + +SELECT * FROM dateadd_numeric_representation_helper_week_view +GO + +DROP VIEW dateadd_numeric_representation_helper_week_view +GO + +SELECT * FROM dateadd_numeric_representation_helper_weekday_view +GO + +DROP VIEW dateadd_numeric_representation_helper_weekday_view +GO + +SELECT * FROM dateadd_numeric_representation_helper_hour_view +GO + +DROP VIEW dateadd_numeric_representation_helper_hour_view +GO + +SELECT * FROM dateadd_numeric_representation_helper_minute_view +GO + +DROP VIEW dateadd_numeric_representation_helper_minute_view +GO + +SELECT * FROM dateadd_numeric_representation_helper_second_view +GO + +DROP VIEW dateadd_numeric_representation_helper_second_view +GO + +SELECT * FROM dateadd_numeric_representation_helper_millisecond_view +GO + +DROP VIEW dateadd_numeric_representation_helper_millisecond_view +GO + +SELECT * FROM dateadd_view_1 +GO + +DROP VIEW dateadd_view_1 +GO + +SELECT * FROM dateadd_view_2 +GO + +DROP VIEW dateadd_view_2 +GO + +SELECT * FROM dateadd_view_3 +GO + +DROP VIEW dateadd_view_3 +GO + +SELECT * FROM dateadd_view_4 +GO + +DROP VIEW dateadd_view_4 +GO + +SELECT * FROM dateadd_view_5 +GO + +DROP VIEW dateadd_view_5 +GO + +SELECT * FROM dateadd_view_6 +GO + +DROP VIEW dateadd_view_6 +GO diff --git a/test/JDBC/input/datatypes/TestDatetime-numeric-representation-vu-prepare.sql b/test/JDBC/input/datatypes/TestDatetime-numeric-representation-vu-prepare.sql new file mode 100644 index 0000000000..f8c57f81c7 --- /dev/null +++ b/test/JDBC/input/datatypes/TestDatetime-numeric-representation-vu-prepare.sql @@ -0,0 +1,286 @@ +CREATE VIEW Datetime_view1 +AS( + SELECT + CAST(CAST(2.5 as BIT) as DATETIME) as re1, + CAST(CAST(2.5 as DECIMAL) as DATETIME)as re2, + CAST(CAST(2.5 as NUMERIC(30,8)) as DATETIME)as re3, + CAST(CAST(2.5 as FLOAT) as DATETIME)as re4, + CAST(CAST(2.5 as REAL) as DATETIME)as re5, + CAST(CAST(2.5 as INT) as DATETIME)as re6, + CAST(CAST(2.5 as BIGINT) as DATETIME)as re7, + CAST(CAST(2.5 as SMALLINT) as DATETIME)as re8, + CAST(CAST(2.5 as TINYINT) as DATETIME)as re9, + CAST(CAST(2.5 as MONEY) as DATETIME)as re10, + CAST(CAST(2.5 as SMALLMONEY) as DATETIME)as re11, + CAST(CAST(-2.5 as BIT) as DATETIME) as re12, + CAST(CAST(-2.5 as DECIMAL) as DATETIME)as re13, + CAST(CAST(-2.5 as NUMERIC(30,8)) as DATETIME)as re14, + CAST(CAST(-2.5 as FLOAT) as DATETIME)as re15, + CAST(CAST(-2.5 as REAL) as DATETIME)as re16, + CAST(CAST(-2.5 as INT) as DATETIME)as re17, + CAST(CAST(-2.5 as BIGINT) as DATETIME)as re18, + CAST(CAST(-2.5 as SMALLINT) as DATETIME)as re19, + CAST(CAST(-2.5 as MONEY) as DATETIME)as re20, + CAST(CAST(-2.5 as SMALLMONEY) as DATETIME)as re21, + CAST(NULL as DATETIME)as res22 +); +GO + +CREATE VIEW Datetime_view2 +AS( + SELECT + CAST(CAST(2.5 as BIT) as SMALLDATETIME) as re1, + CAST(CAST(2.5 as DECIMAL) as SMALLDATETIME)as re2, + CAST(CAST(2.5 as NUMERIC(30,8)) as SMALLDATETIME)as re3, + CAST(CAST(2.5 as FLOAT) as SMALLDATETIME)as re4, + CAST(CAST(2.5 as REAL) as SMALLDATETIME)as re5, + CAST(CAST(2.5 as INT) as SMALLDATETIME)as re6, + CAST(CAST(2.5 as BIGINT) as SMALLDATETIME)as re7, + CAST(CAST(2.5 as SMALLINT) as SMALLDATETIME)as re8, + CAST(CAST(2.5 as TINYINT) as SMALLDATETIME)as re9, + CAST(CAST(2.5 as MONEY) as SMALLDATETIME)as re10, + CAST(CAST(2.5 as SMALLMONEY) as SMALLDATETIME)as re11, + CAST(CAST(-2.5 as BIT) as SMALLDATETIME) as re12, + CAST(NULL as SMALLDATETIME)as res13 +); +GO + +-- Should all fail +SELECT CAST(CAST(-2.5 as NUMERIC(30,8)) as SMALLDATETIME) +GO +SELECT CAST(CAST(-2.5 as FLOAT) as SMALLDATETIME) +GO +SELECT CAST(CAST(-2.5 as REAL) as SMALLDATETIME) +GO +SELECT CAST(CAST(-2.5 as INT) as SMALLDATETIME) +GO +SELECT CAST(CAST(-2.5 as BIGINT) as SMALLDATETIME) +GO +SELECT CAST(CAST(-2.5 as SMALLINT) as SMALLDATETIME) +GO +SELECT CAST(CAST(-2.5 as MONEY) as SMALLDATETIME) +GO +SELECT CAST(CAST(-2.5 as SMALLMONEY) as SMALLDATETIME) +GO + +CREATE VIEW Datetime_view6 as ( + SELECT + DATEDIFF(minute, CAST(1 as BIT), CAST(2.5 AS BIT)) as re1, + DATEDIFF(minute, CAST(1 as DECIMAL), CAST(2.5 AS DECIMAL)) as re2, + DATEDIFF(minute, CAST(1 as NUMERIC(30,8)), CAST(2.5 AS NUMERIC(30,8))) as re3, + DATEDIFF(minute, CAST(1 as FLOAT), CAST(2.5 AS FLOAT)) as re4, + DATEDIFF(minute, CAST(1 as REAL), CAST(2.5 AS REAL)) as re5, + DATEDIFF(minute, CAST(1 as INT), CAST(2.5 AS INT)) as re6, + DATEDIFF(minute, CAST(1 as BIGINT), CAST(2.5 AS BIGINT)) as re7, + DATEDIFF(minute, CAST(1 as SMALLINT), CAST(2.5 AS SMALLINT)) as re8, + DATEDIFF(minute, CAST(1 as TINYINT), CAST(2.5 AS TINYINT)) as re9, + DATEDIFF(minute, CAST(1 as MONEY), CAST(2.5 AS MONEY)) as re10, + DATEDIFF(minute, CAST(1 as SMALLMONEY), CAST(-2.5 AS SMALLMONEY)) as re11, + DATEDIFF(minute, CAST(-1 as BIT), CAST(-2.5 AS BIT)) as re12, + DATEDIFF(minute, CAST(-1 as DECIMAL), CAST(-2.5 AS DECIMAL)) as re13, + DATEDIFF(minute, CAST(-1 as NUMERIC(30,8)), CAST(-2.5 AS NUMERIC(30,8))) as re14, + DATEDIFF(minute, CAST(-1 as FLOAT), CAST(-2.5 AS FLOAT)) as re15, + DATEDIFF(minute, CAST(-1 as REAL), CAST(-2.5 AS REAL)) as re16, + DATEDIFF(minute, CAST(-1 as INT), CAST(-2.5 AS INT)) as re17, + DATEDIFF(minute, CAST(-1 as BIGINT), CAST(-2.5 AS BIGINT)) as re18, + DATEDIFF(minute, CAST(-1 as SMALLINT), CAST(-2.5 AS SMALLINT)) as re19, + DATEDIFF(minute, CAST(-1 as MONEY), CAST(-2.5 AS MONEY)) as re20, + DATEDIFF(minute, CAST(-1 as SMALLMONEY), CAST(-2.5 AS SMALLMONEY)) as re21 +); +GO + + +CREATE TABLE Datetime_Operators_tbl1 (col DATETIME) +GO +INSERT INTO Datetime_Operators_tbl1 VALUES('1900-01-05 00:00:00.000'); +INSERT INTO Datetime_Operators_tbl1 VALUES('1900-01-05 23:40:30.000'); +INSERT INTO Datetime_Operators_tbl1 VALUES('1900-01-01 23:40:30.000'); +INSERT INTO Datetime_Operators_tbl1 VALUES('1900-01-02 00:00:00.000'); +INSERT INTO Datetime_Operators_tbl1 VALUES(NULL); +GO + +CREATE TABLE Datetime_Operators_tbl2 (col SMALLDATETIME) +GO +INSERT INTO Datetime_Operators_tbl2 VALUES('1900-01-05 00:00:00.000'); +INSERT INTO Datetime_Operators_tbl2 VALUES('1900-01-05 23:40:30.000'); +INSERT INTO Datetime_Operators_tbl2 VALUES('1900-01-01 23:40:30.000'); +INSERT INTO Datetime_Operators_tbl2 VALUES('1900-01-02 00:00:00.000'); +INSERT INTO Datetime_Operators_tbl2 VALUES(NULL); +GO + +CREATE TABLE Datetime_tbl1 (c1 DATETIME, c2 as DATEDIFF(day,'1900-01-01 00:00:00.000',c1)) +GO + +CREATE TABLE Datetime_tbl2 (c1 SMALLDATETIME, c2 as DATEDIFF(day,'1900-01-01 00:00:00.000',c1)) +GO + +CREATE PROCEDURE Datetime_proc2 (@a DATETIME, @b DECIMAL) AS +BEGIN + DECLARE @c DATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE Datetime_proc3 (@a DATETIME, @b NUMERIC(30,8)) AS +BEGIN + DECLARE @c DATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE Datetime_proc4 (@a DATETIME, @b FLOAT) AS +BEGIN + DECLARE @c DATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE Datetime_proc5 (@a DATETIME, @b REAL) AS +BEGIN + DECLARE @c DATETIME = @b; + SELECT (@a) as result1; + SELECT (@c) as result2; +END +GO + +CREATE PROCEDURE Datetime_proc6 (@a DATETIME, @b INT) AS +BEGIN + DECLARE @c DATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE Datetime_proc7 (@a DATETIME, @b BIGINT) AS +BEGIN + DECLARE @c DATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE Datetime_proc8 (@a DATETIME, @b SMALLINT) AS +BEGIN + DECLARE @c DATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE Datetime_proc9 (@a DATETIME, @b TINYINT) AS +BEGIN + DECLARE @c DATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE Datetime_proc10 (@a DATETIME, @b MONEY) AS +BEGIN + DECLARE @c DATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE Datetime_proc11 (@a DATETIME, @b SMALLMONEY) AS +BEGIN + DECLARE @c DATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE SMALLDatetime_proc2 (@a SMALLDATETIME, @b DECIMAL) AS +BEGIN + DECLARE @c SMALLDATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE SMALLDatetime_proc3 (@a SMALLDATETIME, @b NUMERIC(30,8)) AS +BEGIN + DECLARE @c SMALLDATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE SMALLDatetime_proc4 (@a SMALLDATETIME, @b FLOAT) AS +BEGIN + DECLARE @c SMALLDATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE SMALLDatetime_proc5 (@a SMALLDATETIME, @b REAL) AS +BEGIN + DECLARE @c SMALLDATETIME = @b; + SELECT (@a) as result1; + SELECT (@c) as result2; +END +GO + +CREATE PROCEDURE SMALLDatetime_proc6 (@a SMALLDATETIME, @b INT) AS +BEGIN + DECLARE @c SMALLDATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE SMALLDatetime_proc7 (@a SMALLDATETIME, @b BIGINT) AS +BEGIN + DECLARE @c SMALLDATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE SMALLDatetime_proc8 (@a SMALLDATETIME, @b SMALLINT) AS +BEGIN + DECLARE @c SMALLDATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE SMALLDatetime_proc9 (@a SMALLDATETIME, @b TINYINT) AS +BEGIN + DECLARE @c SMALLDATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE SMALLDatetime_proc10 (@a SMALLDATETIME, @b MONEY) AS +BEGIN + DECLARE @c SMALLDATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + +CREATE PROCEDURE SMALLDatetime_proc11 (@a SMALLDATETIME, @b SMALLMONEY) AS +BEGIN + DECLARE @c SMALLDATETIME = @b; + SELECT (CASE WHEN @a = @c THEN 'pass' ELSE 'fail' END) as result; +END +GO + + +CREATE TABLE Datetime_target_type_table ( + datetimetype datetime, + smalldatetimetype smalldatetime +); +GO + +CREATE TABLE Datetime_source_type_table ( + bittype bit, + decimaltype decimal, + numerictype numeric(30,8), + floattype float, + realtype real, + inttype int, + biginttype bigint, + smallinttype smallint, + tinyinttype tinyint, + moneytype money, + smallmonettype smallmoney, + nulltype int +); +GO + +INSERT INTO Datetime_target_type_table VALUES ('20120618 10:34:09 AM', '2018-07-24 06:30:50.000'); +GO + +INSERT INTO Datetime_source_type_table VALUES (0,1.9,2.0,3.1,4.2,5.4,6.2,7,8,9,10,null); +GO diff --git a/test/JDBC/input/datatypes/TestDatetime-numeric-representation-vu-verify.sql b/test/JDBC/input/datatypes/TestDatetime-numeric-representation-vu-verify.sql new file mode 100644 index 0000000000..c0ac8a809d --- /dev/null +++ b/test/JDBC/input/datatypes/TestDatetime-numeric-representation-vu-verify.sql @@ -0,0 +1,754 @@ +-- output from SQL Server : +-- 1900-01-02 00:00:00.000 1900-01-04 00:00:00.000 1900-01-03 12:00:00.000 1900-01-03 12:00:00.000 1900-01-03 12:00:00.000 1900-01-03 00:00:00.000 1900-01-03 00:00:00.000 1900-01-03 00:00:00.000 1900-01-03 00:00:00.000 1900-01-03 12:00:00.000 1900-01-03 12:00:00.000 1900-01-02 00:00:00.000 1899-12-29 00:00:00.000 1899-12-29 12:00:00.000 1899-12-29 12:00:00.000 1899-12-29 12:00:00.000 1899-12-30 00:00:00.000 1899-12-30 00:00:00.000 1899-12-30 00:00:00.000 1899-12-29 12:00:00.000 1899-12-29 12:00:00.000 null +SELECT * FROM Datetime_view1 +GO +DROP VIEW Datetime_view1 +GO + +-- output from SQL Server : +-- 1900-01-02 00:00 1900-01-04 00:00 1900-01-03 12:00 1900-01-03 12:00 1900-01-03 12:00 1900-01-03 00:00 1900-01-03 00:00 1900-01-03 00:00 1900-01-03 00:00 1900-01-03 12:00 1900-01-03 12:00 1900-01-02 00:00 null +SELECT * FROM Datetime_view2 +GO +DROP VIEW Datetime_view2 +GO + +-- output from SQL Server : +-- 0 2880 2160 2160 2160 1440 1440 1440 1440 2160 -5040 0 -2880 -2160 -2160 -2160 -1440 -1440 -1440 -2160 -2160 +SELECT * FROM Datetime_view6 +GO +DROP VIEW Datetime_view6 +GO + +-- Operators +SELECT * FROM Datetime_Operators_tbl1 WHERE col = CAST(4 as BIT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col > CAST(4 as BIT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col >= CAST(4 as BIT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col < CAST(4 as BIT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col <= CAST(4 as BIT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col != CAST(4 as BIT); +GO + +SELECT * FROM Datetime_Operators_tbl1 WHERE col = CAST(4 as DECIMAL); +SELECT * FROM Datetime_Operators_tbl1 WHERE col > CAST(4 as DECIMAL); +SELECT * FROM Datetime_Operators_tbl1 WHERE col >= CAST(4 as DECIMAL); +SELECT * FROM Datetime_Operators_tbl1 WHERE col < CAST(4 as DECIMAL); +SELECT * FROM Datetime_Operators_tbl1 WHERE col <= CAST(4 as DECIMAL); +SELECT * FROM Datetime_Operators_tbl1 WHERE col != CAST(4 as DECIMAL); +GO + +SELECT * FROM Datetime_Operators_tbl1 WHERE col = CAST(4 as NUMERIC); +SELECT * FROM Datetime_Operators_tbl1 WHERE col > CAST(4 as NUMERIC); +SELECT * FROM Datetime_Operators_tbl1 WHERE col >= CAST(4 as NUMERIC); +SELECT * FROM Datetime_Operators_tbl1 WHERE col < CAST(4 as NUMERIC); +SELECT * FROM Datetime_Operators_tbl1 WHERE col <= CAST(4 as NUMERIC); +SELECT * FROM Datetime_Operators_tbl1 WHERE col != CAST(4 as NUMERIC); +GO + +SELECT * FROM Datetime_Operators_tbl1 WHERE col = CAST(4 as FLOAT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col > CAST(4 as FLOAT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col >= CAST(4 as FLOAT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col < CAST(4 as FLOAT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col <= CAST(4 as FLOAT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col != CAST(4 as FLOAT); +GO + +SELECT * FROM Datetime_Operators_tbl1 WHERE col = CAST(4 as REAL); +SELECT * FROM Datetime_Operators_tbl1 WHERE col > CAST(4 as REAL); +SELECT * FROM Datetime_Operators_tbl1 WHERE col >= CAST(4 as REAL); +SELECT * FROM Datetime_Operators_tbl1 WHERE col < CAST(4 as REAL); +SELECT * FROM Datetime_Operators_tbl1 WHERE col <= CAST(4 as REAL); +SELECT * FROM Datetime_Operators_tbl1 WHERE col != CAST(4 as REAL); +GO + +SELECT * FROM Datetime_Operators_tbl1 WHERE col = CAST(4 as INT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col > CAST(4 as INT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col >= CAST(4 as INT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col < CAST(4 as INT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col <= CAST(4 as INT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col != CAST(4 as INT); +GO + +SELECT * FROM Datetime_Operators_tbl1 WHERE col = CAST(4 as BIGINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col > CAST(4 as BIGINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col >= CAST(4 as BIGINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col < CAST(4 as BIGINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col <= CAST(4 as BIGINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col != CAST(4 as BIGINT); +GO + +SELECT * FROM Datetime_Operators_tbl1 WHERE col = CAST(4 as SMALLINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col > CAST(4 as SMALLINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col >= CAST(4 as SMALLINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col < CAST(4 as SMALLINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col <= CAST(4 as SMALLINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col != CAST(4 as SMALLINT); +GO + +SELECT * FROM Datetime_Operators_tbl1 WHERE col = CAST(4 as TINYINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col > CAST(4 as TINYINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col >= CAST(4 as TINYINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col < CAST(4 as TINYINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col <= CAST(4 as TINYINT); +SELECT * FROM Datetime_Operators_tbl1 WHERE col != CAST(4 as TINYINT); +GO + +SELECT * FROM Datetime_Operators_tbl1 WHERE col = CAST(4 as MONEY); +SELECT * FROM Datetime_Operators_tbl1 WHERE col > CAST(4 as MONEY); +SELECT * FROM Datetime_Operators_tbl1 WHERE col >= CAST(4 as MONEY); +SELECT * FROM Datetime_Operators_tbl1 WHERE col < CAST(4 as MONEY); +SELECT * FROM Datetime_Operators_tbl1 WHERE col <= CAST(4 as MONEY); +SELECT * FROM Datetime_Operators_tbl1 WHERE col != CAST(4 as MONEY); +GO + +SELECT * FROM Datetime_Operators_tbl1 WHERE col = CAST(4 as SMALLMONEY); +SELECT * FROM Datetime_Operators_tbl1 WHERE col > CAST(4 as SMALLMONEY); +SELECT * FROM Datetime_Operators_tbl1 WHERE col >= CAST(4 as SMALLMONEY); +SELECT * FROM Datetime_Operators_tbl1 WHERE col < CAST(4 as SMALLMONEY); +SELECT * FROM Datetime_Operators_tbl1 WHERE col <= CAST(4 as SMALLMONEY); +SELECT * FROM Datetime_Operators_tbl1 WHERE col != CAST(4 as SMALLMONEY); +GO + +SELECT * FROM Datetime_Operators_tbl1 WHERE col = NULL; +SELECT * FROM Datetime_Operators_tbl1 WHERE col > NULL; +SELECT * FROM Datetime_Operators_tbl1 WHERE col >= NULL; +SELECT * FROM Datetime_Operators_tbl1 WHERE col < NULL; +SELECT * FROM Datetime_Operators_tbl1 WHERE col <= NULL; +SELECT * FROM Datetime_Operators_tbl1 WHERE col != NULL; +GO + +DROP TABLE Datetime_Operators_tbl1 +GO + +SELECT * FROM Datetime_Operators_tbl2 WHERE col = CAST(4 as BIT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col > CAST(4 as BIT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col >= CAST(4 as BIT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col < CAST(4 as BIT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col <= CAST(4 as BIT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col != CAST(4 as BIT); +GO + +SELECT * FROM Datetime_Operators_tbl2 WHERE col = CAST(4 as DECIMAL); +SELECT * FROM Datetime_Operators_tbl2 WHERE col > CAST(4 as DECIMAL); +SELECT * FROM Datetime_Operators_tbl2 WHERE col >= CAST(4 as DECIMAL); +SELECT * FROM Datetime_Operators_tbl2 WHERE col < CAST(4 as DECIMAL); +SELECT * FROM Datetime_Operators_tbl2 WHERE col <= CAST(4 as DECIMAL); +SELECT * FROM Datetime_Operators_tbl2 WHERE col != CAST(4 as DECIMAL); +GO + +SELECT * FROM Datetime_Operators_tbl2 WHERE col = CAST(4 as NUMERIC); +SELECT * FROM Datetime_Operators_tbl2 WHERE col > CAST(4 as NUMERIC); +SELECT * FROM Datetime_Operators_tbl2 WHERE col >= CAST(4 as NUMERIC); +SELECT * FROM Datetime_Operators_tbl2 WHERE col < CAST(4 as NUMERIC); +SELECT * FROM Datetime_Operators_tbl2 WHERE col <= CAST(4 as NUMERIC); +SELECT * FROM Datetime_Operators_tbl2 WHERE col != CAST(4 as NUMERIC); +GO + +SELECT * FROM Datetime_Operators_tbl2 WHERE col = CAST(4 as FLOAT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col > CAST(4 as FLOAT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col >= CAST(4 as FLOAT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col < CAST(4 as FLOAT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col <= CAST(4 as FLOAT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col != CAST(4 as FLOAT); +GO + +SELECT * FROM Datetime_Operators_tbl2 WHERE col = CAST(4 as REAL); +SELECT * FROM Datetime_Operators_tbl2 WHERE col > CAST(4 as REAL); +SELECT * FROM Datetime_Operators_tbl2 WHERE col >= CAST(4 as REAL); +SELECT * FROM Datetime_Operators_tbl2 WHERE col < CAST(4 as REAL); +SELECT * FROM Datetime_Operators_tbl2 WHERE col <= CAST(4 as REAL); +SELECT * FROM Datetime_Operators_tbl2 WHERE col != CAST(4 as REAL); +GO + +SELECT * FROM Datetime_Operators_tbl2 WHERE col = CAST(4 as INT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col > CAST(4 as INT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col >= CAST(4 as INT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col < CAST(4 as INT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col <= CAST(4 as INT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col != CAST(4 as INT); +GO + +SELECT * FROM Datetime_Operators_tbl2 WHERE col = CAST(4 as BIGINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col > CAST(4 as BIGINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col >= CAST(4 as BIGINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col < CAST(4 as BIGINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col <= CAST(4 as BIGINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col != CAST(4 as BIGINT); +GO + +SELECT * FROM Datetime_Operators_tbl2 WHERE col = CAST(4 as SMALLINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col > CAST(4 as SMALLINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col >= CAST(4 as SMALLINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col < CAST(4 as SMALLINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col <= CAST(4 as SMALLINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col != CAST(4 as SMALLINT); +GO + +SELECT * FROM Datetime_Operators_tbl2 WHERE col = CAST(4 as TINYINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col > CAST(4 as TINYINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col >= CAST(4 as TINYINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col < CAST(4 as TINYINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col <= CAST(4 as TINYINT); +SELECT * FROM Datetime_Operators_tbl2 WHERE col != CAST(4 as TINYINT); +GO + +SELECT * FROM Datetime_Operators_tbl2 WHERE col = CAST(4 as MONEY); +SELECT * FROM Datetime_Operators_tbl2 WHERE col > CAST(4 as MONEY); +SELECT * FROM Datetime_Operators_tbl2 WHERE col >= CAST(4 as MONEY); +SELECT * FROM Datetime_Operators_tbl2 WHERE col < CAST(4 as MONEY); +SELECT * FROM Datetime_Operators_tbl2 WHERE col <= CAST(4 as MONEY); +SELECT * FROM Datetime_Operators_tbl2 WHERE col != CAST(4 as MONEY); +GO + +SELECT * FROM Datetime_Operators_tbl2 WHERE col = CAST(4 as SMALLMONEY); +SELECT * FROM Datetime_Operators_tbl2 WHERE col > CAST(4 as SMALLMONEY); +SELECT * FROM Datetime_Operators_tbl2 WHERE col >= CAST(4 as SMALLMONEY); +SELECT * FROM Datetime_Operators_tbl2 WHERE col < CAST(4 as SMALLMONEY); +SELECT * FROM Datetime_Operators_tbl2 WHERE col <= CAST(4 as SMALLMONEY); +SELECT * FROM Datetime_Operators_tbl2 WHERE col != CAST(4 as SMALLMONEY); +GO + +SELECT * FROM Datetime_Operators_tbl2 WHERE col = NULL; +SELECT * FROM Datetime_Operators_tbl2 WHERE col > NULL; +SELECT * FROM Datetime_Operators_tbl2 WHERE col >= NULL; +SELECT * FROM Datetime_Operators_tbl2 WHERE col < NULL; +SELECT * FROM Datetime_Operators_tbl2 WHERE col <= NULL; +SELECT * FROM Datetime_Operators_tbl2 WHERE col != NULL; +GO + +DROP TABLE Datetime_Operators_tbl2 +GO + +-- Tables +ALTER TABLE Datetime_tbl1 ADD CONSTRAINT Datetime_constraint1 DEFAULT CAST(0 as BIT) FOR c1 +INSERT INTO Datetime_tbl1 VALUES(DEFAULT) +INSERT INTO Datetime_tbl1 VALUES(CAST(1.5 as BIT)) +GO +SELECT * FROM Datetime_tbl1 +GO +DELETE FROM Datetime_tbl1 WHERE c1 IS NOT NULL +GO + + +ALTER TABLE Datetime_tbl1 ADD CONSTRAINT Datetime_constraint2 DEFAULT CAST(2 as DECIMAL) FOR c1 +GO +INSERT INTO Datetime_tbl1 VALUES(DEFAULT) +INSERT INTO Datetime_tbl1 VALUES(CAST(1.5 as DECIMAL)) +GO +SELECT * FROM Datetime_tbl1 +GO +DELETE FROM Datetime_tbl1 WHERE c1 IS NOT NULL +GO + +ALTER TABLE Datetime_tbl1 ADD CONSTRAINT Datetime_constraint3 DEFAULT CAST(2 as NUMERIC) FOR c1 +GO +INSERT INTO Datetime_tbl1 VALUES(DEFAULT) +INSERT INTO Datetime_tbl1 VALUES(CAST(1.5 as NUMERIC)) +GO +SELECT * FROM Datetime_tbl1 +GO +DELETE FROM Datetime_tbl1 WHERE c1 IS NOT NULL +GO + +ALTER TABLE Datetime_tbl1 ADD CONSTRAINT Datetime_constraint4 DEFAULT CAST(2 as FLOAT) FOR c1 +GO +INSERT INTO Datetime_tbl1 VALUES(DEFAULT) +INSERT INTO Datetime_tbl1 VALUES(CAST(1.5 as FLOAT)) +GO +SELECT * FROM Datetime_tbl1 +GO +DELETE FROM Datetime_tbl1 WHERE c1 IS NOT NULL +GO + +ALTER TABLE Datetime_tbl1 ADD CONSTRAINT Datetime_constraint5 DEFAULT CAST(2 as REAL) FOR c1 +GO +INSERT INTO Datetime_tbl1 VALUES(DEFAULT) +INSERT INTO Datetime_tbl1 VALUES(CAST(1.5 as REAL)) +GO +SELECT * FROM Datetime_tbl1 +GO +DELETE FROM Datetime_tbl1 WHERE c1 IS NOT NULL +GO + +ALTER TABLE Datetime_tbl1 ADD CONSTRAINT Datetime_constraint6 DEFAULT CAST(2 as INT) FOR c1 +GO +INSERT INTO Datetime_tbl1 VALUES(DEFAULT) +INSERT INTO Datetime_tbl1 VALUES(CAST(1.5 as INT)) +GO +SELECT * FROM Datetime_tbl1 +GO +DELETE FROM Datetime_tbl1 WHERE c1 IS NOT NULL +GO + +ALTER TABLE Datetime_tbl1 ADD CONSTRAINT Datetime_constraint7 DEFAULT CAST(2 as BIGINT) FOR c1 +GO +INSERT INTO Datetime_tbl1 VALUES(DEFAULT) +INSERT INTO Datetime_tbl1 VALUES(CAST(1.5 as BIGINT)) +GO +SELECT * FROM Datetime_tbl1 +GO +DELETE FROM Datetime_tbl1 WHERE c1 IS NOT NULL +GO + +ALTER TABLE Datetime_tbl1 ADD CONSTRAINT Datetime_constraint8 DEFAULT CAST(2 as SMALLINT) FOR c1 +GO +INSERT INTO Datetime_tbl1 VALUES(DEFAULT) +INSERT INTO Datetime_tbl1 VALUES(CAST(1.5 as SMALLINT)) +GO +SELECT * FROM Datetime_tbl1 +GO +DELETE FROM Datetime_tbl1 WHERE c1 IS NOT NULL +GO + +ALTER TABLE Datetime_tbl1 ADD CONSTRAINT Datetime_constraint9 DEFAULT CAST(2 as TINYINT) FOR c1 +GO +INSERT INTO Datetime_tbl1 VALUES(DEFAULT) +INSERT INTO Datetime_tbl1 VALUES(CAST(1.5 as TINYINT)) +GO +SELECT * FROM Datetime_tbl1 +GO +DELETE FROM Datetime_tbl1 WHERE c1 IS NOT NULL +GO + +ALTER TABLE Datetime_tbl1 ADD CONSTRAINT Datetime_constraint10 DEFAULT CAST(2 as MONEY) FOR c1 +GO +INSERT INTO Datetime_tbl1 VALUES(DEFAULT) +INSERT INTO Datetime_tbl1 VALUES(CAST(1.5 as MONEY)) +GO +SELECT * FROM Datetime_tbl1 +GO +DELETE FROM Datetime_tbl1 WHERE c1 IS NOT NULL +GO + +ALTER TABLE Datetime_tbl1 ADD CONSTRAINT Datetime_constraint11 DEFAULT CAST(2 as SMALLMONEY) FOR c1 +GO +INSERT INTO Datetime_tbl1 VALUES(DEFAULT) +INSERT INTO Datetime_tbl1 VALUES(CAST(1.5 as SMALLMONEY)) +GO +SELECT * FROM Datetime_tbl1 +GO +DELETE FROM Datetime_tbl1 WHERE c1 IS NOT NULL +GO + +ALTER TABLE Datetime_tbl1 ADD CONSTRAINT Datetime_constraint12 DEFAULT NULL FOR c1 +GO +INSERT INTO Datetime_tbl1 VALUES(DEFAULT) +INSERT INTO Datetime_tbl1 VALUES(NULL) +GO +SELECT * FROM Datetime_tbl1 +GO +DELETE FROM Datetime_tbl1 WHERE c1 IS NOT NULL +GO + +DROP TABLE datetime_tbl1 +GO + +ALTER TABLE Datetime_tbl2 ADD CONSTRAINT Datetime_constraint13 DEFAULT CAST(0 as BIT) FOR c1 +INSERT INTO Datetime_tbl2 VALUES(DEFAULT) +INSERT INTO Datetime_tbl2 VALUES(CAST(1.5 as BIT)) +GO +SELECT * FROM Datetime_tbl2 +GO +DELETE FROM Datetime_tbl2 WHERE c1 IS NOT NULL +GO + + +ALTER TABLE Datetime_tbl2 ADD CONSTRAINT Datetime_constraint14 DEFAULT CAST(2 as DECIMAL) FOR c1 +GO +INSERT INTO Datetime_tbl2 VALUES(DEFAULT) +INSERT INTO Datetime_tbl2 VALUES(CAST(1.5 as DECIMAL)) +GO +SELECT * FROM Datetime_tbl2 +GO +DELETE FROM Datetime_tbl2 WHERE c1 IS NOT NULL +GO + +ALTER TABLE Datetime_tbl2 ADD CONSTRAINT Datetime_constraint15 DEFAULT CAST(2 as NUMERIC) FOR c1 +GO +INSERT INTO Datetime_tbl2 VALUES(DEFAULT) +INSERT INTO Datetime_tbl2 VALUES(CAST(1.5 as NUMERIC)) +GO +SELECT * FROM Datetime_tbl2 +GO +DELETE FROM Datetime_tbl2 WHERE c1 IS NOT NULL +GO + +ALTER TABLE Datetime_tbl2 ADD CONSTRAINT Datetime_constrain16 DEFAULT CAST(2 as FLOAT) FOR c1 +GO +INSERT INTO Datetime_tbl2 VALUES(DEFAULT) +INSERT INTO Datetime_tbl2 VALUES(CAST(1.5 as FLOAT)) +GO +SELECT * FROM Datetime_tbl2 +GO +DELETE FROM Datetime_tbl2 WHERE c1 IS NOT NULL +GO + +ALTER TABLE Datetime_tbl2 ADD CONSTRAINT Datetime_constraint17 DEFAULT CAST(2 as REAL) FOR c1 +GO +INSERT INTO Datetime_tbl2 VALUES(DEFAULT) +INSERT INTO Datetime_tbl2 VALUES(CAST(1.5 as REAL)) +GO +SELECT * FROM Datetime_tbl2 +GO +DELETE FROM Datetime_tbl2 WHERE c1 IS NOT NULL +GO + +ALTER TABLE Datetime_tbl2 ADD CONSTRAINT Datetime_constraint18 DEFAULT CAST(2 as INT) FOR c1 +GO +INSERT INTO Datetime_tbl2 VALUES(DEFAULT) +INSERT INTO Datetime_tbl2 VALUES(CAST(1.5 as INT)) +GO +SELECT * FROM Datetime_tbl2 +GO +DELETE FROM Datetime_tbl2 WHERE c1 IS NOT NULL +GO + +ALTER TABLE Datetime_tbl2 ADD CONSTRAINT Datetime_constraint19 DEFAULT CAST(2 as BIGINT) FOR c1 +GO +INSERT INTO Datetime_tbl2 VALUES(DEFAULT) +INSERT INTO Datetime_tbl2 VALUES(CAST(1.5 as BIGINT)) +GO +SELECT * FROM Datetime_tbl2 +GO +DELETE FROM Datetime_tbl2 WHERE c1 IS NOT NULL +GO + +ALTER TABLE Datetime_tbl2 ADD CONSTRAINT Datetime_constraint20 DEFAULT CAST(2 as SMALLINT) FOR c1 +GO +INSERT INTO Datetime_tbl2 VALUES(DEFAULT) +INSERT INTO Datetime_tbl2 VALUES(CAST(1.5 as SMALLINT)) +GO +SELECT * FROM Datetime_tbl2 +GO +DELETE FROM Datetime_tbl2 WHERE c1 IS NOT NULL +GO + +ALTER TABLE Datetime_tbl2 ADD CONSTRAINT Datetime_constraint21 DEFAULT CAST(2 as TINYINT) FOR c1 +GO +INSERT INTO Datetime_tbl2 VALUES(DEFAULT) +INSERT INTO Datetime_tbl2 VALUES(CAST(1.5 as TINYINT)) +GO +SELECT * FROM Datetime_tbl2 +GO +DELETE FROM Datetime_tbl2 WHERE c1 IS NOT NULL +GO + +ALTER TABLE Datetime_tbl2 ADD CONSTRAINT Datetime_constraint22 DEFAULT CAST(2 as MONEY) FOR c1 +GO +INSERT INTO Datetime_tbl2 VALUES(DEFAULT) +INSERT INTO Datetime_tbl2 VALUES(CAST(1.5 as MONEY)) +GO +SELECT * FROM Datetime_tbl2 +GO +DELETE FROM Datetime_tbl2 WHERE c1 IS NOT NULL +GO + +ALTER TABLE Datetime_tbl2 ADD CONSTRAINT Datetime_constraint23 DEFAULT CAST(2 as SMALLMONEY) FOR c1 +GO +INSERT INTO Datetime_tbl2 VALUES(DEFAULT) +INSERT INTO Datetime_tbl2 VALUES(CAST(1.5 as SMALLMONEY)) +GO +SELECT * FROM Datetime_tbl2 +GO +DELETE FROM Datetime_tbl2 WHERE c1 IS NOT NULL +GO + +ALTER TABLE Datetime_tbl2 ADD CONSTRAINT Datetime_constraint24 DEFAULT NULL FOR c1 +GO +INSERT INTO Datetime_tbl2 VALUES(DEFAULT) +INSERT INTO Datetime_tbl2 VALUES(NULL) +GO +SELECT * FROM Datetime_tbl2 +GO +DELETE FROM Datetime_tbl2 WHERE c1 IS NOT NULL +GO + +DROP TABLE datetime_tbl2 +GO + +-- Procedures +EXEC Datetime_proc2 '1900-01-04 00:00:00', 3.1 +GO +EXEC Datetime_proc2 '1900-01-01 00:00:00', 0 +GO +EXEC Datetime_proc2 '1900-01-04 00:00:00', 2.5 +GO +EXEC Datetime_proc2 '1899-12-29 00:00:00', -2.5 +GO +DROP PROCEDURE Datetime_proc2 +GO + +EXEC Datetime_proc3 '1900-01-04 02:24:00', 3.1 +GO +EXEC Datetime_proc3 '1900-01-01 00:00:00', 0 +GO +EXEC Datetime_proc3 '1900-01-03 12:00:00', 2.5 +GO +EXEC Datetime_proc3 '1899-12-29 12:00:00', -2.5 +GO +DROP PROCEDURE Datetime_proc3 +GO + +EXEC Datetime_proc4 '1900-01-02 09:36:00', 1.4 +GO +EXEC Datetime_proc4 '1900-01-04 02:24:00', 3.1 +GO +EXEC Datetime_proc4 '1899-12-28 21:36:00', -3.1 +GO +DROP PROCEDURE Datetime_proc4 +GO + +EXEC Datetime_proc5 '1900-01-02 09:35:59.997', 1.4 +GO +EXEC Datetime_proc5 '1900-01-04 02:23:59.99', 3.1 +GO +EXEC Datetime_proc5 '1900-01-01 00:00:00.000', 0 +GO +EXEC Datetime_proc5 '1900-01-02 00:00:00.000', 1 +GO +EXEC Datetime_proc5 '1899-12-28 21:36:00.007', -3.1 +GO +DROP PROCEDURE Datetime_proc5 +GO + +EXEC Datetime_proc6 '1900-01-02 00:00:00.000', 1.4 +GO +EXEC Datetime_proc6 '1900-01-04 00:00:00.000', 3.1 +GO +EXEC Datetime_proc6 '1899-12-30 00:00:00.000', -2.5 +GO +DROP PROCEDURE Datetime_proc6 +GO + +EXEC Datetime_proc7 '1900-01-02 00:00:00.000', 1.4 +GO +EXEC Datetime_proc7 '1900-01-04 00:00:00.000', 3.1 +GO +EXEC Datetime_proc7 '1899-12-30 00:00:00.000', -2.5 +GO +DROP PROCEDURE Datetime_proc7 +GO + +EXEC Datetime_proc8 '1900-01-02 00:00:00.000', 1.4 +GO +EXEC Datetime_proc8 '1989-09-18 00:00:00.000', 32767 +GO +EXEC Datetime_proc8 '1989-09-18 00:00:00.000', 32768 +GO +DROP PROCEDURE Datetime_proc8 +GO + +EXEC Datetime_proc9 '1900-01-02 00:00:00.000', 1.4 +GO +EXEC Datetime_proc9 '1900-09-13 00:00:00.000', 255 +GO +EXEC Datetime_proc9 '1900-09-13 00:00:00.000', 256 +GO +DROP PROCEDURE Datetime_proc9 +GO + +EXEC Datetime_proc10 '1900-01-02 09:36:00.000', 1.4 +GO +EXEC Datetime_proc10 '1900-01-04 02:24:00.000', 3.1 +GO +EXEC Datetime_proc10 '1899-12-29 12:00:00.000', -2.5 +GO +DROP PROCEDURE Datetime_proc10 +GO + +EXEC Datetime_proc11 '1900-01-02 09:36:00.000', 1.4 +GO +EXEC Datetime_proc11 '1900-01-04 02:24:00.000', 3.1 +GO +EXEC Datetime_proc11 '1899-12-29 12:00:00.000', -2.5 +GO + +EXEC Datetime_proc11 '1900-01-02 09:36:00.000', NULL +GO +EXEC Datetime_proc11 '1900-01-04 02:24:00.000', NULL +GO +DROP PROCEDURE Datetime_proc11 +GO + +EXEC SMALLDatetime_proc2 '1900-01-04 00:00:00', 3.1 +GO +EXEC SMALLDatetime_proc2 '1900-01-01 00:00:00', 0 +GO +EXEC SMALLDatetime_proc2 '1900-01-04 00:00:00', 2.5 +GO +EXEC SMALLDatetime_proc2 '1899-12-29 00:00:00', -2.5 +GO +DROP PROCEDURE SMALLDatetime_proc2 +GO + +EXEC SMALLDatetime_proc3 '1900-01-04 02:24:00', 3.1 +GO +EXEC SMALLDatetime_proc3 '1900-01-01 00:00:00', 0 +GO +EXEC SMALLDatetime_proc3 '1900-01-03 12:00:00', 2.5 +GO +DROP PROCEDURE SMALLDatetime_proc3 +GO + +-- Incorrect +EXEC SMALLDatetime_proc4 '1900-01-02 09:36:00', 1.4 +GO +EXEC SMALLDatetime_proc4 '1900-01-04 02:24:00', 3.1 +GO +EXEC SMALLDatetime_proc4 '1899-12-28 21:36:00', -3.1 +GO +DROP PROCEDURE SMALLDatetime_proc4 +GO + +EXEC SMALLDatetime_proc5 '1900-01-02 09:35:59.997', 1.4 +GO +EXEC SMALLDatetime_proc5 '1900-01-04 02:23:59.99', 3.1 +GO +EXEC SMALLDatetime_proc5 '1900-01-01 00:00:00.000', 0 +GO +EXEC SMALLDatetime_proc5 '1900-01-02 00:00:00.000', 1 +GO +EXEC SMALLDatetime_proc5 '1899-12-28 21:36:00.007', -3.1 +GO +DROP PROCEDURE SMALLDatetime_proc5 +GO + +EXEC SMALLDatetime_proc6 '1900-01-02 00:00:00.000', 1.4 +GO +EXEC SMALLDatetime_proc6 '1900-01-04 00:00:00.000', 3.1 +GO +EXEC SMALLDatetime_proc6 '1899-12-30 00:00:00.000', -2.5 +GO +DROP PROCEDURE SMALLDatetime_proc6 +GO + +EXEC SMALLDatetime_proc7 '1900-01-02 00:00:00.000', 1.4 +GO +EXEC SMALLDatetime_proc7 '1900-01-04 00:00:00.000', 3.1 +GO +EXEC SMALLDatetime_proc7 '1899-12-30 00:00:00.000', -2.5 +GO +DROP PROCEDURE SMALLDatetime_proc7 +GO + +EXEC SMALLDatetime_proc8 '1900-01-02 00:00:00.000', 1.4 +GO +EXEC SMALLDatetime_proc8 '1989-09-18 00:00:00.000', 32767 +GO +EXEC SMALLDatetime_proc8 '1989-09-18 00:00:00.000', 32768 +GO +DROP PROCEDURE SMALLDatetime_proc8 +GO + +EXEC SMALLDatetime_proc9 '1900-01-02 00:00:00.000', 1.4 +GO +EXEC SMALLDatetime_proc9 '1900-09-13 00:00:00.000', 255 +GO +EXEC SMALLDatetime_proc9 '1900-09-13 00:00:00.000', 256 +GO +DROP PROCEDURE SMALLDatetime_proc9 +GO + +-- Incorrect +EXEC SMALLDatetime_proc10 '1900-01-02 09:36:00.000', 1.4 +GO +EXEC SMALLDatetime_proc10 '1900-01-04 02:24:00.000', 3.1 +GO +EXEC SMALLDatetime_proc10 '1899-12-29 12:00:00.000', -2.5 +GO +DROP PROCEDURE SMALLDatetime_proc10 +GO + + +--Incorrect +EXEC SMALLDatetime_proc11 '1900-01-02 09:36:00.000', 1.4 +GO +EXEC SMALLDatetime_proc11 '1900-01-04 02:24:00.000', 3.1 +GO +EXEC SMALLDatetime_proc11 '1899-12-29 12:00:00.000', -2.5 +GO + +EXEC SMALLDatetime_proc11 '1900-01-02 09:36:00.000', NULL +GO +EXEC SMALLDatetime_proc11 '1900-01-04 02:24:00.000', NULL +GO +DROP PROCEDURE SMALLDatetime_proc11 +GO + +-- Union +SELECT datetimetype FROM Datetime_target_type_table UNION SELECT bittype FROM Datetime_source_type_table +GO + +SELECT datetimetype FROM Datetime_target_type_table UNION SELECT decimaltype FROM Datetime_source_type_table +GO + +SELECT datetimetype FROM Datetime_target_type_table UNION SELECT numerictype FROM Datetime_source_type_table +GO + +SELECT datetimetype FROM Datetime_target_type_table UNION SELECT floattype FROM Datetime_source_type_table +GO + +SELECT datetimetype FROM Datetime_target_type_table UNION SELECT realtype FROM Datetime_source_type_table +GO + +SELECT datetimetype FROM Datetime_target_type_table UNION SELECT inttype FROM Datetime_source_type_table +GO + +SELECT datetimetype FROM Datetime_target_type_table UNION SELECT biginttype FROM Datetime_source_type_table +GO + +SELECT datetimetype FROM Datetime_target_type_table UNION SELECT smallinttype FROM Datetime_source_type_table +GO + +SELECT datetimetype FROM Datetime_target_type_table UNION SELECT tinyinttype FROM Datetime_source_type_table +GO + +SELECT datetimetype FROM Datetime_target_type_table UNION SELECT moneytype FROM Datetime_source_type_table +GO + +SELECT datetimetype FROM Datetime_target_type_table UNION SELECT smallmonettype FROM Datetime_source_type_table +GO + +SELECT datetimetype FROM Datetime_target_type_table UNION SELECT nulltype FROM Datetime_source_type_table +GO + +SELECT smalldatetimetype FROM Datetime_target_type_table UNION SELECT bittype FROM Datetime_source_type_table +GO + +SELECT smalldatetimetype FROM Datetime_target_type_table UNION SELECT decimaltype FROM Datetime_source_type_table +GO + +SELECT smalldatetimetype FROM Datetime_target_type_table UNION SELECT numerictype FROM Datetime_source_type_table +GO + +SELECT smalldatetimetype FROM Datetime_target_type_table UNION SELECT floattype FROM Datetime_source_type_table +GO + +SELECT smalldatetimetype FROM Datetime_target_type_table UNION SELECT realtype FROM Datetime_source_type_table +GO + +SELECT smalldatetimetype FROM Datetime_target_type_table UNION SELECT inttype FROM Datetime_source_type_table +GO + +SELECT smalldatetimetype FROM Datetime_target_type_table UNION SELECT biginttype FROM Datetime_source_type_table +GO + +SELECT smalldatetimetype FROM Datetime_target_type_table UNION SELECT smallinttype FROM Datetime_source_type_table +GO + +SELECT smalldatetimetype FROM Datetime_target_type_table UNION SELECT tinyinttype FROM Datetime_source_type_table +GO + +SELECT smalldatetimetype FROM Datetime_target_type_table UNION SELECT moneytype FROM Datetime_source_type_table +GO + +SELECT smalldatetimetype FROM Datetime_target_type_table UNION SELECT smallmonettype FROM Datetime_source_type_table +GO + +SELECT smalldatetimetype FROM Datetime_target_type_table UNION SELECT nulltype FROM Datetime_source_type_table +GO + +DROP TABLE Datetime_target_type_table +GO + +DROP TABLE Datetime_source_type_table +GO diff --git a/test/JDBC/upgrade/14_6/schedule b/test/JDBC/upgrade/14_6/schedule index 43b4cbafc7..e0b35135b4 100644 --- a/test/JDBC/upgrade/14_6/schedule +++ b/test/JDBC/upgrade/14_6/schedule @@ -15,6 +15,7 @@ TestBIT TestChar TestDatetime2 TestDatetime +TestDatetime-numeric-representation TestDate TestDecimal TestFloat diff --git a/test/JDBC/upgrade/14_7/schedule b/test/JDBC/upgrade/14_7/schedule index 906dcbada5..df6bb56b1f 100644 --- a/test/JDBC/upgrade/14_7/schedule +++ b/test/JDBC/upgrade/14_7/schedule @@ -17,6 +17,7 @@ TestBIT TestChar TestDatetime2 TestDatetime +TestDatetime-numeric-representation TestDate TestDecimal TestFloat diff --git a/test/JDBC/upgrade/14_8/schedule b/test/JDBC/upgrade/14_8/schedule index 37ea827f64..52ef6eb15f 100644 --- a/test/JDBC/upgrade/14_8/schedule +++ b/test/JDBC/upgrade/14_8/schedule @@ -17,6 +17,7 @@ TestBIT TestChar TestDatetime2 TestDatetime +TestDatetime-numeric-representation TestDate TestDecimal TestFloat diff --git a/test/JDBC/upgrade/15_1/schedule b/test/JDBC/upgrade/15_1/schedule index 153845415b..7440c6868d 100644 --- a/test/JDBC/upgrade/15_1/schedule +++ b/test/JDBC/upgrade/15_1/schedule @@ -17,6 +17,7 @@ TestBIT TestChar TestDatetime2 TestDatetime +TestDatetime-numeric-representation TestDate TestDecimal TestFloat diff --git a/test/JDBC/upgrade/15_2/schedule b/test/JDBC/upgrade/15_2/schedule index 5770e4e712..354f53a13f 100644 --- a/test/JDBC/upgrade/15_2/schedule +++ b/test/JDBC/upgrade/15_2/schedule @@ -17,6 +17,7 @@ TestBIT TestChar TestDatetime2 TestDatetime +TestDatetime-numeric-representation TestDate TestDecimal TestFloat diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index f52263e28e..ed563e7d5a 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -17,6 +17,8 @@ TestBIT TestChar TestDatetime2 TestDatetime +TestDatetime-numeric-representation +TestDatetime-numeric-dateaddfunction TestDate TestDecimal TestFloat diff --git a/test/python/expected/sql_validation_framework/expected_drop.out b/test/python/expected/sql_validation_framework/expected_drop.out index d774166cde..477ce5fad6 100644 --- a/test/python/expected/sql_validation_framework/expected_drop.out +++ b/test/python/expected/sql_validation_framework/expected_drop.out @@ -2,6 +2,7 @@ Unexpected drop found for cast in file babelfishpg_common--1.0.0--1.1.0.sql Unexpected drop found for cast in file babelfishpg_common--1.0.0--1.1.0.sql Unexpected drop found for cast in file babelfishpg_common--1.0.0--1.1.0.sql Unexpected drop found for cast in file babelfishpg_common--1.0.0--1.1.0.sql +Unexpected drop found for cast in file babelfishpg_common--3.1.0--3.2.0.sql Unexpected drop found for function get_bbf_binary_ops_count in file babelfishpg_common--2.3.0--2.4.0.sql Unexpected drop found for function get_bbf_binary_ops_count in file babelfishpg_common--3.0.0--3.1.0.sql Unexpected drop found for function sys.babelfish_update_server_collation_name in file babelfishpg_common--2.0.0--2.1.0.sql diff --git a/test/python/expected/upgrade_validation/expected_dependency.out b/test/python/expected/upgrade_validation/expected_dependency.out index b236cd586a..fda3b66ffc 100644 --- a/test/python/expected/upgrade_validation/expected_dependency.out +++ b/test/python/expected/upgrade_validation/expected_dependency.out @@ -397,8 +397,6 @@ Function sys.fixeddecimaltof(sys.fixeddecimal) Function sys.float4binary(real,integer,boolean) Function sys.float4varbinary(real,integer,boolean) Function sys.float8binary(double precision,integer,boolean) -Function sys.float8datetime(double precision) -Function sys.float8smalldatetime(double precision) Function sys.float8varbinary(double precision,integer,boolean) Function sys.float_sqlvariant(double precision) Function sys.floor(bigint) @@ -442,12 +440,10 @@ Function sys.inject_fault_status(text) Function sys.int2_fixeddecimal_cmp(smallint,sys.fixeddecimal) Function sys.int2binary(smallint,integer,boolean) Function sys.int2bit(smallint) -Function sys.int2datetime(integer) Function sys.int2fixeddecimal(smallint) Function sys.int2fixeddecimaldiv(smallint,sys.fixeddecimal) Function sys.int2fixeddecimaldiv(smallint,sys.smallmoney) Function sys.int2rowversion(smallint,integer,boolean) -Function sys.int2smalldatetime(integer) Function sys.int2varbinary(smallint,integer,boolean) Function sys.int4_fixeddecimal_cmp(integer,sys.fixeddecimal) Function sys.int4fixeddecimaldiv(integer,sys.fixeddecimal) From 5c5deafb34198990adb2169e2732b70c095e6d09 Mon Sep 17 00:00:00 2001 From: pratikzode <73869399+pratikzode@users.noreply.github.com> Date: Wed, 12 Apr 2023 10:50:47 -0700 Subject: [PATCH 053/363] Support DATABASE_PRINCIPAL_ID() T-SQL function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SELECT DATABASE_PRINCIPAL_ID(); Retrieve the ID of the current user. SELECT DATABASE_PRINCIPAL_ID(‘principal_name’); Retrieve the ID of the specific database principal. Modified the file so that when called with NULL as argument it will return NULL and also modified for trailing spaces that will give proper output instead of NULL. Task: BABEL-1199 Signed-off-by: pratikzode --- .../babelfishpg_tsql/sql/sys_functions.sql | 34 ++++----- .../babelfishpg_tsql--3.1.0--3.2.0.sql | 45 +++++------ contrib/babelfishpg_tsql/src/rolecmds.c | 44 +++++++---- .../sys-userid-vu-cleanup.out} | 20 ++++- .../sys-userid-vu-prepare.out} | 35 ++++++++- ...vu-verify.out => sys-userid-vu-verify.out} | 74 ++++++++++++++++++- .../functions/sys-userid-vu-cleanup.sql} | 20 ++++- .../functions/sys-userid-vu-prepare.sql} | 35 ++++++++- .../sys-userid-vu-verify.sql} | 31 +++++++- test/JDBC/upgrade/latest/schedule | 2 +- .../expected_dependency.out | 1 - 11 files changed, 276 insertions(+), 65 deletions(-) rename test/JDBC/{input/BABEL-1199-vu-cleanup.sql => expected/sys-userid-vu-cleanup.out} (55%) rename test/JDBC/{input/BABEL-1199-vu-prepare.sql => expected/sys-userid-vu-prepare.out} (55%) rename test/JDBC/expected/{BABEL-1199-vu-verify.out => sys-userid-vu-verify.out} (61%) rename test/JDBC/{expected/BABEL-1199-vu-cleanup.out => input/functions/sys-userid-vu-cleanup.sql} (56%) rename test/JDBC/{expected/BABEL-1199-vu-prepare.out => input/functions/sys-userid-vu-prepare.sql} (55%) rename test/JDBC/input/{BABEL-1199-vu-verify.sql => functions/sys-userid-vu-verify.sql} (61%) diff --git a/contrib/babelfishpg_tsql/sql/sys_functions.sql b/contrib/babelfishpg_tsql/sql/sys_functions.sql index a90640308c..0ab3160864 100644 --- a/contrib/babelfishpg_tsql/sql/sys_functions.sql +++ b/contrib/babelfishpg_tsql/sql/sys_functions.sql @@ -144,9 +144,14 @@ RETURNS INTEGER AS 'babelfishpg_tsql', 'tsql_get_returnTypmodValue' LANGUAGE C IMMUTABLE PARALLEL SAFE; -CREATE OR REPLACE FUNCTION sys.user_id(IN user_name TEXT DEFAULT NULL) +CREATE OR REPLACE FUNCTION sys.user_id(IN user_name sys.sysname) RETURNS OID AS 'babelfishpg_tsql', 'user_id' +LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT; + +CREATE OR REPLACE FUNCTION sys.user_id() +RETURNS OID +AS 'babelfishpg_tsql', 'user_id_noarg' LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE OR REPLACE FUNCTION sys.suser_name_internal(IN server_user_id OID) @@ -1822,26 +1827,15 @@ CREATE OR REPLACE FUNCTION sys.servicename() RETURNS sys.NVARCHAR(128) AS 'babelfishpg_tsql' LANGUAGE C STABLE; -CREATE OR REPLACE FUNCTION sys.database_principal_id(IN user_name sys.sysname DEFAULT NULL) +CREATE OR REPLACE FUNCTION sys.database_principal_id(IN user_name sys.sysname) RETURNS OID -AS -$$ -BEGIN - -- If user_name is NULL, return the result of USER_ID() - IF user_name IS NULL OR user_name = 'NULL' THEN - RETURN NULL; - END IF; - -- Trim the trailing spaces from user_name - user_name := rtrim(user_name); - -- If user_name is an empty string or contains only spaces, return NULL - IF user_name = '' THEN - RETURN NULL; - END IF; - -- Return the principal_id of the specified user_name - RETURN (SELECT principal_id FROM sys.database_principals WHERE name = user_name); -END; -$$ -LANGUAGE PLPGSQL IMMUTABLE PARALLEL SAFE; +AS 'babelfishpg_tsql', 'user_id' +LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT; + +CREATE OR REPLACE FUNCTION sys.database_principal_id() +RETURNS OID +AS 'babelfishpg_tsql', 'user_id_noarg' +LANGUAGE C IMMUTABLE PARALLEL SAFE; -- In tsql @@max_precision represents max precision that server supports -- As of now, we do not support change in max_precision. So, returning default value diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql index 140bce8956..ecf4c789c7 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql @@ -780,6 +780,30 @@ CREATE AGGREGATE sys.VARP(float8) ( CREATE OR REPLACE FUNCTION sys.rowcount_big() RETURNS BIGINT AS 'babelfishpg_tsql' LANGUAGE C STABLE; +CREATE OR REPLACE FUNCTION sys.database_principal_id(IN user_name sys.sysname) +RETURNS OID +AS 'babelfishpg_tsql', 'user_id' +LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT; + +CREATE OR REPLACE FUNCTION sys.database_principal_id() +RETURNS OID +AS 'babelfishpg_tsql', 'user_id_noarg' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +ALTER FUNCTION sys.user_id(TEXT) RENAME TO user_id_deprecated_in_3_2_0; + +CREATE OR REPLACE FUNCTION sys.user_id(IN user_name sys.sysname) +RETURNS OID +AS 'babelfishpg_tsql', 'user_id' +LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT; + +CREATE OR REPLACE FUNCTION sys.user_id() +RETURNS OID +AS 'babelfishpg_tsql', 'user_id_noarg' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'user_id_deprecated_in_3_2_0'); + ALTER FUNCTION sys.tsql_stat_get_activity(text) RENAME TO tsql_stat_get_activity_deprecated_in_3_2_0; CREATE OR REPLACE FUNCTION sys.tsql_stat_get_activity_deprecated_in_3_2_0( IN view_name text, @@ -1113,27 +1137,6 @@ ALTER FUNCTION sys.json_modify RENAME TO json_modify_deprecated_in_3_2_0; CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'json_modify_deprecated_in_3_2_0'); -CREATE OR REPLACE FUNCTION sys.database_principal_id(IN user_name sys.sysname DEFAULT NULL) -RETURNS OID -AS -$$ -BEGIN - -- If user_name is NULL, return the result of USER_ID() - IF user_name IS NULL OR user_name = 'NULL' THEN - RETURN NULL; - END IF; - -- Trim the trailing spaces from user_name - user_name := rtrim(user_name); - -- If user_name is an empty string or contains only spaces, return NULL - IF user_name = '' THEN - RETURN NULL; - END IF; - -- Return the principal_id of the specified user_name - RETURN (SELECT principal_id FROM sys.database_principals WHERE name = user_name); -END; -$$ -LANGUAGE PLPGSQL IMMUTABLE PARALLEL SAFE; - /* * JSON MODIFY * This function is used to update the value of a property in a JSON string and returns the updated JSON string. diff --git a/contrib/babelfishpg_tsql/src/rolecmds.c b/contrib/babelfishpg_tsql/src/rolecmds.c index 6b31bfb51d..18032b9e4a 100644 --- a/contrib/babelfishpg_tsql/src/rolecmds.c +++ b/contrib/babelfishpg_tsql/src/rolecmds.c @@ -718,38 +718,52 @@ user_id(PG_FUNCTION_ARGS) HeapTuple auth_tuple; Form_pg_authid authform; Oid ret; + size_t len; - user_input = PG_ARGISNULL(0) ? NULL : text_to_cstring(PG_GETARG_TEXT_PP(0)); + user_input = text_to_cstring(PG_GETARG_TEXT_PP(0)); db_name = get_cur_db_name(); if (!db_name) PG_RETURN_NULL(); - if (!user_input) - PG_RETURN_OID(GetUserId()); + user_name = get_physical_user_name(db_name, user_input); - user_name = get_physical_user_name(db_name, user_input); + if (!user_name) + PG_RETURN_NULL(); - if (!user_name) - PG_RETURN_NULL(); + len = strlen(user_name); + while (len > 0 && isspace(user_name[len-1])) + user_name[--len] = '\0'; - if (pltsql_case_insensitive_identifiers) - /* Lowercase the entry, if needed */ - for (char *p = user_name; *p; ++p) - *p = tolower(*p); + if (pltsql_case_insensitive_identifiers) + { + /* Lowercase the entry, if needed */ + for (char *p = user_name; *p; ++p) + *p = tolower(*p); + } - auth_tuple = SearchSysCache1(AUTHNAME, CStringGetDatum(user_name)); - if (!HeapTupleIsValid(auth_tuple)) - PG_RETURN_NULL(); + auth_tuple = SearchSysCache1(AUTHNAME, CStringGetDatum(user_name)); - authform = (Form_pg_authid) GETSTRUCT(auth_tuple); - ret = authform->oid; + if (!HeapTupleIsValid(auth_tuple)) + PG_RETURN_NULL(); + authform = (Form_pg_authid) GETSTRUCT(auth_tuple); + ret = authform->oid; ReleaseSysCache(auth_tuple); PG_RETURN_OID(ret); } +PG_FUNCTION_INFO_V1(user_id_noarg); +Datum +user_id_noarg(PG_FUNCTION_ARGS) +{ + + PG_RETURN_OID(GetUserId()); + +} + + /* * get_original_login_name - returns original login name corresponding to * supplied login by looking into babelfish_authid_login_ext catalog. diff --git a/test/JDBC/input/BABEL-1199-vu-cleanup.sql b/test/JDBC/expected/sys-userid-vu-cleanup.out similarity index 55% rename from test/JDBC/input/BABEL-1199-vu-cleanup.sql rename to test/JDBC/expected/sys-userid-vu-cleanup.out index b399ec2efe..5cc9608eeb 100644 --- a/test/JDBC/input/BABEL-1199-vu-cleanup.sql +++ b/test/JDBC/expected/sys-userid-vu-cleanup.out @@ -4,6 +4,24 @@ GO DROP PROCEDURE proc_current_principal_id; GO +DROP VIEW current_user_id_v1; +GO + +DROP PROCEDURE current_user_id_p1; +GO + +DROP VIEW current_user_id_v2; +GO + +DROP PROCEDURE current_user_id_p2; +GO + +DROP VIEW view_NULL_principal_id; +GO + +DROP PROCEDURE proc_NULL_principal_id; +GO + DROP VIEW view_db_owner_principal_id; GO @@ -20,4 +38,4 @@ DROP USER testuser; GO DROP ROLE roletest; -GO \ No newline at end of file +GO diff --git a/test/JDBC/input/BABEL-1199-vu-prepare.sql b/test/JDBC/expected/sys-userid-vu-prepare.out similarity index 55% rename from test/JDBC/input/BABEL-1199-vu-prepare.sql rename to test/JDBC/expected/sys-userid-vu-prepare.out index 52973ce8e9..a4a56dff20 100644 --- a/test/JDBC/input/BABEL-1199-vu-prepare.sql +++ b/test/JDBC/expected/sys-userid-vu-prepare.out @@ -2,6 +2,28 @@ CREATE VIEW dbo.view_current_principal_id AS SELECT user_name(DATABASE_PRINCIPAL_ID()); GO +CREATE VIEW dbo.current_user_id_v1 AS +SELECT user_name(user_id()); +GO + +CREATE PROCEDURE dbo.current_user_id_p1 +AS +BEGIN + SELECT user_name(user_id()); +END; +GO + +CREATE VIEW dbo.current_user_id_v2 AS +SELECT user_name(user_id('dbo')); +GO + +CREATE PROCEDURE dbo.current_user_id_p2 +AS +BEGIN + SELECT user_name(user_id('dbo')); +END; +GO + CREATE PROCEDURE dbo.proc_current_principal_id AS BEGIN @@ -9,6 +31,17 @@ BEGIN END; GO +CREATE VIEW dbo.view_NULL_principal_id AS +SELECT (DATABASE_PRINCIPAL_ID(NULL)); +GO + +CREATE PROCEDURE dbo.proc_NULL_principal_id +AS +BEGIN + SELECT (DATABASE_PRINCIPAL_ID(NULL)); +END; +GO + CREATE VIEW dbo.view_db_owner_principal_id AS SELECT user_name(DATABASE_PRINCIPAL_ID('db_owner')); GO @@ -27,4 +60,4 @@ GO CREATE LOGIN testuser WITH PASSWORD = 'testpassword'; CREATE USER testuser FOR LOGIN testuser; CREATE ROLE roletest; -GO \ No newline at end of file +GO diff --git a/test/JDBC/expected/BABEL-1199-vu-verify.out b/test/JDBC/expected/sys-userid-vu-verify.out similarity index 61% rename from test/JDBC/expected/BABEL-1199-vu-verify.out rename to test/JDBC/expected/sys-userid-vu-verify.out index 227e00b955..c9ffe4edcb 100644 --- a/test/JDBC/expected/BABEL-1199-vu-verify.out +++ b/test/JDBC/expected/sys-userid-vu-verify.out @@ -14,6 +14,54 @@ dbo ~~END~~ +SELECT * FROM current_user_id_v1; +GO +~~START~~ +nvarchar +dbo +~~END~~ + + +EXEC current_user_id_p1; +GO +~~START~~ +nvarchar +dbo +~~END~~ + + +SELECT * FROM current_user_id_v2; +GO +~~START~~ +nvarchar +dbo +~~END~~ + + +EXEC current_user_id_p2; +GO +~~START~~ +nvarchar +dbo +~~END~~ + + +SELECT * FROM view_NULL_principal_id; +GO +~~START~~ +int + +~~END~~ + + +EXEC proc_NULL_principal_id; +GO +~~START~~ +int + +~~END~~ + + SELECT * FROM view_db_owner_principal_id; GO ~~START~~ @@ -95,10 +143,34 @@ db_owner ~~END~~ -SELECT DATABASE_PRINCIPAL_ID('NULL') +SELECT user_name(DATABASE_PRINCIPAL_ID()); +GO +~~START~~ +nvarchar +dbo +~~END~~ + + +SELECT DATABASE_PRINCIPAL_ID('test_me') +GO +~~START~~ +int + +~~END~~ + + +SELECT DATABASE_PRINCIPAL_ID(NULL) GO ~~START~~ int ~~END~~ + +SELECT user_name(user_id()); +GO +~~START~~ +nvarchar +dbo +~~END~~ + diff --git a/test/JDBC/expected/BABEL-1199-vu-cleanup.out b/test/JDBC/input/functions/sys-userid-vu-cleanup.sql similarity index 56% rename from test/JDBC/expected/BABEL-1199-vu-cleanup.out rename to test/JDBC/input/functions/sys-userid-vu-cleanup.sql index 0f6d3d8efc..504afe5653 100644 --- a/test/JDBC/expected/BABEL-1199-vu-cleanup.out +++ b/test/JDBC/input/functions/sys-userid-vu-cleanup.sql @@ -4,6 +4,24 @@ GO DROP PROCEDURE proc_current_principal_id; GO +DROP VIEW current_user_id_v1; +GO + +DROP PROCEDURE current_user_id_p1; +GO + +DROP VIEW current_user_id_v2; +GO + +DROP PROCEDURE current_user_id_p2; +GO + +DROP VIEW view_NULL_principal_id; +GO + +DROP PROCEDURE proc_NULL_principal_id; +GO + DROP VIEW view_db_owner_principal_id; GO @@ -20,4 +38,4 @@ DROP USER testuser; GO DROP ROLE roletest; -GO +GO \ No newline at end of file diff --git a/test/JDBC/expected/BABEL-1199-vu-prepare.out b/test/JDBC/input/functions/sys-userid-vu-prepare.sql similarity index 55% rename from test/JDBC/expected/BABEL-1199-vu-prepare.out rename to test/JDBC/input/functions/sys-userid-vu-prepare.sql index 398ccdc312..e5d9c1e418 100644 --- a/test/JDBC/expected/BABEL-1199-vu-prepare.out +++ b/test/JDBC/input/functions/sys-userid-vu-prepare.sql @@ -2,6 +2,28 @@ CREATE VIEW dbo.view_current_principal_id AS SELECT user_name(DATABASE_PRINCIPAL_ID()); GO +CREATE VIEW dbo.current_user_id_v1 AS +SELECT user_name(user_id()); +GO + +CREATE PROCEDURE dbo.current_user_id_p1 +AS +BEGIN + SELECT user_name(user_id()); +END; +GO + +CREATE VIEW dbo.current_user_id_v2 AS +SELECT user_name(user_id('dbo')); +GO + +CREATE PROCEDURE dbo.current_user_id_p2 +AS +BEGIN + SELECT user_name(user_id('dbo')); +END; +GO + CREATE PROCEDURE dbo.proc_current_principal_id AS BEGIN @@ -9,6 +31,17 @@ BEGIN END; GO +CREATE VIEW dbo.view_NULL_principal_id AS +SELECT (DATABASE_PRINCIPAL_ID(NULL)); +GO + +CREATE PROCEDURE dbo.proc_NULL_principal_id +AS +BEGIN + SELECT (DATABASE_PRINCIPAL_ID(NULL)); +END; +GO + CREATE VIEW dbo.view_db_owner_principal_id AS SELECT user_name(DATABASE_PRINCIPAL_ID('db_owner')); GO @@ -27,4 +60,4 @@ GO CREATE LOGIN testuser WITH PASSWORD = 'testpassword'; CREATE USER testuser FOR LOGIN testuser; CREATE ROLE roletest; -GO +GO \ No newline at end of file diff --git a/test/JDBC/input/BABEL-1199-vu-verify.sql b/test/JDBC/input/functions/sys-userid-vu-verify.sql similarity index 61% rename from test/JDBC/input/BABEL-1199-vu-verify.sql rename to test/JDBC/input/functions/sys-userid-vu-verify.sql index 6f6cd9b8ee..cd20671b62 100644 --- a/test/JDBC/input/BABEL-1199-vu-verify.sql +++ b/test/JDBC/input/functions/sys-userid-vu-verify.sql @@ -4,6 +4,24 @@ GO EXEC proc_current_principal_id; GO +SELECT * FROM current_user_id_v1; +GO + +EXEC current_user_id_p1; +GO + +SELECT * FROM current_user_id_v2; +GO + +EXEC current_user_id_p2; +GO + +SELECT * FROM view_NULL_principal_id; +GO + +EXEC proc_NULL_principal_id; +GO + SELECT * FROM view_db_owner_principal_id; GO @@ -35,5 +53,14 @@ GO SELECT user_name(DATABASE_PRINCIPAL_ID('db_owner ')); GO -SELECT DATABASE_PRINCIPAL_ID('NULL') -GO \ No newline at end of file +SELECT user_name(DATABASE_PRINCIPAL_ID()); +GO + +SELECT DATABASE_PRINCIPAL_ID('test_me') +GO + +SELECT DATABASE_PRINCIPAL_ID(NULL) +GO + +SELECT user_name(user_id()); +GO diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index ed563e7d5a..975bc2fab3 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -411,7 +411,7 @@ test_windows_alter_user BABEL-733 BABEL-745 BABEL-3938 -BABEL-1199 +sys-userid BABEL-NEXT-VALUE-FOR babel_context_info binary-index diff --git a/test/python/expected/upgrade_validation/expected_dependency.out b/test/python/expected/upgrade_validation/expected_dependency.out index fda3b66ffc..1bdf6b9f7b 100644 --- a/test/python/expected/upgrade_validation/expected_dependency.out +++ b/test/python/expected/upgrade_validation/expected_dependency.out @@ -662,7 +662,6 @@ Function sys.uniqueidentifier_cmp(sys.uniqueidentifier,sys.uniqueidentifier) Function sys.uniqueidentifier_hash(sys.uniqueidentifier) Function sys.uniqueidentifier_sqlvariant(sys.uniqueidentifier) Function sys.update(text) -Function sys.user_id(text) Function sys.user_name_sysname() Function sys.varbinary(sys.varbinary,integer,boolean) Function sys.varbinary2uniqueidentifier(sys.bbf_varbinary,integer,boolean) From a743e7c883a80b5afa4c232894a1142c2e46d65d Mon Sep 17 00:00:00 2001 From: Jake Owen Date: Wed, 12 Apr 2023 15:34:31 -0400 Subject: [PATCH 054/363] Alter table crash in antlr parser unsupported feature (#1421) * Alter table crash in antlr parser unsupported feature Signed-off-by: Jake Owen Task: BABEL-3818 --- .../src/tsqlUnsupportedFeatureHandler.cpp | 18 +++--- test/JDBC/expected/BABEL-3818-vu-cleanup.out | 2 + test/JDBC/expected/BABEL-3818-vu-prepare.out | 10 ++++ test/JDBC/expected/BABEL-3818-vu-verify.out | 57 +++++++++++++++++++ test/JDBC/input/BABEL-3818-vu-cleanup.sql | 2 + test/JDBC/input/BABEL-3818-vu-prepare.sql | 8 +++ test/JDBC/input/BABEL-3818-vu-verify.sql | 29 ++++++++++ test/JDBC/upgrade/14_3/schedule | 1 + test/JDBC/upgrade/14_5/schedule | 1 + test/JDBC/upgrade/14_6/schedule | 1 + test/JDBC/upgrade/14_7/schedule | 1 + test/JDBC/upgrade/14_8/schedule | 1 + test/JDBC/upgrade/15_1/schedule | 1 + test/JDBC/upgrade/15_2/schedule | 1 + test/JDBC/upgrade/latest/schedule | 1 + 15 files changed, 126 insertions(+), 8 deletions(-) create mode 100644 test/JDBC/expected/BABEL-3818-vu-cleanup.out create mode 100644 test/JDBC/expected/BABEL-3818-vu-prepare.out create mode 100644 test/JDBC/expected/BABEL-3818-vu-verify.out create mode 100644 test/JDBC/input/BABEL-3818-vu-cleanup.sql create mode 100644 test/JDBC/input/BABEL-3818-vu-prepare.sql create mode 100644 test/JDBC/input/BABEL-3818-vu-verify.sql diff --git a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp index 1c36f5ec21..c284ce9413 100644 --- a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp @@ -737,16 +737,18 @@ antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitAlter_table(TSqlParser::Al if (ctx->COLUMN()) // ALTER TABLE ... ALTER COLUMN { - Assert(ctx->column_definition()); auto cdctx = ctx->column_definition(); - if (!cdctx->collation().empty()) - handle(INSTR_UNSUPPORTED_TSQL_ALTER_TABLE_ALTER_COLUMN_COLLATE, "COLLATE in ALTER TABLE ALTER COLUMN", getLineAndPos(cdctx)); - if (!cdctx->null_notnull().empty()) + if(cdctx) { - if (cdctx->null_notnull()[0]->NOT()) - handle(INSTR_UNSUPPORTED_TSQL_ALTER_TABLE_ALTER_COLUMN_NOT_NULL, "NOT NULL in ALTER TABLE ALTER COLUMN", getLineAndPos(cdctx)); - else - handle(INSTR_UNSUPPORTED_TSQL_ALTER_TABLE_ALTER_COLUMN_NULL, "NULL in ALTER TABLE ALTER COLUMN", getLineAndPos(cdctx)); + if (!cdctx->collation().empty()) + handle(INSTR_UNSUPPORTED_TSQL_ALTER_TABLE_ALTER_COLUMN_COLLATE, "COLLATE in ALTER TABLE ALTER COLUMN", getLineAndPos(cdctx)); + if (!cdctx->null_notnull().empty()) + { + if (cdctx->null_notnull()[0]->NOT()) + handle(INSTR_UNSUPPORTED_TSQL_ALTER_TABLE_ALTER_COLUMN_NOT_NULL, "NOT NULL in ALTER TABLE ALTER COLUMN", getLineAndPos(cdctx)); + else + handle(INSTR_UNSUPPORTED_TSQL_ALTER_TABLE_ALTER_COLUMN_NULL, "NULL in ALTER TABLE ALTER COLUMN", getLineAndPos(cdctx)); + } } } diff --git a/test/JDBC/expected/BABEL-3818-vu-cleanup.out b/test/JDBC/expected/BABEL-3818-vu-cleanup.out new file mode 100644 index 0000000000..755acefa1a --- /dev/null +++ b/test/JDBC/expected/BABEL-3818-vu-cleanup.out @@ -0,0 +1,2 @@ +drop table cities; +go diff --git a/test/JDBC/expected/BABEL-3818-vu-prepare.out b/test/JDBC/expected/BABEL-3818-vu-prepare.out new file mode 100644 index 0000000000..5af587594d --- /dev/null +++ b/test/JDBC/expected/BABEL-3818-vu-prepare.out @@ -0,0 +1,10 @@ +Create Table cities (name varchar(250)); +GO + +alter table cities add region varchar(50) constraint defRegion default 'NEW ENGLAND'; +GO + +insert into cities (name) VALUES ('Boston'); +GO +~~ROW COUNT: 1~~ + diff --git a/test/JDBC/expected/BABEL-3818-vu-verify.out b/test/JDBC/expected/BABEL-3818-vu-verify.out new file mode 100644 index 0000000000..5ea34f2128 --- /dev/null +++ b/test/JDBC/expected/BABEL-3818-vu-verify.out @@ -0,0 +1,57 @@ +-- Should throw unsupported feature error instead of crashing +alter table cities alter column region drop default defRegion +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'DROP DEFAULT' is not currently supported in Babelfish)~~ + + +-- Should throw unsupported feature error +alter table cities alter column region varchar(50) drop default defRegion +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'DROP DEFAULT' is not currently supported in Babelfish)~~ + + +-- Should throw syntax error +alter table cities alter region varchar(50) drop default defRegion +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near 'region' at line 2 and character position 25)~~ + + +-- Should throw syntax error +alter table cities alter region drop default defRegion +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near 'region' at line 2 and character position 25)~~ + + + +-- Ensure alter table alter column: collate, not null, and null +-- still throw unsupported feature error +alter table cities alter column region varchar(25) collate test +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'COLLATE in ALTER TABLE ALTER COLUMN' is not currently supported in Babelfish)~~ + + +alter table cities alter column region varchar(50) not null +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'NOT NULL in ALTER TABLE ALTER COLUMN' is not currently supported in Babelfish)~~ + + +alter table cities alter column region varchar(50) null +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'NULL in ALTER TABLE ALTER COLUMN' is not currently supported in Babelfish)~~ + + + diff --git a/test/JDBC/input/BABEL-3818-vu-cleanup.sql b/test/JDBC/input/BABEL-3818-vu-cleanup.sql new file mode 100644 index 0000000000..398dc06b07 --- /dev/null +++ b/test/JDBC/input/BABEL-3818-vu-cleanup.sql @@ -0,0 +1,2 @@ +drop table cities; +go \ No newline at end of file diff --git a/test/JDBC/input/BABEL-3818-vu-prepare.sql b/test/JDBC/input/BABEL-3818-vu-prepare.sql new file mode 100644 index 0000000000..17a3171caa --- /dev/null +++ b/test/JDBC/input/BABEL-3818-vu-prepare.sql @@ -0,0 +1,8 @@ +Create Table cities (name varchar(250)); +GO + +alter table cities add region varchar(50) constraint defRegion default 'NEW ENGLAND'; +GO + +insert into cities (name) VALUES ('Boston'); +GO \ No newline at end of file diff --git a/test/JDBC/input/BABEL-3818-vu-verify.sql b/test/JDBC/input/BABEL-3818-vu-verify.sql new file mode 100644 index 0000000000..bdcedd304b --- /dev/null +++ b/test/JDBC/input/BABEL-3818-vu-verify.sql @@ -0,0 +1,29 @@ +-- Should throw unsupported feature error instead of crashing +alter table cities alter column region drop default defRegion +GO + +-- Should throw unsupported feature error +alter table cities alter column region varchar(50) drop default defRegion +GO + +-- Should throw syntax error +alter table cities alter region varchar(50) drop default defRegion +GO + +-- Should throw syntax error +alter table cities alter region drop default defRegion +GO + +-- Ensure alter table alter column: collate, not null, and null +-- still throw unsupported feature error + +alter table cities alter column region varchar(25) collate test +go + +alter table cities alter column region varchar(50) not null +go + +alter table cities alter column region varchar(50) null +go + + diff --git a/test/JDBC/upgrade/14_3/schedule b/test/JDBC/upgrade/14_3/schedule index fb83007c8e..b8625299a2 100644 --- a/test/JDBC/upgrade/14_3/schedule +++ b/test/JDBC/upgrade/14_3/schedule @@ -323,6 +323,7 @@ binary-index rowcount BABEL-1625 BABEL-3474 +BABEL-3818 datetime2fromparts timefromparts BABEL-3215 diff --git a/test/JDBC/upgrade/14_5/schedule b/test/JDBC/upgrade/14_5/schedule index d89345313d..c3705c0492 100644 --- a/test/JDBC/upgrade/14_5/schedule +++ b/test/JDBC/upgrade/14_5/schedule @@ -336,6 +336,7 @@ BABEL-3938 binary-index rowcount BABEL-1625 +BABEL-3818 BABEL-3474 datetime2fromparts timefromparts diff --git a/test/JDBC/upgrade/14_6/schedule b/test/JDBC/upgrade/14_6/schedule index e0b35135b4..2dc690061d 100644 --- a/test/JDBC/upgrade/14_6/schedule +++ b/test/JDBC/upgrade/14_6/schedule @@ -363,6 +363,7 @@ binary-index rowcount BABEL-1625 BABEL-3474 +BABEL-3818 dateadd_internal_df datetime2fromparts timefromparts diff --git a/test/JDBC/upgrade/14_7/schedule b/test/JDBC/upgrade/14_7/schedule index df6bb56b1f..cf1ded9dee 100644 --- a/test/JDBC/upgrade/14_7/schedule +++ b/test/JDBC/upgrade/14_7/schedule @@ -394,6 +394,7 @@ BABEL-745 rowcount BABEL-1625 BABEL-3474 +BABEL-3818 dateadd_internal_df datetime2fromparts timefromparts diff --git a/test/JDBC/upgrade/14_8/schedule b/test/JDBC/upgrade/14_8/schedule index 52ef6eb15f..1582912acc 100644 --- a/test/JDBC/upgrade/14_8/schedule +++ b/test/JDBC/upgrade/14_8/schedule @@ -389,6 +389,7 @@ BABEL-3657 BABEL-733 BABEL-3938 binary-index +BABEL-3818 rowcount BABEL-1625 BABEL-3474 diff --git a/test/JDBC/upgrade/15_1/schedule b/test/JDBC/upgrade/15_1/schedule index 7440c6868d..0772c69168 100644 --- a/test/JDBC/upgrade/15_1/schedule +++ b/test/JDBC/upgrade/15_1/schedule @@ -372,6 +372,7 @@ binary-index rowcount BABEL-1625 BABEL-3474 +BABEL-3818 dateadd_internal_df datetime2fromparts timefromparts diff --git a/test/JDBC/upgrade/15_2/schedule b/test/JDBC/upgrade/15_2/schedule index 354f53a13f..b0eeaa0175 100644 --- a/test/JDBC/upgrade/15_2/schedule +++ b/test/JDBC/upgrade/15_2/schedule @@ -398,6 +398,7 @@ sys-systypes openjson BABEL-3702 BABEL_OBJECT_DEFINITION +BABEL-3818 Test-sp_rename Test-sp_rename-dep # openquery_upgrd diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index 975bc2fab3..c64263ce5e 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -420,6 +420,7 @@ BABEL-3478 rowcount BABEL-1625 BABEL-3474 +BABEL-3818 dateadd_internal_df datetime2fromparts-after-15-2 timefromparts From 388038e094ba209f2c088640094013a6e0b5c291 Mon Sep 17 00:00:00 2001 From: Yanjie Xu Date: Wed, 12 Apr 2023 17:46:09 -0400 Subject: [PATCH 055/363] Support sysusers catalog We add support to sys.sysusers catalog which is not in Babelfish previously. Task: BABEL-2974 Signed-off-by: Yanjie Xu --- contrib/babelfishpg_tsql/sql/ownership.sql | 44 +++++++ .../babelfishpg_tsql--3.1.0--3.2.0.sql | 44 +++++++ .../expected/sys_sysusers_dep-vu-cleanup.out | 29 +++++ .../expected/sys_sysusers_dep-vu-prepare.out | 43 +++++++ .../expected/sys_sysusers_dep-vu-verify.out | 110 ++++++++++++++++++ .../ownership/sys_sysusers_dep-vu-cleanup.sql | 29 +++++ .../ownership/sys_sysusers_dep-vu-prepare.sql | 43 +++++++ .../ownership/sys_sysusers_dep-vu-verify.sql | 58 +++++++++ test/JDBC/upgrade/latest/schedule | 1 + 9 files changed, 401 insertions(+) create mode 100644 test/JDBC/expected/sys_sysusers_dep-vu-cleanup.out create mode 100644 test/JDBC/expected/sys_sysusers_dep-vu-prepare.out create mode 100644 test/JDBC/expected/sys_sysusers_dep-vu-verify.out create mode 100644 test/JDBC/input/ownership/sys_sysusers_dep-vu-cleanup.sql create mode 100644 test/JDBC/input/ownership/sys_sysusers_dep-vu-prepare.sql create mode 100644 test/JDBC/input/ownership/sys_sysusers_dep-vu-verify.sql diff --git a/contrib/babelfishpg_tsql/sql/ownership.sql b/contrib/babelfishpg_tsql/sql/ownership.sql index 5508447a9d..d3ec44abd5 100644 --- a/contrib/babelfishpg_tsql/sql/ownership.sql +++ b/contrib/babelfishpg_tsql/sql/ownership.sql @@ -392,6 +392,50 @@ FROM (VALUES ('public', 'R'), ('sys', 'S'), ('INFORMATION_SCHEMA', 'S')) as dumm GRANT SELECT ON sys.database_principals TO PUBLIC; +-- SYSUSERS +CREATE OR REPLACE VIEW sys.sysusers AS SELECT +Dbp.principal_id AS uid, +CAST(0 AS INT) AS status, +Dbp.name AS name, +Dbp.sid AS sid, +CAST(NULL AS SYS.VARBINARY(2048)) AS roles, +Dbp.create_date AS createdate, +Dbp.modify_date AS updatedate, +CAST(0 AS INT) AS altuid, +CAST(NULL AS SYS.VARBINARY(256)) AS password, +CAST(0 AS INT) AS gid, +CAST(NULL AS SYS.VARCHAR(85)) AS environ, +CASE + WHEN Dbp.name = 'INFORMATION_SCHEMA' + OR Dbp.name = 'sys' + OR Dbp.type_desc = 'DATABASE_ROLE' + THEN 0 + WHEN (Dbp.type_desc = 'WINDOWS_USER' OR Dbp.type_desc = 'SQL_USER') AND Ext.user_can_connect = 1 THEN 1 + ELSE 0 +END AS hasdbaccess, +CASE + WHEN Dbp.name = 'INFORMATION_SCHEMA' + OR Dbp.name = 'sys' + OR Dbp.name = 'guest' + OR Dbp.name = 'dbo' + THEN 1 + WHEN Dbp.type_desc = 'WINDOWS_USER' OR Dbp.type_desc = 'SQL_USER' THEN 1 + ELSE 0 +END AS islogin, +CASE WHEN Dbp.type_desc = 'WINDOWS_USER' THEN 1 ELSE 0 END AS isntname, +CAST(0 AS INT) AS isntgroup, +CASE WHEN Dbp.type_desc = 'WINDOWS_USER' THEN 1 ELSE 0 END AS isntuser, +CASE WHEN Dbp.type_desc = 'SQL_USER' THEN 1 ELSE 0 END AS issqluser, +CAST(0 AS INT) AS isaliased, +CASE WHEN Dbp.type_desc = 'DATABASE_ROLE' THEN 1 ELSE 0 END AS issqlrole, +CAST(0 AS INT) AS isapprole +FROM sys.database_principals AS Dbp LEFT JOIN + (SELECT orig_username, user_can_connect FROM sys.babelfish_authid_user_ext + WHERE database_name = DB_NAME()) AS Ext +ON Dbp.name = Ext.orig_username; + +GRANT SELECT ON sys.sysusers TO PUBLIC; + -- DATABASE_ROLE_MEMBERS CREATE OR REPLACE VIEW sys.database_role_members AS SELECT diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql index ecf4c789c7..2073d2343e 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql @@ -37,6 +37,50 @@ LANGUAGE plpgsql; * So make sure that any SQL statement (DDL/DML) being added here can be executed multiple times without affecting * final behaviour. */ + +-- SYSUSERS +CREATE OR REPLACE VIEW sys.sysusers AS SELECT +Dbp.principal_id AS uid, +CAST(0 AS INT) AS status, +Dbp.name AS name, +Dbp.sid AS sid, +CAST(NULL AS SYS.VARBINARY(2048)) AS roles, +Dbp.create_date AS createdate, +Dbp.modify_date AS updatedate, +CAST(0 AS INT) AS altuid, +CAST(NULL AS SYS.VARBINARY(256)) AS password, +CAST(0 AS INT) AS gid, +CAST(NULL AS SYS.VARCHAR(85)) AS environ, +CASE + WHEN Dbp.name = 'INFORMATION_SCHEMA' + OR Dbp.name = 'sys' + OR Dbp.type_desc = 'DATABASE_ROLE' + THEN 0 + WHEN (Dbp.type_desc = 'WINDOWS_USER' OR Dbp.type_desc = 'SQL_USER') AND Ext.user_can_connect = 1 THEN 1 + ELSE 0 +END AS hasdbaccess, +CASE + WHEN Dbp.name = 'INFORMATION_SCHEMA' + OR Dbp.name = 'sys' + OR Dbp.name = 'guest' + OR Dbp.name = 'dbo' + THEN 1 + WHEN Dbp.type_desc = 'WINDOWS_USER' OR Dbp.type_desc = 'SQL_USER' THEN 1 + ELSE 0 +END AS islogin, +CASE WHEN Dbp.type_desc = 'WINDOWS_USER' THEN 1 ELSE 0 END AS isntname, +CAST(0 AS INT) AS isntgroup, +CASE WHEN Dbp.type_desc = 'WINDOWS_USER' THEN 1 ELSE 0 END AS isntuser, +CASE WHEN Dbp.type_desc = 'SQL_USER' THEN 1 ELSE 0 END AS issqluser, +CAST(0 AS INT) AS isaliased, +CASE WHEN Dbp.type_desc = 'DATABASE_ROLE' THEN 1 ELSE 0 END AS issqlrole, +CAST(0 AS INT) AS isapprole +FROM sys.database_principals AS Dbp LEFT JOIN + (SELECT orig_username, user_can_connect FROM sys.babelfish_authid_user_ext + WHERE database_name = DB_NAME()) AS Ext +ON Dbp.name = Ext.orig_username; + +GRANT SELECT ON sys.sysusers TO PUBLIC; CREATE OR REPLACE VIEW sys.syslanguages AS diff --git a/test/JDBC/expected/sys_sysusers_dep-vu-cleanup.out b/test/JDBC/expected/sys_sysusers_dep-vu-cleanup.out new file mode 100644 index 0000000000..ed9c7b8db6 --- /dev/null +++ b/test/JDBC/expected/sys_sysusers_dep-vu-cleanup.out @@ -0,0 +1,29 @@ +USE sysusersdb +GO + +DROP VIEW sysusers_dep_vu_prepare_view +GO + +DROP PROC sysusers_dep_vu_prepare_proc +GO + +DROP FUNCTION sysusers_dep_vu_prepare_func +GO + +DROP USER sysusers_dep_vu_prepare_user1 +GO + +DROP USER sysusers_dep_vu_prepare_user2 +GO + +DROP LOGIN sysusers_dep_vu_prepare_login1 +GO + +DROP LOGIN sysusers_dep_vu_prepare_login2 +GO + +USE master +GO + +DROP DATABASE sysusersdb +GO diff --git a/test/JDBC/expected/sys_sysusers_dep-vu-prepare.out b/test/JDBC/expected/sys_sysusers_dep-vu-prepare.out new file mode 100644 index 0000000000..1ec95026a2 --- /dev/null +++ b/test/JDBC/expected/sys_sysusers_dep-vu-prepare.out @@ -0,0 +1,43 @@ +CREATE DATABASE sysusersdb +GO + +USE sysusersdb +GO + +CREATE LOGIN sysusers_dep_vu_prepare_login1 WITH PASSWORD = '123' +GO + +CREATE USER sysusers_dep_vu_prepare_user1 FOR LOGIN sysusers_dep_vu_prepare_login1 +GO + +CREATE LOGIN sysusers_dep_vu_prepare_login2 WITH PASSWORD = '123' +GO + +CREATE USER sysusers_dep_vu_prepare_user2 FOR LOGIN sysusers_dep_vu_prepare_login2; +GO + +CREATE VIEW sysusers_dep_vu_prepare_view +AS +SELECT name, hasdbaccess, islogin, isntname, issqluser, issqlrole +FROM sys.sysusers +WHERE name LIKE '%sysusers_dep_vu_prepare_%' OR name = 'dbo' or name = 'guest' +ORDER BY name offset 0 rows +GO + +CREATE PROC sysusers_dep_vu_prepare_proc +AS +SELECT name, hasdbaccess, islogin, isntname, issqluser, issqlrole +FROM sys.sysusers +WHERE name LIKE '%sysusers_dep_vu_prepare_%' OR name = 'dbo' or name = 'guest' +ORDER BY name +GO + +CREATE FUNCTION sysusers_dep_vu_prepare_func() +RETURNS TABLE +AS +RETURN + SELECT name, hasdbaccess, islogin, isntname, issqluser, issqlrole + FROM sys.sysusers + WHERE name LIKE '%sysusers_dep_vu_prepare_%' OR name = 'dbo' or name = 'guest' + ORDER BY name offset 0 rows +GO diff --git a/test/JDBC/expected/sys_sysusers_dep-vu-verify.out b/test/JDBC/expected/sys_sysusers_dep-vu-verify.out new file mode 100644 index 0000000000..86eaad1403 --- /dev/null +++ b/test/JDBC/expected/sys_sysusers_dep-vu-verify.out @@ -0,0 +1,110 @@ +USE sysusersdb +GO + +-- test view created on sys.sysusers +SELECT * FROM sysusers_dep_vu_prepare_view +GO +~~START~~ +varchar#!#int#!#int#!#int#!#int#!#int +dbo#!#1#!#1#!#0#!#1#!#0 +guest#!#0#!#1#!#0#!#1#!#0 +sysusers_dep_vu_prepare_user1#!#1#!#1#!#0#!#1#!#0 +sysusers_dep_vu_prepare_user2#!#1#!#1#!#0#!#1#!#0 +~~END~~ + + +-- test procedure created on sys.sysusers +EXEC sysusers_dep_vu_prepare_proc +GO +~~START~~ +varchar#!#int#!#int#!#int#!#int#!#int +dbo#!#1#!#1#!#0#!#1#!#0 +guest#!#0#!#1#!#0#!#1#!#0 +sysusers_dep_vu_prepare_user1#!#1#!#1#!#0#!#1#!#0 +sysusers_dep_vu_prepare_user2#!#1#!#1#!#0#!#1#!#0 +~~END~~ + + +-- test function created on sys.sysusers +SELECT * FROM sysusers_dep_vu_prepare_func() +GO +~~START~~ +varchar#!#int#!#int#!#int#!#int#!#int +dbo#!#1#!#1#!#0#!#1#!#0 +guest#!#0#!#1#!#0#!#1#!#0 +sysusers_dep_vu_prepare_user1#!#1#!#1#!#0#!#1#!#0 +sysusers_dep_vu_prepare_user2#!#1#!#1#!#0#!#1#!#0 +~~END~~ + + +-- test sys.sysusers view, hasdbaccess should be 1 for newly created user +SELECT name, hasdbaccess, islogin, isntname, issqluser, issqlrole +FROM sys.sysusers +WHERE name LIKE '%sysusers_dep_vu_prepare_%' OR name = 'dbo' or name = 'guest' +ORDER BY name +GO +~~START~~ +varchar#!#int#!#int#!#int#!#int#!#int +dbo#!#1#!#1#!#0#!#1#!#0 +guest#!#0#!#1#!#0#!#1#!#0 +sysusers_dep_vu_prepare_user1#!#1#!#1#!#0#!#1#!#0 +sysusers_dep_vu_prepare_user2#!#1#!#1#!#0#!#1#!#0 +~~END~~ + + +-- test [GRANT CONNECT TO], hasdbaccess should be 1 +GRANT CONNECT TO guest +GO + +SELECT name, hasdbaccess, islogin +FROM sys.sysusers +WHERE name = 'guest' +GO +~~START~~ +varchar#!#int#!#int +guest#!#1#!#1 +~~END~~ + + +-- test [REVOKE CONNECT FROM], hasdbaccess should be 0 +REVOKE CONNECT FROM guest +GO + +SELECT name, hasdbaccess, islogin +FROM sys.sysusers +WHERE name = 'guest' +GO +~~START~~ +varchar#!#int#!#int +guest#!#0#!#1 +~~END~~ + + +-- test [REVOKE CONNECT FROM], hasdbaccess should be 0 +REVOKE CONNECT FROM sysusers_dep_vu_prepare_user1 +GO + +SELECT name, hasdbaccess, islogin +FROM sys.sysusers +WHERE name = 'sysusers_dep_vu_prepare_user1' +GO +~~START~~ +varchar#!#int#!#int +sysusers_dep_vu_prepare_user1#!#0#!#1 +~~END~~ + + +-- test [GRANT CONNECT TO], hasdbaccess should be 1 +GRANT CONNECT TO sysusers_dep_vu_prepare_user1 +GO + +SELECT name, hasdbaccess, islogin +FROM sys.sysusers +WHERE name = 'sysusers_dep_vu_prepare_user1' +GO +~~START~~ +varchar#!#int#!#int +sysusers_dep_vu_prepare_user1#!#1#!#1 +~~END~~ + + diff --git a/test/JDBC/input/ownership/sys_sysusers_dep-vu-cleanup.sql b/test/JDBC/input/ownership/sys_sysusers_dep-vu-cleanup.sql new file mode 100644 index 0000000000..50926485eb --- /dev/null +++ b/test/JDBC/input/ownership/sys_sysusers_dep-vu-cleanup.sql @@ -0,0 +1,29 @@ +USE sysusersdb +GO + +DROP VIEW sysusers_dep_vu_prepare_view +GO + +DROP PROC sysusers_dep_vu_prepare_proc +GO + +DROP FUNCTION sysusers_dep_vu_prepare_func +GO + +DROP USER sysusers_dep_vu_prepare_user1 +GO + +DROP USER sysusers_dep_vu_prepare_user2 +GO + +DROP LOGIN sysusers_dep_vu_prepare_login1 +GO + +DROP LOGIN sysusers_dep_vu_prepare_login2 +GO + +USE master +GO + +DROP DATABASE sysusersdb +GO \ No newline at end of file diff --git a/test/JDBC/input/ownership/sys_sysusers_dep-vu-prepare.sql b/test/JDBC/input/ownership/sys_sysusers_dep-vu-prepare.sql new file mode 100644 index 0000000000..37b98ea84d --- /dev/null +++ b/test/JDBC/input/ownership/sys_sysusers_dep-vu-prepare.sql @@ -0,0 +1,43 @@ +CREATE DATABASE sysusersdb +GO + +USE sysusersdb +GO + +CREATE LOGIN sysusers_dep_vu_prepare_login1 WITH PASSWORD = '123' +GO + +CREATE USER sysusers_dep_vu_prepare_user1 FOR LOGIN sysusers_dep_vu_prepare_login1 +GO + +CREATE LOGIN sysusers_dep_vu_prepare_login2 WITH PASSWORD = '123' +GO + +CREATE USER sysusers_dep_vu_prepare_user2 FOR LOGIN sysusers_dep_vu_prepare_login2; +GO + +CREATE VIEW sysusers_dep_vu_prepare_view +AS +SELECT name, hasdbaccess, islogin, isntname, issqluser, issqlrole +FROM sys.sysusers +WHERE name LIKE '%sysusers_dep_vu_prepare_%' OR name = 'dbo' or name = 'guest' +ORDER BY name offset 0 rows +GO + +CREATE PROC sysusers_dep_vu_prepare_proc +AS +SELECT name, hasdbaccess, islogin, isntname, issqluser, issqlrole +FROM sys.sysusers +WHERE name LIKE '%sysusers_dep_vu_prepare_%' OR name = 'dbo' or name = 'guest' +ORDER BY name +GO + +CREATE FUNCTION sysusers_dep_vu_prepare_func() +RETURNS TABLE +AS +RETURN + SELECT name, hasdbaccess, islogin, isntname, issqluser, issqlrole + FROM sys.sysusers + WHERE name LIKE '%sysusers_dep_vu_prepare_%' OR name = 'dbo' or name = 'guest' + ORDER BY name offset 0 rows +GO \ No newline at end of file diff --git a/test/JDBC/input/ownership/sys_sysusers_dep-vu-verify.sql b/test/JDBC/input/ownership/sys_sysusers_dep-vu-verify.sql new file mode 100644 index 0000000000..3f08bd9c21 --- /dev/null +++ b/test/JDBC/input/ownership/sys_sysusers_dep-vu-verify.sql @@ -0,0 +1,58 @@ +USE sysusersdb +GO + +-- test view created on sys.sysusers +SELECT * FROM sysusers_dep_vu_prepare_view +GO + +-- test procedure created on sys.sysusers +EXEC sysusers_dep_vu_prepare_proc +GO + +-- test function created on sys.sysusers +SELECT * FROM sysusers_dep_vu_prepare_func() +GO + +-- test sys.sysusers view, hasdbaccess should be 1 for newly created user +SELECT name, hasdbaccess, islogin, isntname, issqluser, issqlrole +FROM sys.sysusers +WHERE name LIKE '%sysusers_dep_vu_prepare_%' OR name = 'dbo' or name = 'guest' +ORDER BY name +GO + +-- test [GRANT CONNECT TO], hasdbaccess should be 1 +GRANT CONNECT TO guest +GO + +SELECT name, hasdbaccess, islogin +FROM sys.sysusers +WHERE name = 'guest' +GO + +-- test [REVOKE CONNECT FROM], hasdbaccess should be 0 +REVOKE CONNECT FROM guest +GO + +SELECT name, hasdbaccess, islogin +FROM sys.sysusers +WHERE name = 'guest' +GO + +-- test [REVOKE CONNECT FROM], hasdbaccess should be 0 +REVOKE CONNECT FROM sysusers_dep_vu_prepare_user1 +GO + +SELECT name, hasdbaccess, islogin +FROM sys.sysusers +WHERE name = 'sysusers_dep_vu_prepare_user1' +GO + +-- test [GRANT CONNECT TO], hasdbaccess should be 1 +GRANT CONNECT TO sysusers_dep_vu_prepare_user1 +GO + +SELECT name, hasdbaccess, islogin +FROM sys.sysusers +WHERE name = 'sysusers_dep_vu_prepare_user1' +GO + diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index c64263ce5e..b6988e3248 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -425,4 +425,5 @@ dateadd_internal_df datetime2fromparts-after-15-2 timefromparts orderby +sys_sysusers_dep BABEL-3215 From c5d632f8d38811459c017e723bf6c8662c53a9f9 Mon Sep 17 00:00:00 2001 From: Rui Zhao Date: Thu, 13 Apr 2023 20:07:06 +0800 Subject: [PATCH 056/363] Fix segmentation fault on null pointer when set context_info with declared but unassigned value. (#1423) Description =========== DECLARE @v int SET CONTEXT_INFO @v Above case can cause segmentation fault on null pointer. Analysis ======== We did null pointer check during ANTLR parsing, but miss the case with declared and unassigned value. Fix === Add null pointer check before actually using the value. --- contrib/babelfishpg_tsql/runtime/functions.c | 5 +++++ .../expected/babel_context_info-vu-verify.out | 18 +++++++++++++++++- .../input/babel_context_info-vu-verify.sql | 9 ++++++++- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/contrib/babelfishpg_tsql/runtime/functions.c b/contrib/babelfishpg_tsql/runtime/functions.c index dcf0b8f52a..d1fc6c496c 100644 --- a/contrib/babelfishpg_tsql/runtime/functions.c +++ b/contrib/babelfishpg_tsql/runtime/functions.c @@ -1870,6 +1870,11 @@ bbf_get_context_info(PG_FUNCTION_ARGS) Datum bbf_set_context_info(PG_FUNCTION_ARGS) { + if (PG_ARGISNULL(0)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("SET CONTEXT_INFO option requires varbinary (128) NOT NULL parameter."))); + if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->set_context_info) (*pltsql_protocol_plugin_ptr)->set_context_info(PG_GETARG_BYTEA_P(0)); diff --git a/test/JDBC/expected/babel_context_info-vu-verify.out b/test/JDBC/expected/babel_context_info-vu-verify.out index 5f2bbdb34d..7aed2d8f8a 100644 --- a/test/JDBC/expected/babel_context_info-vu-verify.out +++ b/test/JDBC/expected/babel_context_info-vu-verify.out @@ -322,7 +322,7 @@ varbinary ~~END~~ --- set NULL +-- set NULL, which should return error SET CONTEXT_INFO NULL GO ~~ERROR (Code: 33557097)~~ @@ -338,6 +338,22 @@ varbinary ~~END~~ +DECLARE @context int +SET CONTEXT_INFO @context +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: SET CONTEXT_INFO option requires varbinary (128) NOT NULL parameter.)~~ + + +SELECT CONTEXT_INFO() +GO +~~START~~ +varbinary +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + -- set more than 128-byte hex constant SET CONTEXT_INFO 0x123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567890 GO diff --git a/test/JDBC/input/babel_context_info-vu-verify.sql b/test/JDBC/input/babel_context_info-vu-verify.sql index 97f15d6fad..a1e952c195 100644 --- a/test/JDBC/input/babel_context_info-vu-verify.sql +++ b/test/JDBC/input/babel_context_info-vu-verify.sql @@ -155,13 +155,20 @@ go SELECT CONTEXT_INFO() GO --- set NULL +-- set NULL, which should return error SET CONTEXT_INFO NULL GO SELECT CONTEXT_INFO() GO +DECLARE @context int +SET CONTEXT_INFO @context +GO + +SELECT CONTEXT_INFO() +GO + -- set more than 128-byte hex constant SET CONTEXT_INFO 0x123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567890 GO From 807d81028a2f5aa9d5b02f29cbaf2ff02b2ffe37 Mon Sep 17 00:00:00 2001 From: "Ray\" DongHo Kim" <112982631+raydhkim@users.noreply.github.com> Date: Thu, 13 Apr 2023 08:58:31 -0700 Subject: [PATCH 057/363] Add COLUMN for sp_rename (#1416) Previously, sp_rename did not support renaming column in BBF. Now, renaming of column though sp_rename is also being supported. Task: BABEL-3889 Signed-off-by: Ray Kim --- .../babelfishpg_tsql/sql/babelfishpg_tsql.sql | 205 ++++++++++++------ .../babelfishpg_tsql--3.1.0--3.2.0.sql | 174 +++++++++++++++ contrib/babelfishpg_tsql/src/catalog.c | 2 + contrib/babelfishpg_tsql/src/procedures.c | 104 ++++++--- .../expected/Test-sp_rename-vu-cleanup.out | 2 +- .../expected/Test-sp_rename-vu-verify.out | 89 +++++++- .../Test-sp_rename-vu-cleanup.sql | 2 +- .../Test-sp_rename-vu-verify.sql | 47 +++- 8 files changed, 518 insertions(+), 107 deletions(-) diff --git a/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql index f5ce2ecd06..2b032c0500 100644 --- a/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql +++ b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql @@ -2941,13 +2941,101 @@ CREATE OR REPLACE PROCEDURE sys.babelfish_sp_rename_internal( IN "@objname" sys.nvarchar(776), IN "@newname" sys.SYSNAME, IN "@schemaname" sys.nvarchar(776), - IN "@objtype" char(2) DEFAULT NULL + IN "@objtype" char(2) DEFAULT NULL, + IN "@curr_relname" sys.nvarchar(776) DEFAULT NULL ) AS 'babelfishpg_tsql', 'sp_rename_internal' LANGUAGE C; GRANT EXECUTE on PROCEDURE sys.babelfish_sp_rename_internal TO PUBLIC; +CREATE OR REPLACE PROCEDURE sys.babelfish_sp_rename_word_parse( + IN "@input" sys.nvarchar(776), + IN "@objtype" sys.varchar(13), + INOUT "@subname" sys.nvarchar(776), + INOUT "@curr_relname" sys.nvarchar(776), + INOUT "@schemaname" sys.nvarchar(776), + INOUT "@dbname" sys.nvarchar(776) +) +AS $$ +BEGIN + SELECT (ROW_NUMBER() OVER (ORDER BY NULL)) as row, * + INTO #sp_rename_temptable + FROM STRING_SPLIT(@input, '.') ORDER BY row DESC; + + SELECT (ROW_NUMBER() OVER (ORDER BY NULL)) as id, * + INTO #sp_rename_temptable2 + FROM #sp_rename_temptable; + + DECLARE @row_count INT; + SELECT @row_count = COUNT(*) FROM #sp_rename_temptable2; + + IF @objtype = 'COLUMN' + BEGIN + IF @row_count = 1 + BEGIN + THROW 33557097, N'Either the parameter @objname is ambiguous or the claimed @objtype (COLUMN) is wrong.', 1; + END + ELSE IF @row_count > 4 + BEGIN + THROW 33557097, N'No item by the given @objname could be found in the current database', 1; + END + ELSE + BEGIN + IF @row_count > 1 + BEGIN + SELECT @subname = value FROM #sp_rename_temptable2 WHERE id = 1; + SELECT @curr_relname = value FROM #sp_rename_temptable2 WHERE id = 2; + SET @schemaname = sys.schema_name(); + + END + IF @row_count > 2 + BEGIN + SELECT @schemaname = value FROM #sp_rename_temptable2 WHERE id = 3; + END + IF @row_count > 3 + BEGIN + SELECT @dbname = value FROM #sp_rename_temptable2 WHERE id = 4; + IF @dbname != sys.db_name() + BEGIN + THROW 33557097, N'No item by the given @objname could be found in the current database', 1; + END + END + END + END + ELSE + BEGIN + IF @row_count > 3 + BEGIN + THROW 33557097, N'No item by the given @objname could be found in the current database', 1; + END + ELSE + BEGIN + SET @curr_relname = NULL; + IF @row_count > 0 + BEGIN + SELECT @subname = value FROM #sp_rename_temptable2 WHERE id = 1; + SET @schemaname = sys.schema_name(); + END + IF @row_count > 1 + BEGIN + SELECT @schemaname = value FROM #sp_rename_temptable2 WHERE id = 2; + END + IF @row_count > 2 + BEGIN + SELECT @dbname = value FROM #sp_rename_temptable2 WHERE id = 3; + IF @dbname != sys.db_name() + BEGIN + THROW 33557097, N'No item by the given @objname could be found in the current database', 1; + END + END + END + END +END; +$$ +LANGUAGE 'pltsql'; +GRANT EXECUTE on PROCEDURE sys.babelfish_sp_rename_word_parse(IN sys.nvarchar(776), IN sys.varchar(13), INOUT sys.nvarchar(776), INOUT sys.nvarchar(776), INOUT sys.nvarchar(776), INOUT sys.nvarchar(776)) TO PUBLIC; + CREATE OR REPLACE PROCEDURE sys.sp_rename( - IN "@objname" sys.nvarchar(776), - IN "@newname" sys.SYSNAME, + IN "@objname" sys.nvarchar(776) = NULL, + IN "@newname" sys.SYSNAME = NULL, IN "@objtype" sys.varchar(13) DEFAULT NULL ) LANGUAGE 'pltsql' @@ -2957,87 +3045,62 @@ BEGIN BEGIN THROW 33557097, N'Please provide @objtype that is supported in Babelfish', 1; END - IF @objtype = 'COLUMN' - BEGIN - THROW 33557097, N'Feature not supported: renaming object type Column', 1; - END - IF @objtype = 'INDEX' + ELSE IF @objtype = 'INDEX' BEGIN THROW 33557097, N'Feature not supported: renaming object type Index', 1; END - IF @objtype = 'STATISTICS' + ELSE IF @objtype = 'STATISTICS' BEGIN THROW 33557097, N'Feature not supported: renaming object type Statistics', 1; END - IF @objtype = 'USERDATATYPE' + ELSE IF @objtype = 'USERDATATYPE' BEGIN THROW 33557097, N'Feature not supported: renaming object type User-defined Data Type alias', 1; END - IF @objtype IS NOT NULL AND (@objtype != 'OBJECT') - BEGIN - THROW 33557097, N'Provided @objtype is not currently supported in Babelfish', 1; - END - DECLARE @name_count INT; - DECLARE @subname sys.nvarchar(776) = ''; - DECLARE @schemaname sys.nvarchar(776) = ''; - DECLARE @dbname sys.nvarchar(776) = ''; - SELECT @name_count = COUNT(*) FROM STRING_SPLIT(@objname, '.'); - IF @name_count > 3 - BEGIN - THROW 33557097, N'No item by the given @objname could be found in the current database', 1; - END - IF @name_count = 3 + ELSE BEGIN - WITH myTableWithRows AS ( - SELECT (ROW_NUMBER() OVER (ORDER BY NULL)) as row,* - FROM STRING_SPLIT(@objname, '.')) - SELECT @dbname = value FROM myTableWithRows WHERE row = 1; - IF @dbname != sys.db_name() + DECLARE @subname sys.nvarchar(776); + DECLARE @schemaname sys.nvarchar(776); + DECLARE @dbname sys.nvarchar(776); + DECLARE @curr_relname sys.nvarchar(776); + + EXEC sys.babelfish_sp_rename_word_parse @objname, @objtype, @subname OUT, @curr_relname OUT, @schemaname OUT, @dbname OUT; + + DECLARE @currtype char(2); + + IF @objtype = 'COLUMN' BEGIN - THROW 33557097, N'No item by the given @objname could be found in the current database', 1; + DECLARE @col_count INT; + SELECT @col_count = COUNT(*)FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @curr_relname and COLUMN_NAME = @subname; + IF @col_count < 0 + BEGIN + THROW 33557097, N'There is no object with the given @objname.', 1; + END + SET @currtype = 'CO'; END - WITH myTableWithRows AS ( - SELECT (ROW_NUMBER() OVER (ORDER BY NULL)) as row,* - FROM STRING_SPLIT(@objname, '.')) - SELECT @schemaname = value FROM myTableWithRows WHERE row = 2; - WITH myTableWithRows AS ( - SELECT (ROW_NUMBER() OVER (ORDER BY NULL)) as row,* - FROM STRING_SPLIT(@objname, '.')) - SELECT @subname = value FROM myTableWithRows WHERE row = 3; - END - IF @name_count = 2 - BEGIN - WITH myTableWithRows AS ( - SELECT (ROW_NUMBER() OVER (ORDER BY NULL)) as row,* - FROM STRING_SPLIT(@objname, '.')) - SELECT @schemaname = value FROM myTableWithRows WHERE row = 1; - WITH myTableWithRows AS ( - SELECT (ROW_NUMBER() OVER (ORDER BY NULL)) as row,* - FROM STRING_SPLIT(@objname, '.')) - SELECT @subname = value FROM myTableWithRows WHERE row = 2; - END - IF @name_count = 1 - BEGIN - SET @schemaname = sys.schema_name(); - SET @subname = @objname; - END - - DECLARE @count INT; - DECLARE @currtype char(2); - SELECT @count = COUNT(*) FROM sys.objects o1 INNER JOIN sys.schemas s1 ON o1.schema_id = s1.schema_id - WHERE s1.name = @schemaname AND o1.name = @subname; - IF @count > 1 - BEGIN - THROW 33557097, N'There are multiple objects with the given @objname.', 1; - END - IF @count < 1 - BEGIN - THROW 33557097, N'There is no object with the given @objname.', 1; + ELSE IF @objtype = 'OBJECT' + BEGIN + DECLARE @count INT; + SELECT @count = COUNT(*) FROM sys.objects o1 INNER JOIN sys.schemas s1 ON o1.schema_id = s1.schema_id + WHERE s1.name = @schemaname AND o1.name = @subname; + IF @count > 1 + BEGIN + THROW 33557097, N'There are multiple objects with the given @objname.', 1; + END + IF @count < 1 + BEGIN + THROW 33557097, N'There is no object with the given @objname.', 1; + END + SELECT @currtype = type FROM sys.objects o1 INNER JOIN sys.schemas s1 ON o1.schema_id = s1.schema_id + WHERE s1.name = @schemaname AND o1.name = @subname; + END + ELSE + BEGIN + THROW 33557097, N'Provided @objtype is not currently supported in Babelfish', 1; + END + EXEC sys.babelfish_sp_rename_internal @subname, @newname, @schemaname, @currtype, @curr_relname; + PRINT 'Caution: Changing any part of an object name could break scripts and stored procedures.'; END - SELECT @currtype = type FROM sys.objects o1 INNER JOIN sys.schemas s1 ON o1.schema_id = s1.schema_id - WHERE s1.name = @schemaname AND o1.name = @subname; - EXEC sys.babelfish_sp_rename_internal @subname, @newname, @schemaname, @currtype; - PRINT 'Caution: Changing any part of an object name could break scripts and stored procedures.'; END; $$; GRANT EXECUTE on PROCEDURE sys.sp_rename(IN sys.nvarchar(776), IN sys.SYSNAME, IN sys.varchar(13)) TO PUBLIC; diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql index 2073d2343e..a13248b74b 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql @@ -1638,6 +1638,180 @@ LANGUAGE plpgsql VOLATILE RETURNS NULL ON NULL INPUT; +CREATE OR REPLACE PROCEDURE sys.babelfish_sp_rename_word_parse( + IN "@input" sys.nvarchar(776), + IN "@objtype" sys.varchar(13), + INOUT "@subname" sys.nvarchar(776), + INOUT "@curr_relname" sys.nvarchar(776), + INOUT "@schemaname" sys.nvarchar(776), + INOUT "@dbname" sys.nvarchar(776) +) +AS $$ +BEGIN + SELECT (ROW_NUMBER() OVER (ORDER BY NULL)) as row, * + INTO #sp_rename_temptable + FROM STRING_SPLIT(@input, '.') ORDER BY row DESC; + + SELECT (ROW_NUMBER() OVER (ORDER BY NULL)) as id, * + INTO #sp_rename_temptable2 + FROM #sp_rename_temptable; + + DECLARE @row_count INT; + SELECT @row_count = COUNT(*) FROM #sp_rename_temptable2; + + IF @objtype = 'COLUMN' + BEGIN + IF @row_count = 1 + BEGIN + THROW 33557097, N'Either the parameter @objname is ambiguous or the claimed @objtype (COLUMN) is wrong.', 1; + END + ELSE IF @row_count > 4 + BEGIN + THROW 33557097, N'No item by the given @objname could be found in the current database', 1; + END + ELSE + BEGIN + IF @row_count > 1 + BEGIN + SELECT @subname = value FROM #sp_rename_temptable2 WHERE id = 1; + SELECT @curr_relname = value FROM #sp_rename_temptable2 WHERE id = 2; + SET @schemaname = sys.schema_name(); + + END + IF @row_count > 2 + BEGIN + SELECT @schemaname = value FROM #sp_rename_temptable2 WHERE id = 3; + END + IF @row_count > 3 + BEGIN + SELECT @dbname = value FROM #sp_rename_temptable2 WHERE id = 4; + IF @dbname != sys.db_name() + BEGIN + THROW 33557097, N'No item by the given @objname could be found in the current database', 1; + END + END + END + END + ELSE + BEGIN + IF @row_count > 3 + BEGIN + THROW 33557097, N'No item by the given @objname could be found in the current database', 1; + END + ELSE + BEGIN + SET @curr_relname = NULL; + IF @row_count > 0 + BEGIN + SELECT @subname = value FROM #sp_rename_temptable2 WHERE id = 1; + SET @schemaname = sys.schema_name(); + END + IF @row_count > 1 + BEGIN + SELECT @schemaname = value FROM #sp_rename_temptable2 WHERE id = 2; + END + IF @row_count > 2 + BEGIN + SELECT @dbname = value FROM #sp_rename_temptable2 WHERE id = 3; + IF @dbname != sys.db_name() + BEGIN + THROW 33557097, N'No item by the given @objname could be found in the current database', 1; + END + END + END + END +END; +$$ +LANGUAGE 'pltsql'; +GRANT EXECUTE on PROCEDURE sys.babelfish_sp_rename_word_parse(IN sys.nvarchar(776), IN sys.varchar(13), INOUT sys.nvarchar(776), INOUT sys.nvarchar(776), INOUT sys.nvarchar(776), INOUT sys.nvarchar(776)) TO PUBLIC; + +ALTER PROCEDURE sys.babelfish_sp_rename_internal RENAME TO babelfish_sp_rename_internal_deprecated_in_3_2_0; +ALTER PROCEDURE sys.sp_rename RENAME TO sp_rename_deprecated_in_3_2_0; + +CREATE OR REPLACE PROCEDURE sys.babelfish_sp_rename_internal( + IN "@objname" sys.nvarchar(776), + IN "@newname" sys.SYSNAME, + IN "@schemaname" sys.nvarchar(776), + IN "@objtype" char(2) DEFAULT NULL, + IN "@curr_relname" sys.nvarchar(776) DEFAULT NULL +) AS 'babelfishpg_tsql', 'sp_rename_internal' LANGUAGE C; +GRANT EXECUTE on PROCEDURE sys.babelfish_sp_rename_internal TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_rename( + IN "@objname" sys.nvarchar(776) = NULL, + IN "@newname" sys.SYSNAME = NULL, + IN "@objtype" sys.varchar(13) DEFAULT NULL +) +LANGUAGE 'pltsql' +AS $$ +BEGIN + If @objtype IS NULL + BEGIN + THROW 33557097, N'Please provide @objtype that is supported in Babelfish', 1; + END + ELSE IF @objtype = 'INDEX' + BEGIN + THROW 33557097, N'Feature not supported: renaming object type Index', 1; + END + ELSE IF @objtype = 'STATISTICS' + BEGIN + THROW 33557097, N'Feature not supported: renaming object type Statistics', 1; + END + ELSE IF @objtype = 'USERDATATYPE' + BEGIN + THROW 33557097, N'Feature not supported: renaming object type User-defined Data Type alias', 1; + END + ELSE + BEGIN + DECLARE @subname sys.nvarchar(776); + DECLARE @schemaname sys.nvarchar(776); + DECLARE @dbname sys.nvarchar(776); + DECLARE @curr_relname sys.nvarchar(776); + + EXEC sys.babelfish_sp_rename_word_parse @objname, @objtype, @subname OUT, @curr_relname OUT, @schemaname OUT, @dbname OUT; + + DECLARE @currtype char(2); + + IF @objtype = 'COLUMN' + BEGIN + DECLARE @col_count INT; + SELECT @col_count = COUNT(*)FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @curr_relname and COLUMN_NAME = @subname; + IF @col_count < 0 + BEGIN + THROW 33557097, N'There is no object with the given @objname.', 1; + END + SET @currtype = 'CO'; + END + ELSE IF @objtype = 'OBJECT' + BEGIN + DECLARE @count INT; + SELECT @count = COUNT(*) FROM sys.objects o1 INNER JOIN sys.schemas s1 ON o1.schema_id = s1.schema_id + WHERE s1.name = @schemaname AND o1.name = @subname; + IF @count > 1 + BEGIN + THROW 33557097, N'There are multiple objects with the given @objname.', 1; + END + IF @count < 1 + BEGIN + THROW 33557097, N'There is no object with the given @objname.', 1; + END + SELECT @currtype = type FROM sys.objects o1 INNER JOIN sys.schemas s1 ON o1.schema_id = s1.schema_id + WHERE s1.name = @schemaname AND o1.name = @subname; + END + ELSE + BEGIN + THROW 33557097, N'Provided @objtype is not currently supported in Babelfish', 1; + END + EXEC sys.babelfish_sp_rename_internal @subname, @newname, @schemaname, @currtype, @curr_relname; + PRINT 'Caution: Changing any part of an object name could break scripts and stored procedures.'; + END +END; +$$; +GRANT EXECUTE on PROCEDURE sys.sp_rename(IN sys.nvarchar(776), IN sys.SYSNAME, IN sys.varchar(13)) TO PUBLIC; + +CALL sys.babelfish_drop_deprecated_object('procedure', 'sys', 'babelfish_sp_rename_internal_deprecated_in_3_2_0'); +CALL sys.babelfish_drop_deprecated_object('procedure', 'sys', 'sp_rename_deprecated_in_3_2_0'); + -- Drops the temporary procedure used by the upgrade script. -- Please have this be one of the last statements executed in this upgrade script. DROP PROCEDURE sys.babelfish_drop_deprecated_object(varchar, varchar, varchar); diff --git a/contrib/babelfishpg_tsql/src/catalog.c b/contrib/babelfishpg_tsql/src/catalog.c index 0a2bfc48f0..ad3a98d021 100644 --- a/contrib/babelfishpg_tsql/src/catalog.c +++ b/contrib/babelfishpg_tsql/src/catalog.c @@ -2419,6 +2419,8 @@ rename_update_bbf_catalog(RenameStmt *stmt) break; case OBJECT_SEQUENCE: break; + case OBJECT_COLUMN: + break; default: break; } diff --git a/contrib/babelfishpg_tsql/src/procedures.c b/contrib/babelfishpg_tsql/src/procedures.c index be666e9eb8..b0aeab0ec2 100644 --- a/contrib/babelfishpg_tsql/src/procedures.c +++ b/contrib/babelfishpg_tsql/src/procedures.c @@ -75,7 +75,7 @@ static List *gen_sp_addrole_subcmds(const char *user); static List *gen_sp_droprole_subcmds(const char *user); static List *gen_sp_addrolemember_subcmds(const char *user, const char *member); static List *gen_sp_droprolemember_subcmds(const char *user, const char *member); -static List *gen_sp_rename_subcmds(const char *objname, const char *newname, const char *schemaname, ObjectType objtype); +static List *gen_sp_rename_subcmds(const char *objname, const char *newname, const char *schemaname, ObjectType objtype, const char *curr_relname); static void exec_utility_cmd_helper(char *query_str); List *handle_bool_expr_rec(BoolExpr *expr, List *list); @@ -2868,6 +2868,7 @@ sp_rename_internal(PG_FUNCTION_ARGS) *new_name, *schema_name, *objtype, + *curr_relname, *process_util_querystr; ObjectType objtype_code; size_t len; @@ -2887,6 +2888,7 @@ sp_rename_internal(PG_FUNCTION_ARGS) new_name = PG_ARGISNULL(1) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(1)); schema_name = PG_ARGISNULL(2) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(2)); objtype = PG_ARGISNULL(3) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(3)); + curr_relname = PG_ARGISNULL(4) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(4)); /* 3. check if the input arguments are valid, and parse the objname */ /* objname can have at most 3 parts */ @@ -2912,6 +2914,11 @@ sp_rename_internal(PG_FUNCTION_ARGS) len = strlen(objtype); while (isspace(objtype[len - 1])) objtype[--len] = 0; + if (curr_relname != NULL) { + len = strlen(curr_relname); + while(isspace(curr_relname[len - 1])) + curr_relname[--len] = 0; + } /* check if inputs are empty after removing trailing spaces */ if (obj_name == NULL) @@ -2970,6 +2977,11 @@ sp_rename_internal(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Feature not supported: renaming object type Table-Type"))); } + else if (strcmp(objtype, "CO") == 0) + { + objtype_code = OBJECT_COLUMN; + process_util_querystr = "(ALTER TABLE )"; + } else { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), @@ -2984,7 +2996,7 @@ sp_rename_internal(PG_FUNCTION_ARGS) * parsetree_list = gen_sp_rename_subcmds(obj_name, new_name, * schema_name, objtype); */ - parsetree_list = gen_sp_rename_subcmds(obj_name, new_name, schema_name, objtype_code); + parsetree_list = gen_sp_rename_subcmds(obj_name, new_name, schema_name, objtype_code, curr_relname); /* 5. run all commands */ foreach(parsetree_item, parsetree_list) @@ -3029,8 +3041,10 @@ sp_rename_internal(PG_FUNCTION_ARGS) PG_RETURN_VOID(); } +extern const char *ATTOPTION_BBF_ORIGINAL_NAME; + static List * -gen_sp_rename_subcmds(const char *objname, const char *newname, const char *schemaname, ObjectType objtype) +gen_sp_rename_subcmds(const char *objname, const char *newname, const char *schemaname, ObjectType objtype, const char *curr_relname) { StringInfoData query; List *res; @@ -3038,35 +3052,36 @@ gen_sp_rename_subcmds(const char *objname, const char *newname, const char *sche RenameStmt *renamestmt; initStringInfo(&query); - if (objtype == OBJECT_TABLE) - { - appendStringInfo(&query, "ALTER TABLE dummy RENAME TO dummy; "); - } - else if (objtype == OBJECT_VIEW) - { - appendStringInfo(&query, "ALTER VIEW dummy RENAME TO dummy; "); - } - else if (objtype == OBJECT_PROCEDURE) - { - appendStringInfo(&query, "ALTER PROCEDURE dummy RENAME TO dummy; "); - } - else if (objtype == OBJECT_FUNCTION) - { - appendStringInfo(&query, "ALTER FUNCTION dummy RENAME TO dummy; "); - } - else if (objtype == OBJECT_SEQUENCE) - { - appendStringInfo(&query, "ALTER SEQUENCE dummy RENAME TO dummy; "); - } - else + switch (objtype) { - ereport(ERROR, + case OBJECT_TABLE: + appendStringInfo(&query, "ALTER TABLE dummy RENAME TO dummy; "); + break; + case OBJECT_VIEW: + appendStringInfo(&query, "ALTER VIEW dummy RENAME TO dummy; "); + break; + case OBJECT_PROCEDURE: + appendStringInfo(&query, "ALTER PROCEDURE dummy RENAME TO dummy; "); + break; + case OBJECT_FUNCTION: + appendStringInfo(&query, "ALTER FUNCTION dummy RENAME TO dummy; "); + break; + case OBJECT_SEQUENCE: + appendStringInfo(&query, "ALTER SEQUENCE dummy RENAME TO dummy; "); + break; + case OBJECT_COLUMN: + appendStringInfo(&query, "ALTER TABLE dummy RENAME COLUMN dummy TO dummy; "); + appendStringInfo(&query, "ALTER TABLE dummy ALTER COLUMN dummy SET (dummy = 'dummy'); "); + break; + default: + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Provided objtype is not supported for sp_rename"))); + break; } res = raw_parser(query.data, RAW_PARSE_DEFAULT); - if (list_length(res) != 1) + if ((objtype != OBJECT_COLUMN) && (list_length(res) != 1)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("Expected 1 statement but get %d statements after parsing", list_length(res)))); @@ -3085,12 +3100,8 @@ gen_sp_rename_subcmds(const char *objname, const char *newname, const char *sche renamestmt->relation->schemaname = pstrdup(lowerstr(schemaname)); renamestmt->relation->relname = pstrdup(lowerstr(objname)); } - else + else if ((objtype == OBJECT_PROCEDURE) || (objtype == OBJECT_FUNCTION)) { - /* - * } else if ((objtype == OBJECT_PROCEDURE) || (objtype == - * OBJECT_FUNCTION)) { - */ ObjectWithArgs *objwargs = (ObjectWithArgs *) renamestmt->object; renamestmt->renameType = objtype; @@ -3099,6 +3110,37 @@ gen_sp_rename_subcmds(const char *objname, const char *newname, const char *sche renamestmt->subname = pstrdup(lowerstr(objname)); renamestmt->newname = pstrdup(lowerstr(newname)); } + else + { + /* COLUMN */ + AlterTableStmt *altertablestmt; + AlterTableCmd *cmd; + ListCell *lc = NULL; + + renamestmt->renameType = objtype; + renamestmt->relationType = OBJECT_TABLE; + renamestmt->subname = pstrdup(lowerstr(objname)); + renamestmt->newname = pstrdup(lowerstr(newname)); + renamestmt->relation->schemaname = pstrdup(lowerstr(schemaname)); + renamestmt->relation->relname = pstrdup(lowerstr(curr_relname)); + rewrite_object_refs(stmt); + + /* extra query nodes for modifying attoption column */ + stmt = parsetree_nth_stmt(res, 1); + altertablestmt = (AlterTableStmt *) stmt; + if (!IsA(altertablestmt, AlterTableStmt)) + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("query is not a AlterTableStmt"))); + + altertablestmt->relation->schemaname = pstrdup(lowerstr(schemaname)); + altertablestmt->relation->relname = pstrdup(lowerstr(curr_relname)); + altertablestmt->objtype = OBJECT_TABLE; + /* get data of the first node */ + lc = list_head(altertablestmt->cmds); + cmd = (AlterTableCmd *) lfirst(lc); + cmd->subtype = AT_SetOptions; + cmd->name = pstrdup(lowerstr(newname)); + cmd->def = (Node *) list_make1(makeDefElem(pstrdup(ATTOPTION_BBF_ORIGINAL_NAME), (Node *) makeString(pstrdup(newname)), -1)); //column->location)); + } /* name mapping */ rewrite_object_refs(stmt); diff --git a/test/JDBC/expected/Test-sp_rename-vu-cleanup.out b/test/JDBC/expected/Test-sp_rename-vu-cleanup.out index 2f39f6364a..09fcb264a4 100644 --- a/test/JDBC/expected/Test-sp_rename-vu-cleanup.out +++ b/test/JDBC/expected/Test-sp_rename-vu-cleanup.out @@ -11,7 +11,7 @@ GO DROP VIEW sp_rename_vu_schema1.sp_rename_vu_view1_new; GO -DROP TABLE sp_rename_vu_table1_case_insensitive2; +DROP TABLE sp_rename_vu_table1; GO DROP TABLE sp_rename_vu_schema1.sp_rename_vu_table1; diff --git a/test/JDBC/expected/Test-sp_rename-vu-verify.out b/test/JDBC/expected/Test-sp_rename-vu-verify.out index ff82337a55..e16e97e5dd 100644 --- a/test/JDBC/expected/Test-sp_rename-vu-verify.out +++ b/test/JDBC/expected/Test-sp_rename-vu-verify.out @@ -430,11 +430,82 @@ master#!#sp_rename_vu_schema1#!#sp_rename_vu_seq1_new2 -- ****Given objtype is valid but not supported yet**** -- Column -EXEC sp_rename 'sp_rename_vu_table2.sp_rename_vu_t2_col1', 'sp_rename_vu_t2_col1_new', 'COLUMN'; +EXEC sp_rename 'sp_rename_vu_table1_case_insensitive2', 'sp_rename_vu_table1', 'OBJECT'; +GO + +SELECT COLUMN_NAME, TABLE_SCHEMA, TABLE_NAME +FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'sp_rename_vu_table1' +ORDER BY COLUMN_NAME, TABLE_SCHEMA, TABLE_NAME; +GO +~~START~~ +nvarchar#!#nvarchar#!#nvarchar +sp_rename_vu_s1_t1_col1#!#sp_rename_vu_schema1#!#sp_rename_vu_table1 +sp_rename_vu_s1_t1_col2#!#sp_rename_vu_schema1#!#sp_rename_vu_table1 +sp_rename_vu_t1_col1#!#dbo#!#sp_rename_vu_table1 +sp_rename_vu_t1_col2#!#dbo#!#sp_rename_vu_table1 +~~END~~ + + +EXEC sp_rename 'sp_rename_vu_table1.sp_rename_vu_t1_col1', 'sp_rename_vu_t1_col1_new', 'COLUMN'; +GO + +SELECT COLUMN_NAME, TABLE_SCHEMA, TABLE_NAME +FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'sp_rename_vu_table1' +ORDER BY COLUMN_NAME, TABLE_SCHEMA, TABLE_NAME; +GO +~~START~~ +nvarchar#!#nvarchar#!#nvarchar +sp_rename_vu_s1_t1_col1#!#sp_rename_vu_schema1#!#sp_rename_vu_table1 +sp_rename_vu_s1_t1_col2#!#sp_rename_vu_schema1#!#sp_rename_vu_table1 +sp_rename_vu_t1_col1_new#!#dbo#!#sp_rename_vu_table1 +sp_rename_vu_t1_col2#!#dbo#!#sp_rename_vu_table1 +~~END~~ + + +INSERT INTO sp_rename_vu_table1(sp_rename_vu_t1_col1_new) VALUES (10); +GO +~~ROW COUNT: 1~~ + + +SELECT sp_rename_vu_t1_col1_new from sp_rename_vu_table1; +GO +~~START~~ +int +10 +~~END~~ + + +SELECT COLUMN_NAME, TABLE_SCHEMA, TABLE_NAME +FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'sp_rename_vu_table2_new' +ORDER BY COLUMN_NAME, TABLE_SCHEMA, TABLE_NAME; +GO +~~START~~ +nvarchar#!#nvarchar#!#nvarchar +sp_rename_vu_s1_t2_col1#!#sp_rename_vu_schema1#!#sp_rename_vu_table2_new +sp_rename_vu_s1_t2_col2#!#sp_rename_vu_schema1#!#sp_rename_vu_table2_new +~~END~~ + + +EXEC sp_rename 'sp_rename_vu_schema1.sp_rename_vu_table2_new.sp_rename_vu_s1_t2_col1', 'sp_rename_vu_s1_t2_col1_new', 'COLUMN'; +GO + +SELECT COLUMN_NAME, TABLE_SCHEMA, TABLE_NAME +FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'sp_rename_vu_table2_new' +ORDER BY COLUMN_NAME, TABLE_SCHEMA, TABLE_NAME; +GO +~~START~~ +nvarchar#!#nvarchar#!#nvarchar +sp_rename_vu_s1_t2_col1_new#!#sp_rename_vu_schema1#!#sp_rename_vu_table2_new +sp_rename_vu_s1_t2_col2#!#sp_rename_vu_schema1#!#sp_rename_vu_table2_new +~~END~~ + + +-- COLUMN: error-case +EXEC sp_rename 'sp_rename_vu_schema1.sp_rename_vu_table2_new.sp_rename_vu_s1_t2_wrong_col', 'sp_rename_vu_s1_t2_col1_new', 'COLUMN'; GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: Feature not supported: renaming object type Column)~~ +~~ERROR (Message: column "sp_rename_vu_s1_t2_wrong_col" does not exist)~~ -- Index @@ -468,3 +539,17 @@ GO ~~ERROR (Message: Feature not supported: renaming object type Trigger)~~ + +-- Helper Function +DECLARE @sp_rename_helperfunc_out1 nvarchar(776); +DECLARE @sp_rename_helperfunc_out2 nvarchar(776); +DECLARE @sp_rename_helperfunc_out3 nvarchar(776); +DECLARE @sp_rename_helperfunc_out4 nvarchar(776); +EXEC sys.babelfish_sp_rename_word_parse 'sp_rename_vu_schema1.sp_rename_vu_table2_new.sp_rename_vu_s1_t2_col1_new', 'COLUMN', @sp_rename_helperfunc_out1 OUT, @sp_rename_helperfunc_out2 OUT, @sp_rename_helperfunc_out3 OUT, @sp_rename_helperfunc_out4 OUT; +SELECT @sp_rename_helperfunc_out1, @sp_rename_helperfunc_out2, @sp_rename_helperfunc_out3, @sp_rename_helperfunc_out4; +GO +~~START~~ +nvarchar#!#nvarchar#!#nvarchar#!#nvarchar +sp_rename_vu_s1_t2_col1_new#!#sp_rename_vu_table2_new#!#sp_rename_vu_schema1#!# +~~END~~ + diff --git a/test/JDBC/input/storedProcedures/Test-sp_rename-vu-cleanup.sql b/test/JDBC/input/storedProcedures/Test-sp_rename-vu-cleanup.sql index b0ff89fcd9..e01114d2d4 100644 --- a/test/JDBC/input/storedProcedures/Test-sp_rename-vu-cleanup.sql +++ b/test/JDBC/input/storedProcedures/Test-sp_rename-vu-cleanup.sql @@ -11,7 +11,7 @@ GO DROP VIEW sp_rename_vu_schema1.sp_rename_vu_view1_new; GO -DROP TABLE sp_rename_vu_table1_case_insensitive2; +DROP TABLE sp_rename_vu_table1; GO DROP TABLE sp_rename_vu_schema1.sp_rename_vu_table1; diff --git a/test/JDBC/input/storedProcedures/Test-sp_rename-vu-verify.sql b/test/JDBC/input/storedProcedures/Test-sp_rename-vu-verify.sql index 69ef6bc3be..a86a19b98e 100644 --- a/test/JDBC/input/storedProcedures/Test-sp_rename-vu-verify.sql +++ b/test/JDBC/input/storedProcedures/Test-sp_rename-vu-verify.sql @@ -209,7 +209,43 @@ GO -- ****Given objtype is valid but not supported yet**** -- Column -EXEC sp_rename 'sp_rename_vu_table2.sp_rename_vu_t2_col1', 'sp_rename_vu_t2_col1_new', 'COLUMN'; +EXEC sp_rename 'sp_rename_vu_table1_case_insensitive2', 'sp_rename_vu_table1', 'OBJECT'; +GO + +SELECT COLUMN_NAME, TABLE_SCHEMA, TABLE_NAME +FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'sp_rename_vu_table1' +ORDER BY COLUMN_NAME, TABLE_SCHEMA, TABLE_NAME; +GO + +EXEC sp_rename 'sp_rename_vu_table1.sp_rename_vu_t1_col1', 'sp_rename_vu_t1_col1_new', 'COLUMN'; +GO + +SELECT COLUMN_NAME, TABLE_SCHEMA, TABLE_NAME +FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'sp_rename_vu_table1' +ORDER BY COLUMN_NAME, TABLE_SCHEMA, TABLE_NAME; +GO + +INSERT INTO sp_rename_vu_table1(sp_rename_vu_t1_col1_new) VALUES (10); +GO + +SELECT sp_rename_vu_t1_col1_new from sp_rename_vu_table1; +GO + +SELECT COLUMN_NAME, TABLE_SCHEMA, TABLE_NAME +FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'sp_rename_vu_table2_new' +ORDER BY COLUMN_NAME, TABLE_SCHEMA, TABLE_NAME; +GO + +EXEC sp_rename 'sp_rename_vu_schema1.sp_rename_vu_table2_new.sp_rename_vu_s1_t2_col1', 'sp_rename_vu_s1_t2_col1_new', 'COLUMN'; +GO + +SELECT COLUMN_NAME, TABLE_SCHEMA, TABLE_NAME +FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'sp_rename_vu_table2_new' +ORDER BY COLUMN_NAME, TABLE_SCHEMA, TABLE_NAME; +GO + +-- COLUMN: error-case +EXEC sp_rename 'sp_rename_vu_schema1.sp_rename_vu_table2_new.sp_rename_vu_s1_t2_wrong_col', 'sp_rename_vu_s1_t2_col1_new', 'COLUMN'; GO -- Index @@ -226,4 +262,13 @@ GO -- Trigger EXEC sp_rename 'sp_rename_vu_trig1', 'sp_rename_vu_trig2', 'OBJECT'; +GO + +-- Helper Function +DECLARE @sp_rename_helperfunc_out1 nvarchar(776); +DECLARE @sp_rename_helperfunc_out2 nvarchar(776); +DECLARE @sp_rename_helperfunc_out3 nvarchar(776); +DECLARE @sp_rename_helperfunc_out4 nvarchar(776); +EXEC sys.babelfish_sp_rename_word_parse 'sp_rename_vu_schema1.sp_rename_vu_table2_new.sp_rename_vu_s1_t2_col1_new', 'COLUMN', @sp_rename_helperfunc_out1 OUT, @sp_rename_helperfunc_out2 OUT, @sp_rename_helperfunc_out3 OUT, @sp_rename_helperfunc_out4 OUT; +SELECT @sp_rename_helperfunc_out1, @sp_rename_helperfunc_out2, @sp_rename_helperfunc_out3, @sp_rename_helperfunc_out4; GO \ No newline at end of file From f51d4e0a5e0d0b1854a1c6ce2e2e7840b583bfa3 Mon Sep 17 00:00:00 2001 From: Suthapalli-Ramya-satya-vasavi-srija <110654856+Suthapalli-Ramya-satya-vasavi-srija@users.noreply.github.com> Date: Thu, 13 Apr 2023 23:32:57 +0530 Subject: [PATCH 058/363] sys.sys% catalogs should also exist in dbo schema In SQL Server, many catalogs whose name starts with 'sys' are available both in the 'sys' and 'dbo' schema(note: this does not apply to all sys.sys% catalogs; also does not apply to catalogs whose names do npt start with 'sys'). But the current Babelfish behaves such that these catalog are present in 'sys' schema only. This commit fixes the behaviour of babelfish such that the catalogs whose name starts with 'sys' are present in both 'sys' and 'dbo' schema. Task: BABEL-3731, BABEL-3377 Signed-off-by: vasavi suthapalli --- contrib/babelfishpg_tsql/src/multidb.c | 42 ++++++ test/JDBC/expected/BABEL-2349.out | 59 ++++++++ test/JDBC/expected/BABEL-2829.out | 94 +++++++++++++ test/JDBC/expected/BABEL-SYSCHARSETS.out | 31 +++++ test/JDBC/expected/sys-configurations.out | 111 +++++++++++++++ test/JDBC/expected/sys-syscolumns.out | 130 ++++++++++++++++++ test/JDBC/expected/sys-sysforeignkeys.out | 68 +++++++++ test/JDBC/expected/sys-syslanguages.out | 41 ++++++ .../expected/sys-sysobjects-vu-cleanup.out | 12 ++ .../expected/sys-sysobjects-vu-verify.out | 50 +++++++ test/JDBC/input/BABEL-2349.sql | 24 ++++ test/JDBC/input/BABEL-2829.sql | 45 ++++++ test/JDBC/input/BABEL-SYSCHARSETS.sql | 18 ++- test/JDBC/input/sys-sysobjects-vu-cleanup.sql | 12 ++ test/JDBC/input/sys-sysobjects-vu-verify.sql | 27 ++++ test/JDBC/input/views/sys-configurations.sql | 35 +++++ .../input/views/sys-syscharsets-vu-verify.sql | 2 +- test/JDBC/input/views/sys-syscolumns.sql | 43 ++++++ test/JDBC/input/views/sys-sysforeignkeys.sql | 29 ++++ test/JDBC/input/views/sys-syslanguages.sql | 21 +++ 20 files changed, 892 insertions(+), 2 deletions(-) diff --git a/contrib/babelfishpg_tsql/src/multidb.c b/contrib/babelfishpg_tsql/src/multidb.c index 25e5075e4a..22198d0df0 100644 --- a/contrib/babelfishpg_tsql/src/multidb.c +++ b/contrib/babelfishpg_tsql/src/multidb.c @@ -37,6 +37,7 @@ static bool is_select_for_json(SelectStmt *stmt); static void select_json_modify(SelectStmt *stmt); static bool is_for_json(FuncCall *fc); static bool get_array_wrapper(List *for_json_args); +static void set_schemaname_dbo_to_sys(RangeVar *rv); @@ -692,6 +693,12 @@ rewrite_relation_walker(Node *node, void *context) { RangeVar *rv = (RangeVar *) node; + /* + * For the list of catalog names if the schema name + * specified is 'dbo' then replace with 'sys'. + */ + set_schemaname_dbo_to_sys(rv); + rewrite_rangevar(rv); return false; } @@ -947,6 +954,41 @@ rewrite_rangevar(RangeVar *rv) } } +static void +set_schemaname_dbo_to_sys(RangeVar *rv) +{ + char* list_of_dbo_catalog[5]= {"sysprocesses", "syscharsets", "sysconfigures", "syscurconfigs", "syslanguages"}; + char* list_of_dbo_catalog_not_supported_for_cross_db[4]= {"syscolumns", "sysforeignkeys", "sysindexes", "sysobjects"}; + if (rv->schemaname && strcmp(rv->schemaname, "dbo") == 0) + { + for (int i = 0; i < 5; i++) + { + if(rv->relname && strcmp(rv->relname, list_of_dbo_catalog[i]) == 0) + { + rv->schemaname = pstrdup("sys"); + break; + } + } + for (int i = 0; i < 4; i++) + { + if(rv->relname && strcmp(rv->relname, list_of_dbo_catalog_not_supported_for_cross_db[i]) == 0) + { + /* Throw error for dbo catalog which does not support cross-db */ + if (rv->catalogname && strcmp(get_cur_db_name(), rv->catalogname) != 0) + { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Cross-DB system view query is not currently supported in Babelfish."))); + } + else + { + rv->schemaname = pstrdup("sys"); + break; + } + } + } + } +} static void rewrite_objectwithargs(ObjectWithArgs *obj) { diff --git a/test/JDBC/expected/BABEL-2349.out b/test/JDBC/expected/BABEL-2349.out index 5ae2c18a5f..2a4de0e6c0 100644 --- a/test/JDBC/expected/BABEL-2349.out +++ b/test/JDBC/expected/BABEL-2349.out @@ -13,6 +13,15 @@ smallint#!#varchar ~~END~~ +select indid, name from dbo.sysindexes where id=OBJECT_ID('t1'); +go +~~START~~ +smallint#!#varchar +0#!# +2#!#i1_t1t1f8997b05ff6c7614042919b25a8cc2e0 +~~END~~ + + select count(*) from sys.sysindexes where id=OBJECT_ID('t1'); go ~~START~~ @@ -21,6 +30,14 @@ int ~~END~~ +select count(*) from dbo.sysindexes where id=OBJECT_ID('t1'); +go +~~START~~ +int +2 +~~END~~ + + create database db1; go @@ -36,9 +53,51 @@ int ~~END~~ +select count(*) from dbo.sysindexes where id=OBJECT_ID('t1'); +go +~~START~~ +int +0 +~~END~~ + + use master; go +-- sysindexes should also exist in dbo schema +SELECT COUNT(*) FROM sys.SySInDeXes where id=OBJECT_ID('t1'); +go +~~START~~ +int +2 +~~END~~ + + +SELECT COUNT(*) FROM dbo.SySInDeXes where id=OBJECT_ID('t1'); +go +~~START~~ +int +2 +~~END~~ + + +-- In case of cross-db, sysindexes should also exist in dbo schema +-- should not be visible here +SELECT count(*) FROM db1.sys.SySInDeXes where id=OBJECT_ID('t1'); +go +~~START~~ +int +0 +~~END~~ + + +SELECT count(*) FROM db1.dbo.SySInDeXes where id=OBJECT_ID('t1'); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cross-DB system view query is not currently supported in Babelfish.)~~ + + -- clean up drop index i1_t1 on t1 go diff --git a/test/JDBC/expected/BABEL-2829.out b/test/JDBC/expected/BABEL-2829.out index 17c8ac39fe..cfd96b8eca 100644 --- a/test/JDBC/expected/BABEL-2829.out +++ b/test/JDBC/expected/BABEL-2829.out @@ -10,6 +10,30 @@ master#!#jdbc_user ~~END~~ +SELECT DISTINCT db_name(dbid), loginname FROM dbo.sysprocesses WHERE spid = @@SPID +GO +~~START~~ +nvarchar#!#varchar +master#!#jdbc_user +~~END~~ + + +SELECT DISTINCT db_name(dbid), loginname FROM [sys].[sysprocesses] WHERE spid = @@SPID +GO +~~START~~ +nvarchar#!#varchar +master#!#jdbc_user +~~END~~ + + +SELECT DISTINCT db_name(dbid), loginname FROM [DbO].[SySProcESSeS] WHERE spid = @@SPID +GO +~~START~~ +nvarchar#!#varchar +master#!#jdbc_user +~~END~~ + + CREATE DATABASE db_2829 GO USE db_2829 @@ -21,7 +45,77 @@ nvarchar#!#varchar db_2829#!#jdbc_user ~~END~~ +SELECT DISTINCT db_name(dbid), loginname FROM dbo.sysprocesses WHERE spid = @@SPID +GO +~~START~~ +nvarchar#!#varchar +db_2829#!#jdbc_user +~~END~~ + USE master GO + +SELECT DISTINCT db_name(dbid), loginname FROM db_2829.sys.sysprocesses WHERE spid = @@SPID +GO +~~START~~ +nvarchar#!#varchar +db_2829#!#jdbc_user +~~END~~ + +SELECT DISTINCT db_name(dbid), loginname FROM db_2829.dbo.sysprocesses WHERE spid = @@SPID +GO +~~START~~ +nvarchar#!#varchar +master#!#jdbc_user +~~END~~ + + +-- These below test cases are just to validate the schema rewrite from dbo to sys in different scenarios. +select (select DISTINCT db_name(dbid) from dbo.sysprocesses WHERE spid = @@SPID) as a, count(*) from (select * from (select DISTINCT * from [DbO].[SySProcESSeS] WHERE spid = @@SPID) as a) as b; +go +~~START~~ +nvarchar#!#int +master#!#1 +~~END~~ + + +create procedure procedure_2829 as select DISTINCT db_name(dbid), loginname from [DbO].[SySProcESSeS] WHERE spid = @@SPID; +go + +exec procedure_2829 +go +~~START~~ +nvarchar#!#varchar +master#!#jdbc_user +~~END~~ + + +create table table_2829 ( a int, b int); +go + +insert into table_2829 select 1,2; +go +~~ROW COUNT: 1~~ + + +select * from table_2829; +go +~~START~~ +int#!#int +1#!#2 +~~END~~ + + +insert into table_2829 select DISTINCT spid, kpid from sys.sysprocesses WHERE spid = @@SPID; +go +~~ROW COUNT: 1~~ + + +DROP PROCEDURE procedure_2829 +GO + +DROP TABLE table_2829 +GO + DROP DATABASE db_2829 GO diff --git a/test/JDBC/expected/BABEL-SYSCHARSETS.out b/test/JDBC/expected/BABEL-SYSCHARSETS.out index cbfdf33bd6..4e345eb5da 100644 --- a/test/JDBC/expected/BABEL-SYSCHARSETS.out +++ b/test/JDBC/expected/BABEL-SYSCHARSETS.out @@ -8,3 +8,34 @@ int#!#int#!#int#!#int#!#nvarchar#!#nvarchar#!#varbinary#!#image 1001#!#1#!#0#!#0#!##!##!##!# ~~END~~ + +select * from dbo.SySChaRSets; +go +~~START~~ +int#!#int#!#int#!#int#!#nvarchar#!#nvarchar#!#varbinary#!#image +1001#!#1#!#0#!#0#!##!##!##!# +~~END~~ + + +CREATE DATABASE DB1; +GO + +-- In case of cross-db, syscharsets should also exist in dbo schema +SELECT * FROM db1.sys.SySChaRSets; +GO +~~START~~ +int#!#int#!#int#!#int#!#nvarchar#!#nvarchar#!#varbinary#!#image +1001#!#1#!#0#!#0#!##!##!##!# +~~END~~ + + +SELECT * FROM db1.dbo.SySChaRSets; +GO +~~START~~ +int#!#int#!#int#!#int#!#nvarchar#!#nvarchar#!#varbinary#!#image +1001#!#1#!#0#!#0#!##!##!##!# +~~END~~ + + +DROP DATABASE DB1; +GO diff --git a/test/JDBC/expected/sys-configurations.out b/test/JDBC/expected/sys-configurations.out index 0e8782fdad..35274b5ea9 100644 --- a/test/JDBC/expected/sys-configurations.out +++ b/test/JDBC/expected/sys-configurations.out @@ -26,6 +26,53 @@ sql_variant#!#int#!#nvarchar#!#smallint ~~END~~ +-- syscurconfigs should also exist in dbo schema +select * from dbo.SySCuRConFIgS; +go +~~START~~ +sql_variant#!#int#!#nvarchar#!#smallint +1#!#16387#!#Enable or disable SMO and DMO XPs#!#3 +0#!#1534#!#user options#!#1 +1#!#115#!#Allow triggers to be invoked within triggers#!#1 +0#!#124#!#default language#!#1 +1033#!#1126#!#default full-text language#!#3 +2049#!#1127#!#two digit year cutoff#!#3 +0#!#1555#!#Transform noise words for full-text query#!#3 +~~END~~ + + +CREATE DATABASE DB1; +GO + +-- In case of cross-db, syscurconfigs should also exist in dbo schema +SELECT * FROM db1.sys.SySCuRConFIgS; +GO +~~START~~ +sql_variant#!#int#!#nvarchar#!#smallint +1#!#16387#!#Enable or disable SMO and DMO XPs#!#3 +0#!#1534#!#user options#!#1 +1#!#115#!#Allow triggers to be invoked within triggers#!#1 +0#!#124#!#default language#!#1 +1033#!#1126#!#default full-text language#!#3 +2049#!#1127#!#two digit year cutoff#!#3 +0#!#1555#!#Transform noise words for full-text query#!#3 +~~END~~ + + +SELECT * FROM db1.dbo.SySCuRConFIgS; +GO +~~START~~ +sql_variant#!#int#!#nvarchar#!#smallint +1#!#16387#!#Enable or disable SMO and DMO XPs#!#3 +0#!#1534#!#user options#!#1 +1#!#115#!#Allow triggers to be invoked within triggers#!#1 +0#!#124#!#default language#!#1 +1033#!#1126#!#default full-text language#!#3 +2049#!#1127#!#two digit year cutoff#!#3 +0#!#1555#!#Transform noise words for full-text query#!#3 +~~END~~ + + SELECT * FROM sys.sysconfigures; GO ~~START~~ @@ -40,6 +87,50 @@ sql_variant#!#int#!#nvarchar#!#smallint ~~END~~ +-- sysconfigures should also exist in dbo schema +select * from dbo.SySConFIGuReS; +go +~~START~~ +sql_variant#!#int#!#nvarchar#!#smallint +1#!#16387#!#Enable or disable SMO and DMO XPs#!#3 +0#!#1534#!#user options#!#1 +1#!#115#!#Allow triggers to be invoked within triggers#!#1 +0#!#124#!#default language#!#1 +1033#!#1126#!#default full-text language#!#3 +2049#!#1127#!#two digit year cutoff#!#3 +0#!#1555#!#Transform noise words for full-text query#!#3 +~~END~~ + + +-- In case of cross-db, sysconfigures should also exist in dbo schema +SELECT * FROM db1.sys.SySConFIGuReS; +GO +~~START~~ +sql_variant#!#int#!#nvarchar#!#smallint +1#!#16387#!#Enable or disable SMO and DMO XPs#!#3 +0#!#1534#!#user options#!#1 +1#!#115#!#Allow triggers to be invoked within triggers#!#1 +0#!#124#!#default language#!#1 +1033#!#1126#!#default full-text language#!#3 +2049#!#1127#!#two digit year cutoff#!#3 +0#!#1555#!#Transform noise words for full-text query#!#3 +~~END~~ + + +SELECT * FROM db1.dbo.SySConFIGuReS; +GO +~~START~~ +sql_variant#!#int#!#nvarchar#!#smallint +1#!#16387#!#Enable or disable SMO and DMO XPs#!#3 +0#!#1534#!#user options#!#1 +1#!#115#!#Allow triggers to be invoked within triggers#!#1 +0#!#124#!#default language#!#1 +1033#!#1126#!#default full-text language#!#3 +2049#!#1127#!#two digit year cutoff#!#3 +0#!#1555#!#Transform noise words for full-text query#!#3 +~~END~~ + + SELECT * FROM sys.babelfish_configurations; GO ~~ERROR (Code: 33557097)~~ @@ -65,3 +156,23 @@ GO ~~ERROR (Message: permission denied for table babelfish_configurations)~~ + +-- These below test cases are just to validate the schema rewrite from dbo to sys in different scenarios. +select (select count(*) from DbO.SySConFIGuReS) as x, (select count(*) from [DbO].SySCuRConFIgS) as y; +go +~~START~~ +int#!#int +7#!#7 +~~END~~ + + +select count(*) from DbO.SySConFIGuReS x inner join [DbO].SySCuRConFIgS y on x.value=y.value; +go +~~START~~ +int +15 +~~END~~ + + +DROP DATABASE DB1; +GO diff --git a/test/JDBC/expected/sys-syscolumns.out b/test/JDBC/expected/sys-syscolumns.out index 32b370e481..d66b6d1e3b 100644 --- a/test/JDBC/expected/sys-syscolumns.out +++ b/test/JDBC/expected/sys-syscolumns.out @@ -68,6 +68,20 @@ col_d#!#syscolumns_demo_table#!#numeric#!#0#!#5 ~~END~~ +select name, OidToObject(id), OidToDataType(xtype), typestat, length from dbo.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' or name = 'col_d' order by OidToObject(id) asc, name +GO +~~START~~ +varchar#!#varchar#!#varchar#!#tinyint#!#smallint +@firstparam#!#syscolumns_demo_proc1#!#nvarchar#!#0#!# +@firstparam#!#syscolumns_demo_proc2#!#nvarchar#!#0#!# +@secondparam#!#syscolumns_demo_proc2#!#varchar#!#0#!# +col_a#!#syscolumns_demo_table#!#int4#!#0#!#4 +col_b#!#syscolumns_demo_table#!#int8#!#0#!#8 +col_c#!#syscolumns_demo_table#!#bpchar#!#0#!#10 +col_d#!#syscolumns_demo_table#!#numeric#!#0#!#5 +~~END~~ + + select colid, cdefault, domain, number from sys.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' or name = 'col_d' order by OidToObject(id) asc, name GO ~~START~~ @@ -82,6 +96,20 @@ smallint#!#int#!#int#!#smallint ~~END~~ +select colid, cdefault, domain, number from dbo.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' or name = 'col_d' order by OidToObject(id) asc, name +GO +~~START~~ +smallint#!#int#!#int#!#smallint +1#!##!##!#0 +1#!##!##!#0 +2#!##!##!#0 +1#!#0#!#0#!#0 +2#!#0#!#0#!#0 +3#!#0#!#0#!#0 +4#!#0#!#0#!#0 +~~END~~ + + select OidToCollation(collationid), status, OidToDataType(type), prec, scale from sys.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' or name = 'col_d' order by OidToObject(id) asc, name GO ~~START~~ @@ -96,6 +124,20 @@ bbf_unicode_cp1_ci_as#!#8#!#bpchar#!#0#!#0 ~~END~~ +select OidToCollation(collationid), status, OidToDataType(type), prec, scale from dbo.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' or name = 'col_d' order by OidToObject(id) asc, name +GO +~~START~~ +varchar#!#tinyint#!#varchar#!#smallint#!#int +#!#0#!#nvarchar#!##!# +#!#0#!#nvarchar#!##!# +#!#64#!#varchar#!##!# +#!#8#!#int4#!#10#!#0 +#!#8#!#int8#!#19#!#0 +bbf_unicode_cp1_ci_as#!#8#!#bpchar#!#0#!#0 +#!#8#!#numeric#!#5#!#4 +~~END~~ + + select iscomputed, isoutparam, isnullable, collation from sys.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' or name = 'col_d' order by OidToObject(id) asc, name GO ~~START~~ @@ -110,6 +152,20 @@ int#!#int#!#int#!#varchar ~~END~~ +select iscomputed, isoutparam, isnullable, collation from dbo.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' or name = 'col_d' order by OidToObject(id) asc, name +GO +~~START~~ +int#!#int#!#int#!#varchar +0#!#0#!#1#!# +0#!#0#!#1#!# +0#!#1#!#1#!# +0#!#0#!#1#!# +0#!#0#!#1#!# +0#!#0#!#1#!#bbf_unicode_cp1_ci_as +0#!#0#!#1#!# +~~END~~ + + SELECT COUNT(*) FROM sys.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' go ~~START~~ @@ -118,6 +174,14 @@ int ~~END~~ +SELECT COUNT(*) FROM dbo.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' +go +~~START~~ +int +6 +~~END~~ + + use master; go @@ -132,6 +196,48 @@ int ~~END~~ +-- syscolumns should also exist in dbo schema +SELECT COUNT(*) FROM dbo.SySCOluMNs where name = '@thirdparam'; +go +~~START~~ +int +1 +~~END~~ + + +SELECT COUNT(*) FROM db1.sys.SySCOluMNs where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' +go +~~START~~ +int +6 +~~END~~ + + +-- In case of cross-db, syscolumns should also exist in dbo schema +-- Cross-DB system view query is not currently supported in Babelfish. +SELECT COUNT(*) FROM db1.DbO.SySCOluMNs where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cross-DB system view query is not currently supported in Babelfish.)~~ + + +-- should not be visible here +SELECT COUNT(*) FROM db1.sys.SySCOluMNs where name = '@thirdparam'; +GO +~~START~~ +int +0 +~~END~~ + + +SELECT COUNT(*) FROM db1.dbo.SySCOluMNs where name = '@thirdparam'; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cross-DB system view query is not currently supported in Babelfish.)~~ + + -- should not be visible here SELECT COUNT(*) FROM sys.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' go @@ -141,6 +247,14 @@ int ~~END~~ +SELECT COUNT(*) FROM dbo.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' +go +~~START~~ +int +0 +~~END~~ + + use db1; go @@ -152,6 +266,14 @@ int ~~END~~ +SELECT COUNT(*) FROM dbo.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' +go +~~START~~ +int +6 +~~END~~ + + -- should not be visible here SELECT COUNT(*) FROM sys.syscolumns where name = '@thirdparam' go @@ -161,6 +283,14 @@ int ~~END~~ +SELECT COUNT(*) FROM dbo.syscolumns where name = '@thirdparam' +go +~~START~~ +int +0 +~~END~~ + + -- Cleanup DROP FUNCTION OidToDataType DROP FUNCTION OidToObject diff --git a/test/JDBC/expected/sys-sysforeignkeys.out b/test/JDBC/expected/sys-sysforeignkeys.out index 9705438530..d1e405d951 100644 --- a/test/JDBC/expected/sys-sysforeignkeys.out +++ b/test/JDBC/expected/sys-sysforeignkeys.out @@ -18,6 +18,32 @@ int ~~END~~ +-- sysforeignkeys should also exist in dbo schema +SELECT COUNT(*) FROM dbo.SySFoReIGNkeYs where fkeyid = object_id('fk_2'); +go +~~START~~ +int +1 +~~END~~ + + +SELECT COUNT(*) FROM db1.sys.SySFoReIGNkeYs where fkeyid = object_id('fk_2'); +go +~~START~~ +int +1 +~~END~~ + + +-- In case of cross-db, sysforeignkeys should also exist in dbo schema +SELECT COUNT(*) FROM db1.dbo.SySFoReIGNkeYs where fkeyid = object_id('fk_2'); +go +~~START~~ +int +1 +~~END~~ + + select count(*) from sys.foreign_keys where parent_object_id = object_id('fk_2'); GO ~~START~~ @@ -37,6 +63,14 @@ int ~~END~~ +select count(*) from dbo.sysforeignkeys where fkeyid = object_id('fk_2'); +GO +~~START~~ +int +0 +~~END~~ + + select count(*) from sys.foreign_keys where parent_object_id = object_id('fk_2'); GO ~~START~~ @@ -59,6 +93,32 @@ int ~~END~~ +-- sysforeignkeys should also exist in dbo schema +SELECT COUNT(*) FROM dbo.SySFoReIGNkeYs where fkeyid = object_id('fk_4'); +go +~~START~~ +int +1 +~~END~~ + + +-- In case of cross-db, sysforeignkeys should also exist in dbo schema +-- should not be visible here +SELECT COUNT(*) FROM db1.sys.SySFoReIGNkeYs where fkeyid = object_id('fk_4'); +go +~~START~~ +int +0 +~~END~~ + + +SELECT COUNT(*) FROM db1.dbo.SySFoReIGNkeYs where fkeyid = object_id('fk_4'); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cross-DB system view query is not currently supported in Babelfish.)~~ + + select count(*) from sys.foreign_keys where parent_object_id = object_id('fk_4'); GO ~~START~~ @@ -78,6 +138,14 @@ int ~~END~~ +select count(*) from dbo.sysforeignkeys where fkeyid = object_id('fk_4'); +GO +~~START~~ +int +0 +~~END~~ + + select count(*) from sys.foreign_keys where parent_object_id = object_id('fk_4'); GO ~~START~~ diff --git a/test/JDBC/expected/sys-syslanguages.out b/test/JDBC/expected/sys-syslanguages.out index 2db7412032..7fb77e59b8 100644 --- a/test/JDBC/expected/sys-syslanguages.out +++ b/test/JDBC/expected/sys-syslanguages.out @@ -13,3 +13,44 @@ smallint#!#nchar#!#tinyint#!#int#!#varchar#!#varchar#!#nvarchar#!#nvarchar#!#nva 1#!#dmy#!#1#!##!#ENGLISH#!#ENGLISH (AUSTRALIA)#!#January,February,March,April,May,June,July,August,September,October,November,December#!#Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec#!#Mon,Tue,Wed,Thu,Fri,Sat,Sun#!##!# ~~END~~ + +-- syslanguages should also exist in dbo schema +select * from dbo.SySLanGUAgeS WHERE langid = 1; +go +~~START~~ +smallint#!#nchar#!#tinyint#!#int#!#varchar#!#varchar#!#nvarchar#!#nvarchar#!#nvarchar#!#int#!#smallint +1#!#dmy#!#1#!##!#ENGLISH#!#ENGLISH (AUSTRALIA)#!#January,February,March,April,May,June,July,August,September,October,November,December#!#Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec#!#Mon,Tue,Wed,Thu,Fri,Sat,Sun#!##!# +~~END~~ + + +CREATE DATABASE DB1; +GO + +-- In case of cross-db, syslanguages should also exist in dbo schema +SELECT * FROM db1.sys.SySLanGUAgeS WHERE langid = 1; +GO +~~START~~ +smallint#!#nchar#!#tinyint#!#int#!#varchar#!#varchar#!#nvarchar#!#nvarchar#!#nvarchar#!#int#!#smallint +1#!#dmy#!#1#!##!#ENGLISH#!#ENGLISH (AUSTRALIA)#!#January,February,March,April,May,June,July,August,September,October,November,December#!#Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec#!#Mon,Tue,Wed,Thu,Fri,Sat,Sun#!##!# +~~END~~ + + +SELECT * FROM db1.dbo.SySLanGUAgeS WHERE langid = 1; +GO +~~START~~ +smallint#!#nchar#!#tinyint#!#int#!#varchar#!#varchar#!#nvarchar#!#nvarchar#!#nvarchar#!#int#!#smallint +1#!#dmy#!#1#!##!#ENGLISH#!#ENGLISH (AUSTRALIA)#!#January,February,March,April,May,June,July,August,September,October,November,December#!#Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec#!#Mon,Tue,Wed,Thu,Fri,Sat,Sun#!##!# +~~END~~ + + +-- These below test cases are just to validate the schema rewrite from dbo to sys in different scenarios. +select * from DbO.SySLanGUAgeS where langid = (SELECT count(*) FROM DbO.syslanguages WHERE langid = 1); +go +~~START~~ +smallint#!#nchar#!#tinyint#!#int#!#varchar#!#varchar#!#nvarchar#!#nvarchar#!#nvarchar#!#int#!#smallint +1#!#dmy#!#1#!##!#ENGLISH#!#ENGLISH (AUSTRALIA)#!#January,February,March,April,May,June,July,August,September,October,November,December#!#Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec#!#Mon,Tue,Wed,Thu,Fri,Sat,Sun#!##!# +~~END~~ + + +DROP DATABASE DB1; +GO diff --git a/test/JDBC/expected/sys-sysobjects-vu-cleanup.out b/test/JDBC/expected/sys-sysobjects-vu-cleanup.out index 54d0f564c3..de5cd9c0cc 100644 --- a/test/JDBC/expected/sys-sysobjects-vu-cleanup.out +++ b/test/JDBC/expected/sys-sysobjects-vu-cleanup.out @@ -9,3 +9,15 @@ GO DROP FUNCTION sys_sysobjects_vu_prepare_func GO + +USE sys_sysobjects_vu_prepare_db1; +GO + +DROP TABLE sys_sysobjects_vu_prepare_table_t1 +GO + +USE MASTER; +GO + +DROP DATABASE sys_sysobjects_vu_prepare_db1; +GO diff --git a/test/JDBC/expected/sys-sysobjects-vu-verify.out b/test/JDBC/expected/sys-sysobjects-vu-verify.out index 2cbe67ecd7..b912ce1eda 100644 --- a/test/JDBC/expected/sys-sysobjects-vu-verify.out +++ b/test/JDBC/expected/sys-sysobjects-vu-verify.out @@ -1,3 +1,12 @@ +CREATE DATABASE sys_sysobjects_vu_prepare_db1; +GO + +USE sys_sysobjects_vu_prepare_db1; +GO + +CREATE TABLE sys_sysobjects_vu_prepare_table_t1(c1 int) +GO + USE master; GO @@ -9,6 +18,47 @@ int ~~END~~ +-- sysobjects should also exist in dbo schema +SELECT COUNT(*) FROM dbo.SySObJEctS s where s.name = 'sys_sysobjects_vu_prepare_table'; +go +~~START~~ +int +1 +~~END~~ + + +-- In case of cross-db, sysobjects should also exist in dbo schema +SELECT COUNT(*) FROM sys_sysobjects_vu_prepare_db1.sys.SySObJEctS s where s.name = 'sys_sysobjects_vu_prepare_table_t1'; +go +~~START~~ +int +1 +~~END~~ + + +SELECT COUNT(*) FROM sys_sysobjects_vu_prepare_db1.dbo.SySObJEctS s where s.name = 'sys_sysobjects_vu_prepare_table_t1'; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cross-DB system view query is not currently supported in Babelfish.)~~ + + +-- should not be visible here +SELECT COUNT(*) FROM sys_sysobjects_vu_prepare_db1.sys.SySObJEctS s where s.name = 'sys_sysobjects_vu_prepare_table'; +go +~~START~~ +int +0 +~~END~~ + + +SELECT COUNT(*) FROM sys_sysobjects_vu_prepare_db1.dbo.SySObJEctS s where s.name = 'sys_sysobjects_vu_prepare_table'; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cross-DB system view query is not currently supported in Babelfish.)~~ + + SELECT * FROM sys_sysobjects_vu_prepare_view GO ~~START~~ diff --git a/test/JDBC/input/BABEL-2349.sql b/test/JDBC/input/BABEL-2349.sql index 27eca53194..eb10957261 100644 --- a/test/JDBC/input/BABEL-2349.sql +++ b/test/JDBC/input/BABEL-2349.sql @@ -7,9 +7,15 @@ go select indid, name from sys.sysindexes where id=OBJECT_ID('t1'); go +select indid, name from dbo.sysindexes where id=OBJECT_ID('t1'); +go + select count(*) from sys.sysindexes where id=OBJECT_ID('t1'); go +select count(*) from dbo.sysindexes where id=OBJECT_ID('t1'); +go + create database db1; go @@ -20,9 +26,27 @@ go select count(*) from sys.sysindexes where id=OBJECT_ID('t1'); go +select count(*) from dbo.sysindexes where id=OBJECT_ID('t1'); +go + use master; go +-- sysindexes should also exist in dbo schema +SELECT COUNT(*) FROM sys.SySInDeXes where id=OBJECT_ID('t1'); +go + +SELECT COUNT(*) FROM dbo.SySInDeXes where id=OBJECT_ID('t1'); +go + +-- In case of cross-db, sysindexes should also exist in dbo schema +-- should not be visible here +SELECT count(*) FROM db1.sys.SySInDeXes where id=OBJECT_ID('t1'); +go + +SELECT count(*) FROM db1.dbo.SySInDeXes where id=OBJECT_ID('t1'); +go + -- clean up drop index i1_t1 on t1 go diff --git a/test/JDBC/input/BABEL-2829.sql b/test/JDBC/input/BABEL-2829.sql index c7aa7289e0..7771553117 100644 --- a/test/JDBC/input/BABEL-2829.sql +++ b/test/JDBC/input/BABEL-2829.sql @@ -5,13 +5,58 @@ SELECT DISTINCT db_name(dbid), loginname FROM sys.sysprocesses WHERE spid = @@SPID GO +SELECT DISTINCT db_name(dbid), loginname FROM dbo.sysprocesses WHERE spid = @@SPID +GO + +SELECT DISTINCT db_name(dbid), loginname FROM [sys].[sysprocesses] WHERE spid = @@SPID +GO + +SELECT DISTINCT db_name(dbid), loginname FROM [DbO].[SySProcESSeS] WHERE spid = @@SPID +GO + CREATE DATABASE db_2829 GO USE db_2829 GO SELECT DISTINCT db_name(dbid), loginname FROM sys.sysprocesses WHERE spid = @@SPID GO +SELECT DISTINCT db_name(dbid), loginname FROM dbo.sysprocesses WHERE spid = @@SPID +GO USE master GO + +SELECT DISTINCT db_name(dbid), loginname FROM db_2829.sys.sysprocesses WHERE spid = @@SPID +GO +SELECT DISTINCT db_name(dbid), loginname FROM db_2829.dbo.sysprocesses WHERE spid = @@SPID +GO + +-- These below test cases are just to validate the schema rewrite from dbo to sys in different scenarios. +select (select DISTINCT db_name(dbid) from dbo.sysprocesses WHERE spid = @@SPID) as a, count(*) from (select * from (select DISTINCT * from [DbO].[SySProcESSeS] WHERE spid = @@SPID) as a) as b; +go + +create procedure procedure_2829 as select DISTINCT db_name(dbid), loginname from [DbO].[SySProcESSeS] WHERE spid = @@SPID; +go + +exec procedure_2829 +go + +create table table_2829 ( a int, b int); +go + +insert into table_2829 select 1,2; +go + +select * from table_2829; +go + +insert into table_2829 select DISTINCT spid, kpid from sys.sysprocesses WHERE spid = @@SPID; +go + +DROP PROCEDURE procedure_2829 +GO + +DROP TABLE table_2829 +GO + DROP DATABASE db_2829 GO \ No newline at end of file diff --git a/test/JDBC/input/BABEL-SYSCHARSETS.sql b/test/JDBC/input/BABEL-SYSCHARSETS.sql index bcacaf425d..ce6cc92582 100644 --- a/test/JDBC/input/BABEL-SYSCHARSETS.sql +++ b/test/JDBC/input/BABEL-SYSCHARSETS.sql @@ -2,4 +2,20 @@ USE master go select * from sys.syscharsets; -go \ No newline at end of file +go + +select * from dbo.SySChaRSets; +go + +CREATE DATABASE DB1; +GO + +-- In case of cross-db, syscharsets should also exist in dbo schema +SELECT * FROM db1.sys.SySChaRSets; +GO + +SELECT * FROM db1.dbo.SySChaRSets; +GO + +DROP DATABASE DB1; +GO diff --git a/test/JDBC/input/sys-sysobjects-vu-cleanup.sql b/test/JDBC/input/sys-sysobjects-vu-cleanup.sql index 54d0f564c3..de5cd9c0cc 100644 --- a/test/JDBC/input/sys-sysobjects-vu-cleanup.sql +++ b/test/JDBC/input/sys-sysobjects-vu-cleanup.sql @@ -9,3 +9,15 @@ GO DROP FUNCTION sys_sysobjects_vu_prepare_func GO + +USE sys_sysobjects_vu_prepare_db1; +GO + +DROP TABLE sys_sysobjects_vu_prepare_table_t1 +GO + +USE MASTER; +GO + +DROP DATABASE sys_sysobjects_vu_prepare_db1; +GO diff --git a/test/JDBC/input/sys-sysobjects-vu-verify.sql b/test/JDBC/input/sys-sysobjects-vu-verify.sql index 5a4079162f..5443ef7b75 100644 --- a/test/JDBC/input/sys-sysobjects-vu-verify.sql +++ b/test/JDBC/input/sys-sysobjects-vu-verify.sql @@ -1,9 +1,36 @@ +CREATE DATABASE sys_sysobjects_vu_prepare_db1; +GO + +USE sys_sysobjects_vu_prepare_db1; +GO + +CREATE TABLE sys_sysobjects_vu_prepare_table_t1(c1 int) +GO + USE master; GO SELECT COUNT(*) FROM sys.sysobjects s where s.name = 'sys_sysobjects_vu_prepare_table' GO +-- sysobjects should also exist in dbo schema +SELECT COUNT(*) FROM dbo.SySObJEctS s where s.name = 'sys_sysobjects_vu_prepare_table'; +go + +-- In case of cross-db, sysobjects should also exist in dbo schema +SELECT COUNT(*) FROM sys_sysobjects_vu_prepare_db1.sys.SySObJEctS s where s.name = 'sys_sysobjects_vu_prepare_table_t1'; +go + +SELECT COUNT(*) FROM sys_sysobjects_vu_prepare_db1.dbo.SySObJEctS s where s.name = 'sys_sysobjects_vu_prepare_table_t1'; +go + +-- should not be visible here +SELECT COUNT(*) FROM sys_sysobjects_vu_prepare_db1.sys.SySObJEctS s where s.name = 'sys_sysobjects_vu_prepare_table'; +go + +SELECT COUNT(*) FROM sys_sysobjects_vu_prepare_db1.dbo.SySObJEctS s where s.name = 'sys_sysobjects_vu_prepare_table'; +go + SELECT * FROM sys_sysobjects_vu_prepare_view GO diff --git a/test/JDBC/input/views/sys-configurations.sql b/test/JDBC/input/views/sys-configurations.sql index b22f83b76d..44969de1a9 100644 --- a/test/JDBC/input/views/sys-configurations.sql +++ b/test/JDBC/input/views/sys-configurations.sql @@ -4,9 +4,34 @@ GO SELECT * FROM sys.syscurconfigs; GO +-- syscurconfigs should also exist in dbo schema +select * from dbo.SySCuRConFIgS; +go + +CREATE DATABASE DB1; +GO + +-- In case of cross-db, syscurconfigs should also exist in dbo schema +SELECT * FROM db1.sys.SySCuRConFIgS; +GO + +SELECT * FROM db1.dbo.SySCuRConFIgS; +GO + SELECT * FROM sys.sysconfigures; GO +-- sysconfigures should also exist in dbo schema +select * from dbo.SySConFIGuReS; +go + +-- In case of cross-db, sysconfigures should also exist in dbo schema +SELECT * FROM db1.sys.SySConFIGuReS; +GO + +SELECT * FROM db1.dbo.SySConFIGuReS; +GO + SELECT * FROM sys.babelfish_configurations; GO @@ -24,3 +49,13 @@ INSERT INTO sys.babelfish_configurations 'testing' ); GO + +-- These below test cases are just to validate the schema rewrite from dbo to sys in different scenarios. +select (select count(*) from DbO.SySConFIGuReS) as x, (select count(*) from [DbO].SySCuRConFIgS) as y; +go + +select count(*) from DbO.SySConFIGuReS x inner join [DbO].SySCuRConFIgS y on x.value=y.value; +go + +DROP DATABASE DB1; +GO diff --git a/test/JDBC/input/views/sys-syscharsets-vu-verify.sql b/test/JDBC/input/views/sys-syscharsets-vu-verify.sql index bcacaf425d..5eb81065f1 100644 --- a/test/JDBC/input/views/sys-syscharsets-vu-verify.sql +++ b/test/JDBC/input/views/sys-syscharsets-vu-verify.sql @@ -2,4 +2,4 @@ USE master go select * from sys.syscharsets; -go \ No newline at end of file +go diff --git a/test/JDBC/input/views/sys-syscolumns.sql b/test/JDBC/input/views/sys-syscolumns.sql index d461717d0c..be76ab1665 100644 --- a/test/JDBC/input/views/sys-syscolumns.sql +++ b/test/JDBC/input/views/sys-syscolumns.sql @@ -58,18 +58,33 @@ GO select name, OidToObject(id), OidToDataType(xtype), typestat, length from sys.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' or name = 'col_d' order by OidToObject(id) asc, name GO +select name, OidToObject(id), OidToDataType(xtype), typestat, length from dbo.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' or name = 'col_d' order by OidToObject(id) asc, name +GO + select colid, cdefault, domain, number from sys.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' or name = 'col_d' order by OidToObject(id) asc, name GO +select colid, cdefault, domain, number from dbo.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' or name = 'col_d' order by OidToObject(id) asc, name +GO + select OidToCollation(collationid), status, OidToDataType(type), prec, scale from sys.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' or name = 'col_d' order by OidToObject(id) asc, name GO +select OidToCollation(collationid), status, OidToDataType(type), prec, scale from dbo.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' or name = 'col_d' order by OidToObject(id) asc, name +GO + select iscomputed, isoutparam, isnullable, collation from sys.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' or name = 'col_d' order by OidToObject(id) asc, name GO +select iscomputed, isoutparam, isnullable, collation from dbo.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' or name = 'col_d' order by OidToObject(id) asc, name +GO + SELECT COUNT(*) FROM sys.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' go +SELECT COUNT(*) FROM dbo.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' +go + use master; go @@ -79,20 +94,48 @@ go SELECT COUNT(*) FROM sys.syscolumns where name = '@thirdparam' go +-- syscolumns should also exist in dbo schema +SELECT COUNT(*) FROM dbo.SySCOluMNs where name = '@thirdparam'; +go + +SELECT COUNT(*) FROM db1.sys.SySCOluMNs where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' +go + +-- In case of cross-db, syscolumns should also exist in dbo schema +-- Cross-DB system view query is not currently supported in Babelfish. +SELECT COUNT(*) FROM db1.DbO.SySCOluMNs where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' +go + +-- should not be visible here +SELECT COUNT(*) FROM db1.sys.SySCOluMNs where name = '@thirdparam'; +GO + +SELECT COUNT(*) FROM db1.dbo.SySCOluMNs where name = '@thirdparam'; +GO + -- should not be visible here SELECT COUNT(*) FROM sys.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' go +SELECT COUNT(*) FROM dbo.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' +go + use db1; go SELECT COUNT(*) FROM sys.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' go +SELECT COUNT(*) FROM dbo.syscolumns where name = '@firstparam' or name = '@secondparam' or name = 'col_a' or name = 'col_b' or name = 'col_c' +go + -- should not be visible here SELECT COUNT(*) FROM sys.syscolumns where name = '@thirdparam' go +SELECT COUNT(*) FROM dbo.syscolumns where name = '@thirdparam' +go + -- Cleanup DROP FUNCTION OidToDataType DROP FUNCTION OidToObject diff --git a/test/JDBC/input/views/sys-sysforeignkeys.sql b/test/JDBC/input/views/sys-sysforeignkeys.sql index 03e8f742ea..c36799c537 100644 --- a/test/JDBC/input/views/sys-sysforeignkeys.sql +++ b/test/JDBC/input/views/sys-sysforeignkeys.sql @@ -13,6 +13,17 @@ GO select count(*) from sys.sysforeignkeys where fkeyid = object_id('fk_2'); GO +-- sysforeignkeys should also exist in dbo schema +SELECT COUNT(*) FROM dbo.SySFoReIGNkeYs where fkeyid = object_id('fk_2'); +go + +SELECT COUNT(*) FROM db1.sys.SySFoReIGNkeYs where fkeyid = object_id('fk_2'); +go + +-- In case of cross-db, sysforeignkeys should also exist in dbo schema +SELECT COUNT(*) FROM db1.dbo.SySFoReIGNkeYs where fkeyid = object_id('fk_2'); +go + select count(*) from sys.foreign_keys where parent_object_id = object_id('fk_2'); GO @@ -22,6 +33,9 @@ GO select count(*) from sys.sysforeignkeys where fkeyid = object_id('fk_2'); GO +select count(*) from dbo.sysforeignkeys where fkeyid = object_id('fk_2'); +GO + select count(*) from sys.foreign_keys where parent_object_id = object_id('fk_2'); GO @@ -34,6 +48,18 @@ GO select count(*) from sys.sysforeignkeys where fkeyid = object_id('fk_4'); GO +-- sysforeignkeys should also exist in dbo schema +SELECT COUNT(*) FROM dbo.SySFoReIGNkeYs where fkeyid = object_id('fk_4'); +go + +-- In case of cross-db, sysforeignkeys should also exist in dbo schema +-- should not be visible here +SELECT COUNT(*) FROM db1.sys.SySFoReIGNkeYs where fkeyid = object_id('fk_4'); +go + +SELECT COUNT(*) FROM db1.dbo.SySFoReIGNkeYs where fkeyid = object_id('fk_4'); +go + select count(*) from sys.foreign_keys where parent_object_id = object_id('fk_4'); GO @@ -43,6 +69,9 @@ GO select count(*) from sys.sysforeignkeys where fkeyid = object_id('fk_4'); GO +select count(*) from dbo.sysforeignkeys where fkeyid = object_id('fk_4'); +GO + select count(*) from sys.foreign_keys where parent_object_id = object_id('fk_4'); GO diff --git a/test/JDBC/input/views/sys-syslanguages.sql b/test/JDBC/input/views/sys-syslanguages.sql index cc39b9ff59..1def1572c2 100644 --- a/test/JDBC/input/views/sys-syslanguages.sql +++ b/test/JDBC/input/views/sys-syslanguages.sql @@ -3,3 +3,24 @@ GO SELECT * FROM sys.syslanguages WHERE langid = 1; GO + +-- syslanguages should also exist in dbo schema +select * from dbo.SySLanGUAgeS WHERE langid = 1; +go + +CREATE DATABASE DB1; +GO + +-- In case of cross-db, syslanguages should also exist in dbo schema +SELECT * FROM db1.sys.SySLanGUAgeS WHERE langid = 1; +GO + +SELECT * FROM db1.dbo.SySLanGUAgeS WHERE langid = 1; +GO + +-- These below test cases are just to validate the schema rewrite from dbo to sys in different scenarios. +select * from DbO.SySLanGUAgeS where langid = (SELECT count(*) FROM DbO.syslanguages WHERE langid = 1); +go + +DROP DATABASE DB1; +GO From e02911c048db35d71b8b1a82be28b1a814590925 Mon Sep 17 00:00:00 2001 From: Sumit Jaiswal <54075285+sumitj824@users.noreply.github.com> Date: Fri, 14 Apr 2023 09:53:31 +0530 Subject: [PATCH 059/363] Fix the output style for NVARCHAR datatype in CONVERT function (#1425) Earlier when we were converting from DATE/TIME types to NVARCHAR type using CONVERT function the output style was not getting into account as we have not handled the case for NVARCHAR type in TsqlFunctionConvert function correctly. This commit add changes to handle the case for NVARCHAR correctly. Task: BABEL-4078 Signed-off-by: Sumit Jaiswal --- .../src/backend_parser/gram-tsql-epilogue.y.c | 2 +- ...EL-4078-before-14_8-or-15_3-vu-cleanup.out | 50 +++++++ ...EL-4078-before-14_8-or-15_3-vu-prepare.out | 109 ++++++++++++++ ...BEL-4078-before-14_8-or-15_3-vu-verify.out | 135 ++++++++++++++++++ test/JDBC/expected/BABEL-4078-vu-cleanup.out | 50 +++++++ test/JDBC/expected/BABEL-4078-vu-prepare.out | 109 ++++++++++++++ test/JDBC/expected/BABEL-4078-vu-verify.out | 135 ++++++++++++++++++ .../ISC-Check-Constraints-vu-verify.out | 2 +- ...EL-4078-before-14_8-or-15_3-vu-cleanup.sql | 50 +++++++ ...EL-4078-before-14_8-or-15_3-vu-prepare.sql | 109 ++++++++++++++ ...BEL-4078-before-14_8-or-15_3-vu-verify.sql | 50 +++++++ test/JDBC/input/BABEL-4078-vu-cleanup.sql | 50 +++++++ test/JDBC/input/BABEL-4078-vu-prepare.sql | 109 ++++++++++++++ test/JDBC/input/BABEL-4078-vu-verify.sql | 50 +++++++ test/JDBC/jdbc_schedule | 5 + test/JDBC/upgrade/13_4/schedule | 1 + test/JDBC/upgrade/13_5/schedule | 1 + test/JDBC/upgrade/13_6/schedule | 1 + test/JDBC/upgrade/13_7/schedule | 1 + test/JDBC/upgrade/13_8/schedule | 1 + test/JDBC/upgrade/13_9/schedule | 1 + test/JDBC/upgrade/14_3/schedule | 1 + test/JDBC/upgrade/14_5/schedule | 1 + test/JDBC/upgrade/14_6/schedule | 1 + test/JDBC/upgrade/14_7/schedule | 1 + test/JDBC/upgrade/14_8/schedule | 1 + test/JDBC/upgrade/15_1/schedule | 1 + test/JDBC/upgrade/15_2/schedule | 1 + test/JDBC/upgrade/latest/schedule | 1 + 29 files changed, 1027 insertions(+), 2 deletions(-) create mode 100644 test/JDBC/expected/BABEL-4078-before-14_8-or-15_3-vu-cleanup.out create mode 100644 test/JDBC/expected/BABEL-4078-before-14_8-or-15_3-vu-prepare.out create mode 100644 test/JDBC/expected/BABEL-4078-before-14_8-or-15_3-vu-verify.out create mode 100644 test/JDBC/expected/BABEL-4078-vu-cleanup.out create mode 100644 test/JDBC/expected/BABEL-4078-vu-prepare.out create mode 100644 test/JDBC/expected/BABEL-4078-vu-verify.out create mode 100644 test/JDBC/input/BABEL-4078-before-14_8-or-15_3-vu-cleanup.sql create mode 100644 test/JDBC/input/BABEL-4078-before-14_8-or-15_3-vu-prepare.sql create mode 100644 test/JDBC/input/BABEL-4078-before-14_8-or-15_3-vu-verify.sql create mode 100644 test/JDBC/input/BABEL-4078-vu-cleanup.sql create mode 100644 test/JDBC/input/BABEL-4078-vu-prepare.sql create mode 100644 test/JDBC/input/BABEL-4078-vu-verify.sql diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c index 858191bdce..8601c53449 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c @@ -201,7 +201,7 @@ TsqlFunctionConvert(TypeName *typename, Node *arg, Node *style, bool try, int lo else if (type_oid == typenameTypeId(NULL, makeTypeName("datetime"))) result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_conv_helper_to_datetime"), args, COERCE_EXPLICIT_CALL, location); - else if (strcmp(typename_string, "varchar") == 0) + else if ((strcmp(typename_string, "varchar") == 0) || (strcmp(typename_string, "nvarchar") == 0)) { Node *helperFuncCall; diff --git a/test/JDBC/expected/BABEL-4078-before-14_8-or-15_3-vu-cleanup.out b/test/JDBC/expected/BABEL-4078-before-14_8-or-15_3-vu-cleanup.out new file mode 100644 index 0000000000..dc5355264e --- /dev/null +++ b/test/JDBC/expected/BABEL-4078-before-14_8-or-15_3-vu-cleanup.out @@ -0,0 +1,50 @@ +DROP VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view1 +GO + +DROP VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view11 +GO + +DROP VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view2 +GO + +DROP VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view22 +GO + +DROP PROCEDURE babel_4078_before_14_8_or_15_3_vu_prepare_proc1 +GO + +DROP PROCEDURE babel_4078_before_14_8_or_15_3_vu_prepare_proc11 +GO + +DROP PROCEDURE babel_4078_before_14_8_or_15_3_vu_prepare_proc2 +GO + +DROP PROCEDURE babel_4078_before_14_8_or_15_3_vu_prepare_proc22 +GO + +DROP FUNCTION babel_4078_before_14_8_or_15_3_vu_prepare_func1 +GO + +DROP FUNCTION babel_4078_before_14_8_or_15_3_vu_prepare_func11 +GO + +DROP FUNCTION babel_4078_before_14_8_or_15_3_vu_prepare_func2 +GO + +DROP FUNCTION babel_4078_before_14_8_or_15_3_vu_prepare_func22 +GO + +DROP VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view3 +GO + +DROP VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view4 +GO + +DROP VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view5 +GO + +DROP VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view6 +GO + +DROP VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view7 +GO diff --git a/test/JDBC/expected/BABEL-4078-before-14_8-or-15_3-vu-prepare.out b/test/JDBC/expected/BABEL-4078-before-14_8-or-15_3-vu-prepare.out new file mode 100644 index 0000000000..fd18b8e37c --- /dev/null +++ b/test/JDBC/expected/BABEL-4078-before-14_8-or-15_3-vu-prepare.out @@ -0,0 +1,109 @@ +-- default style +CREATE VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view1 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE)) result +GO + +-- different style +CREATE VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view11 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE), 105) result +GO + +-- default style +CREATE VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view2 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME)) result +GO + +-- different style +CREATE VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view22 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME), 20) result +GO + +-- default style +CREATE PROCEDURE babel_4078_before_14_8_or_15_3_vu_prepare_proc1 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE)) result +GO + +-- different style +CREATE PROCEDURE babel_4078_before_14_8_or_15_3_vu_prepare_proc11 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE), 105) result +GO + +-- default style +CREATE PROCEDURE babel_4078_before_14_8_or_15_3_vu_prepare_proc2 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME)) result +GO + +-- different style +CREATE PROCEDURE babel_4078_before_14_8_or_15_3_vu_prepare_proc22 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME), 20) result +GO + +-- default style +CREATE FUNCTION babel_4078_before_14_8_or_15_3_vu_prepare_func1() +RETURNS TABLE +AS +RETURN (SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE)) result) +GO + +-- different style +CREATE FUNCTION babel_4078_before_14_8_or_15_3_vu_prepare_func11() +RETURNS TABLE +AS +RETURN (SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE), 105) result) +GO + +-- different style +CREATE FUNCTION babel_4078_before_14_8_or_15_3_vu_prepare_func2() +RETURNS TABLE +AS +RETURN (SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME)) result) +GO + +-- different style +CREATE FUNCTION babel_4078_before_14_8_or_15_3_vu_prepare_func22() +RETURNS TABLE +AS +RETURN (SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME), 20) result) +GO + +-- to verify that is returning expected the default style +CREATE VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view3 AS +SELECT CASE + WHEN CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE)) = CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE), 20) + THEN 'true' + else 'false' + END result +GO + +CREATE VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view4 AS +SELECT CASE + WHEN CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME)) = CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME), 25) + THEN 'true' + else 'false' + END result +GO + +CREATE VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view5 AS +SELECT CASE + WHEN CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as sys.DATETIME)) = CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as sys.DATETIME), 0) + THEN 'true' + else 'false' + END result +GO + +CREATE VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view6 AS +SELECT CASE + WHEN CONVERT(NVARCHAR(10), CAST('1.0001' as float)) = CONVERT(NVARCHAR(10), CAST('1.0001' as float), 0) + THEN 'true' + else 'false' + END result +GO + +CREATE VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view7 AS +SELECT CASE + WHEN CONVERT(NVARCHAR(10), CAST('1.0001' as sys.money)) = CONVERT(NVARCHAR(10), CAST('1.0001' as sys.money), 0) + THEN 'true' + else 'false' + END result +GO + diff --git a/test/JDBC/expected/BABEL-4078-before-14_8-or-15_3-vu-verify.out b/test/JDBC/expected/BABEL-4078-before-14_8-or-15_3-vu-verify.out new file mode 100644 index 0000000000..68a05a05d3 --- /dev/null +++ b/test/JDBC/expected/BABEL-4078-before-14_8-or-15_3-vu-verify.out @@ -0,0 +1,135 @@ +SELECT * FROM babel_4078_before_14_8_or_15_3_vu_prepare_view1 +GO +~~START~~ +nvarchar +2023-02-03 +~~END~~ + + +SELECT * FROM babel_4078_before_14_8_or_15_3_vu_prepare_view11 +GO +~~START~~ +nvarchar +2023-02-03 +~~END~~ + + +SELECT * FROM babel_4078_before_14_8_or_15_3_vu_prepare_view2 +GO +~~START~~ +nvarchar +19:08:35.5 +~~END~~ + + +SELECT * FROM babel_4078_before_14_8_or_15_3_vu_prepare_view22 +GO +~~START~~ +nvarchar +19:08:35.5 +~~END~~ + + +EXEC babel_4078_before_14_8_or_15_3_vu_prepare_proc1 +GO +~~START~~ +nvarchar +2023-02-03 +~~END~~ + + +EXEC babel_4078_before_14_8_or_15_3_vu_prepare_proc11 +GO +~~START~~ +nvarchar +03-02-2023 +~~END~~ + + +EXEC babel_4078_before_14_8_or_15_3_vu_prepare_proc2 +GO +~~START~~ +nvarchar +19:08:35.5 +~~END~~ + + +EXEC babel_4078_before_14_8_or_15_3_vu_prepare_proc22 +GO +~~START~~ +nvarchar +19:08:35 +~~END~~ + + +SELECT * FROM babel_4078_before_14_8_or_15_3_vu_prepare_func1() +GO +~~START~~ +nvarchar +2023-02-03 +~~END~~ + + +SELECT * FROM babel_4078_before_14_8_or_15_3_vu_prepare_func11() +GO +~~START~~ +nvarchar +03-02-2023 +~~END~~ + + +SELECT * FROM babel_4078_before_14_8_or_15_3_vu_prepare_func2() +GO +~~START~~ +nvarchar +19:08:35.5 +~~END~~ + + +SELECT * FROM babel_4078_before_14_8_or_15_3_vu_prepare_func22() +GO +~~START~~ +nvarchar +19:08:35 +~~END~~ + + +SELECT * FROM babel_4078_before_14_8_or_15_3_vu_prepare_view3 +GO +~~START~~ +text +true +~~END~~ + + +SELECT * FROM babel_4078_before_14_8_or_15_3_vu_prepare_view4 +GO +~~START~~ +text +true +~~END~~ + + +SELECT * FROM babel_4078_before_14_8_or_15_3_vu_prepare_view5 +GO +~~START~~ +text +true +~~END~~ + + +SELECT * FROM babel_4078_before_14_8_or_15_3_vu_prepare_view6 +GO +~~START~~ +text +true +~~END~~ + + +SELECT * FROM babel_4078_before_14_8_or_15_3_vu_prepare_view7 +GO +~~START~~ +text +true +~~END~~ + diff --git a/test/JDBC/expected/BABEL-4078-vu-cleanup.out b/test/JDBC/expected/BABEL-4078-vu-cleanup.out new file mode 100644 index 0000000000..7b9901acaa --- /dev/null +++ b/test/JDBC/expected/BABEL-4078-vu-cleanup.out @@ -0,0 +1,50 @@ +DROP VIEW babel_4078_vu_prepare_view1 +GO + +DROP VIEW babel_4078_vu_prepare_view11 +GO + +DROP VIEW babel_4078_vu_prepare_view2 +GO + +DROP VIEW babel_4078_vu_prepare_view22 +GO + +DROP PROCEDURE babel_4078_vu_prepare_proc1 +GO + +DROP PROCEDURE babel_4078_vu_prepare_proc11 +GO + +DROP PROCEDURE babel_4078_vu_prepare_proc2 +GO + +DROP PROCEDURE babel_4078_vu_prepare_proc22 +GO + +DROP FUNCTION babel_4078_vu_prepare_func1 +GO + +DROP FUNCTION babel_4078_vu_prepare_func11 +GO + +DROP FUNCTION babel_4078_vu_prepare_func2 +GO + +DROP FUNCTION babel_4078_vu_prepare_func22 +GO + +DROP VIEW babel_4078_vu_prepare_view3 +GO + +DROP VIEW babel_4078_vu_prepare_view4 +GO + +DROP VIEW babel_4078_vu_prepare_view5 +GO + +DROP VIEW babel_4078_vu_prepare_view6 +GO + +DROP VIEW babel_4078_vu_prepare_view7 +GO diff --git a/test/JDBC/expected/BABEL-4078-vu-prepare.out b/test/JDBC/expected/BABEL-4078-vu-prepare.out new file mode 100644 index 0000000000..a266628abc --- /dev/null +++ b/test/JDBC/expected/BABEL-4078-vu-prepare.out @@ -0,0 +1,109 @@ +-- default style +CREATE VIEW babel_4078_vu_prepare_view1 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE)) result +GO + +-- different style +CREATE VIEW babel_4078_vu_prepare_view11 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE), 105) result +GO + +-- default style +CREATE VIEW babel_4078_vu_prepare_view2 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME)) result +GO + +-- different style +CREATE VIEW babel_4078_vu_prepare_view22 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME), 20) result +GO + +-- default style +CREATE PROCEDURE babel_4078_vu_prepare_proc1 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE)) result +GO + +-- different style +CREATE PROCEDURE babel_4078_vu_prepare_proc11 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE), 105) result +GO + +-- default style +CREATE PROCEDURE babel_4078_vu_prepare_proc2 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME)) result +GO + +-- different style +CREATE PROCEDURE babel_4078_vu_prepare_proc22 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME), 20) result +GO + +-- default style +CREATE FUNCTION babel_4078_vu_prepare_func1() +RETURNS TABLE +AS +RETURN (SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE)) result) +GO + +-- different style +CREATE FUNCTION babel_4078_vu_prepare_func11() +RETURNS TABLE +AS +RETURN (SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE), 105) result) +GO + +-- different style +CREATE FUNCTION babel_4078_vu_prepare_func2() +RETURNS TABLE +AS +RETURN (SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME)) result) +GO + +-- different style +CREATE FUNCTION babel_4078_vu_prepare_func22() +RETURNS TABLE +AS +RETURN (SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME), 20) result) +GO + +-- to verify that is returning expected the default style +CREATE VIEW babel_4078_vu_prepare_view3 AS +SELECT CASE + WHEN CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE)) = CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE), 20) + THEN 'true' + else 'false' + END result +GO + +CREATE VIEW babel_4078_vu_prepare_view4 AS +SELECT CASE + WHEN CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME)) = CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME), 25) + THEN 'true' + else 'false' + END result +GO + +CREATE VIEW babel_4078_vu_prepare_view5 AS +SELECT CASE + WHEN CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as sys.DATETIME)) = CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as sys.DATETIME), 0) + THEN 'true' + else 'false' + END result +GO + +CREATE VIEW babel_4078_vu_prepare_view6 AS +SELECT CASE + WHEN CONVERT(NVARCHAR(10), CAST('1.0001' as float)) = CONVERT(NVARCHAR(10), CAST('1.0001' as float), 0) + THEN 'true' + else 'false' + END result +GO + +CREATE VIEW babel_4078_vu_prepare_view7 AS +SELECT CASE + WHEN CONVERT(NVARCHAR(10), CAST('1.0001' as sys.money)) = CONVERT(NVARCHAR(10), CAST('1.0001' as sys.money), 0) + THEN 'true' + else 'false' + END result +GO + diff --git a/test/JDBC/expected/BABEL-4078-vu-verify.out b/test/JDBC/expected/BABEL-4078-vu-verify.out new file mode 100644 index 0000000000..90348fe468 --- /dev/null +++ b/test/JDBC/expected/BABEL-4078-vu-verify.out @@ -0,0 +1,135 @@ +SELECT * FROM babel_4078_vu_prepare_view1 +GO +~~START~~ +nvarchar +2023-02-03 +~~END~~ + + +SELECT * FROM babel_4078_vu_prepare_view11 +GO +~~START~~ +nvarchar +03-02-2023 +~~END~~ + + +SELECT * FROM babel_4078_vu_prepare_view2 +GO +~~START~~ +nvarchar +19:08:35.5 +~~END~~ + + +SELECT * FROM babel_4078_vu_prepare_view22 +GO +~~START~~ +nvarchar +19:08:35 +~~END~~ + + +EXEC babel_4078_vu_prepare_proc1 +GO +~~START~~ +nvarchar +2023-02-03 +~~END~~ + + +EXEC babel_4078_vu_prepare_proc11 +GO +~~START~~ +nvarchar +03-02-2023 +~~END~~ + + +EXEC babel_4078_vu_prepare_proc2 +GO +~~START~~ +nvarchar +19:08:35.5 +~~END~~ + + +EXEC babel_4078_vu_prepare_proc22 +GO +~~START~~ +nvarchar +19:08:35 +~~END~~ + + +SELECT * FROM babel_4078_vu_prepare_func1() +GO +~~START~~ +nvarchar +2023-02-03 +~~END~~ + + +SELECT * FROM babel_4078_vu_prepare_func11() +GO +~~START~~ +nvarchar +03-02-2023 +~~END~~ + + +SELECT * FROM babel_4078_vu_prepare_func2() +GO +~~START~~ +nvarchar +19:08:35.5 +~~END~~ + + +SELECT * FROM babel_4078_vu_prepare_func22() +GO +~~START~~ +nvarchar +19:08:35 +~~END~~ + + +SELECT * FROM babel_4078_vu_prepare_view3 +GO +~~START~~ +text +true +~~END~~ + + +SELECT * FROM babel_4078_vu_prepare_view4 +GO +~~START~~ +text +true +~~END~~ + + +SELECT * FROM babel_4078_vu_prepare_view5 +GO +~~START~~ +text +true +~~END~~ + + +SELECT * FROM babel_4078_vu_prepare_view6 +GO +~~START~~ +text +true +~~END~~ + + +SELECT * FROM babel_4078_vu_prepare_view7 +GO +~~START~~ +text +true +~~END~~ + diff --git a/test/JDBC/expected/ISC-Check-Constraints-vu-verify.out b/test/JDBC/expected/ISC-Check-Constraints-vu-verify.out index 0e25091475..7a3cadc637 100644 --- a/test/JDBC/expected/ISC-Check-Constraints-vu-verify.out +++ b/test/JDBC/expected/ISC-Check-Constraints-vu-verify.out @@ -33,7 +33,7 @@ isc_check_constraints_db1#!#dbo#!#test_datetime_c_time_check#!#(((c_time < '09:0 isc_check_constraints_db1#!#dbo#!#test_functioncall_col1_check#!#((isjson(col1) > 0)) isc_check_constraints_db1#!#dbo#!#test_functioncall_col1_check1#!#(("right"(col1, 1) <> ',')) isc_check_constraints_db1#!#dbo#!#test_functioncall_col1_check2#!#((ltrim(col1) <> '')) -isc_check_constraints_db1#!#dbo#!#test_functioncall_col1_check3#!#((CAST((getutcdate() AT TIME ZONE col1) AS nvarchar(128)) <> '')) +isc_check_constraints_db1#!#dbo#!#test_functioncall_col1_check3#!#((CAST((babelfish_conv_helper_to_varchar('character varying(128)', getutcdate() AT TIME ZONE col1, false)) AS nvarchar(128)) <> '')) isc_check_constraints_db1#!#dbo#!#test_null_a_check#!#((a IS NOT NULL)) isc_check_constraints_db1#!#dbo#!#test_null1_a_check#!#((a <> CAST(NULL AS int))) isc_check_constraints_db1#!#dbo#!#test_null1_b_check#!#((b = CAST(NULL AS int))) diff --git a/test/JDBC/input/BABEL-4078-before-14_8-or-15_3-vu-cleanup.sql b/test/JDBC/input/BABEL-4078-before-14_8-or-15_3-vu-cleanup.sql new file mode 100644 index 0000000000..7638e5f4b8 --- /dev/null +++ b/test/JDBC/input/BABEL-4078-before-14_8-or-15_3-vu-cleanup.sql @@ -0,0 +1,50 @@ +DROP VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view1 +GO + +DROP VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view11 +GO + +DROP VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view2 +GO + +DROP VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view22 +GO + +DROP PROCEDURE babel_4078_before_14_8_or_15_3_vu_prepare_proc1 +GO + +DROP PROCEDURE babel_4078_before_14_8_or_15_3_vu_prepare_proc11 +GO + +DROP PROCEDURE babel_4078_before_14_8_or_15_3_vu_prepare_proc2 +GO + +DROP PROCEDURE babel_4078_before_14_8_or_15_3_vu_prepare_proc22 +GO + +DROP FUNCTION babel_4078_before_14_8_or_15_3_vu_prepare_func1 +GO + +DROP FUNCTION babel_4078_before_14_8_or_15_3_vu_prepare_func11 +GO + +DROP FUNCTION babel_4078_before_14_8_or_15_3_vu_prepare_func2 +GO + +DROP FUNCTION babel_4078_before_14_8_or_15_3_vu_prepare_func22 +GO + +DROP VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view3 +GO + +DROP VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view4 +GO + +DROP VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view5 +GO + +DROP VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view6 +GO + +DROP VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view7 +GO \ No newline at end of file diff --git a/test/JDBC/input/BABEL-4078-before-14_8-or-15_3-vu-prepare.sql b/test/JDBC/input/BABEL-4078-before-14_8-or-15_3-vu-prepare.sql new file mode 100644 index 0000000000..fd18b8e37c --- /dev/null +++ b/test/JDBC/input/BABEL-4078-before-14_8-or-15_3-vu-prepare.sql @@ -0,0 +1,109 @@ +-- default style +CREATE VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view1 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE)) result +GO + +-- different style +CREATE VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view11 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE), 105) result +GO + +-- default style +CREATE VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view2 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME)) result +GO + +-- different style +CREATE VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view22 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME), 20) result +GO + +-- default style +CREATE PROCEDURE babel_4078_before_14_8_or_15_3_vu_prepare_proc1 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE)) result +GO + +-- different style +CREATE PROCEDURE babel_4078_before_14_8_or_15_3_vu_prepare_proc11 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE), 105) result +GO + +-- default style +CREATE PROCEDURE babel_4078_before_14_8_or_15_3_vu_prepare_proc2 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME)) result +GO + +-- different style +CREATE PROCEDURE babel_4078_before_14_8_or_15_3_vu_prepare_proc22 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME), 20) result +GO + +-- default style +CREATE FUNCTION babel_4078_before_14_8_or_15_3_vu_prepare_func1() +RETURNS TABLE +AS +RETURN (SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE)) result) +GO + +-- different style +CREATE FUNCTION babel_4078_before_14_8_or_15_3_vu_prepare_func11() +RETURNS TABLE +AS +RETURN (SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE), 105) result) +GO + +-- different style +CREATE FUNCTION babel_4078_before_14_8_or_15_3_vu_prepare_func2() +RETURNS TABLE +AS +RETURN (SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME)) result) +GO + +-- different style +CREATE FUNCTION babel_4078_before_14_8_or_15_3_vu_prepare_func22() +RETURNS TABLE +AS +RETURN (SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME), 20) result) +GO + +-- to verify that is returning expected the default style +CREATE VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view3 AS +SELECT CASE + WHEN CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE)) = CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE), 20) + THEN 'true' + else 'false' + END result +GO + +CREATE VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view4 AS +SELECT CASE + WHEN CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME)) = CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME), 25) + THEN 'true' + else 'false' + END result +GO + +CREATE VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view5 AS +SELECT CASE + WHEN CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as sys.DATETIME)) = CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as sys.DATETIME), 0) + THEN 'true' + else 'false' + END result +GO + +CREATE VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view6 AS +SELECT CASE + WHEN CONVERT(NVARCHAR(10), CAST('1.0001' as float)) = CONVERT(NVARCHAR(10), CAST('1.0001' as float), 0) + THEN 'true' + else 'false' + END result +GO + +CREATE VIEW babel_4078_before_14_8_or_15_3_vu_prepare_view7 AS +SELECT CASE + WHEN CONVERT(NVARCHAR(10), CAST('1.0001' as sys.money)) = CONVERT(NVARCHAR(10), CAST('1.0001' as sys.money), 0) + THEN 'true' + else 'false' + END result +GO + diff --git a/test/JDBC/input/BABEL-4078-before-14_8-or-15_3-vu-verify.sql b/test/JDBC/input/BABEL-4078-before-14_8-or-15_3-vu-verify.sql new file mode 100644 index 0000000000..be08044dd0 --- /dev/null +++ b/test/JDBC/input/BABEL-4078-before-14_8-or-15_3-vu-verify.sql @@ -0,0 +1,50 @@ +SELECT * FROM babel_4078_before_14_8_or_15_3_vu_prepare_view1 +GO + +SELECT * FROM babel_4078_before_14_8_or_15_3_vu_prepare_view11 +GO + +SELECT * FROM babel_4078_before_14_8_or_15_3_vu_prepare_view2 +GO + +SELECT * FROM babel_4078_before_14_8_or_15_3_vu_prepare_view22 +GO + +EXEC babel_4078_before_14_8_or_15_3_vu_prepare_proc1 +GO + +EXEC babel_4078_before_14_8_or_15_3_vu_prepare_proc11 +GO + +EXEC babel_4078_before_14_8_or_15_3_vu_prepare_proc2 +GO + +EXEC babel_4078_before_14_8_or_15_3_vu_prepare_proc22 +GO + +SELECT * FROM babel_4078_before_14_8_or_15_3_vu_prepare_func1() +GO + +SELECT * FROM babel_4078_before_14_8_or_15_3_vu_prepare_func11() +GO + +SELECT * FROM babel_4078_before_14_8_or_15_3_vu_prepare_func2() +GO + +SELECT * FROM babel_4078_before_14_8_or_15_3_vu_prepare_func22() +GO + +SELECT * FROM babel_4078_before_14_8_or_15_3_vu_prepare_view3 +GO + +SELECT * FROM babel_4078_before_14_8_or_15_3_vu_prepare_view4 +GO + +SELECT * FROM babel_4078_before_14_8_or_15_3_vu_prepare_view5 +GO + +SELECT * FROM babel_4078_before_14_8_or_15_3_vu_prepare_view6 +GO + +SELECT * FROM babel_4078_before_14_8_or_15_3_vu_prepare_view7 +GO diff --git a/test/JDBC/input/BABEL-4078-vu-cleanup.sql b/test/JDBC/input/BABEL-4078-vu-cleanup.sql new file mode 100644 index 0000000000..1a45587cb0 --- /dev/null +++ b/test/JDBC/input/BABEL-4078-vu-cleanup.sql @@ -0,0 +1,50 @@ +DROP VIEW babel_4078_vu_prepare_view1 +GO + +DROP VIEW babel_4078_vu_prepare_view11 +GO + +DROP VIEW babel_4078_vu_prepare_view2 +GO + +DROP VIEW babel_4078_vu_prepare_view22 +GO + +DROP PROCEDURE babel_4078_vu_prepare_proc1 +GO + +DROP PROCEDURE babel_4078_vu_prepare_proc11 +GO + +DROP PROCEDURE babel_4078_vu_prepare_proc2 +GO + +DROP PROCEDURE babel_4078_vu_prepare_proc22 +GO + +DROP FUNCTION babel_4078_vu_prepare_func1 +GO + +DROP FUNCTION babel_4078_vu_prepare_func11 +GO + +DROP FUNCTION babel_4078_vu_prepare_func2 +GO + +DROP FUNCTION babel_4078_vu_prepare_func22 +GO + +DROP VIEW babel_4078_vu_prepare_view3 +GO + +DROP VIEW babel_4078_vu_prepare_view4 +GO + +DROP VIEW babel_4078_vu_prepare_view5 +GO + +DROP VIEW babel_4078_vu_prepare_view6 +GO + +DROP VIEW babel_4078_vu_prepare_view7 +GO \ No newline at end of file diff --git a/test/JDBC/input/BABEL-4078-vu-prepare.sql b/test/JDBC/input/BABEL-4078-vu-prepare.sql new file mode 100644 index 0000000000..a266628abc --- /dev/null +++ b/test/JDBC/input/BABEL-4078-vu-prepare.sql @@ -0,0 +1,109 @@ +-- default style +CREATE VIEW babel_4078_vu_prepare_view1 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE)) result +GO + +-- different style +CREATE VIEW babel_4078_vu_prepare_view11 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE), 105) result +GO + +-- default style +CREATE VIEW babel_4078_vu_prepare_view2 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME)) result +GO + +-- different style +CREATE VIEW babel_4078_vu_prepare_view22 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME), 20) result +GO + +-- default style +CREATE PROCEDURE babel_4078_vu_prepare_proc1 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE)) result +GO + +-- different style +CREATE PROCEDURE babel_4078_vu_prepare_proc11 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE), 105) result +GO + +-- default style +CREATE PROCEDURE babel_4078_vu_prepare_proc2 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME)) result +GO + +-- different style +CREATE PROCEDURE babel_4078_vu_prepare_proc22 AS +SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME), 20) result +GO + +-- default style +CREATE FUNCTION babel_4078_vu_prepare_func1() +RETURNS TABLE +AS +RETURN (SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE)) result) +GO + +-- different style +CREATE FUNCTION babel_4078_vu_prepare_func11() +RETURNS TABLE +AS +RETURN (SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE), 105) result) +GO + +-- different style +CREATE FUNCTION babel_4078_vu_prepare_func2() +RETURNS TABLE +AS +RETURN (SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME)) result) +GO + +-- different style +CREATE FUNCTION babel_4078_vu_prepare_func22() +RETURNS TABLE +AS +RETURN (SELECT CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME), 20) result) +GO + +-- to verify that is returning expected the default style +CREATE VIEW babel_4078_vu_prepare_view3 AS +SELECT CASE + WHEN CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE)) = CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as DATE), 20) + THEN 'true' + else 'false' + END result +GO + +CREATE VIEW babel_4078_vu_prepare_view4 AS +SELECT CASE + WHEN CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME)) = CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as TIME), 25) + THEN 'true' + else 'false' + END result +GO + +CREATE VIEW babel_4078_vu_prepare_view5 AS +SELECT CASE + WHEN CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as sys.DATETIME)) = CONVERT(NVARCHAR(10), CAST('2023-02-03 19:08:35.527' as sys.DATETIME), 0) + THEN 'true' + else 'false' + END result +GO + +CREATE VIEW babel_4078_vu_prepare_view6 AS +SELECT CASE + WHEN CONVERT(NVARCHAR(10), CAST('1.0001' as float)) = CONVERT(NVARCHAR(10), CAST('1.0001' as float), 0) + THEN 'true' + else 'false' + END result +GO + +CREATE VIEW babel_4078_vu_prepare_view7 AS +SELECT CASE + WHEN CONVERT(NVARCHAR(10), CAST('1.0001' as sys.money)) = CONVERT(NVARCHAR(10), CAST('1.0001' as sys.money), 0) + THEN 'true' + else 'false' + END result +GO + diff --git a/test/JDBC/input/BABEL-4078-vu-verify.sql b/test/JDBC/input/BABEL-4078-vu-verify.sql new file mode 100644 index 0000000000..040889d1d4 --- /dev/null +++ b/test/JDBC/input/BABEL-4078-vu-verify.sql @@ -0,0 +1,50 @@ +SELECT * FROM babel_4078_vu_prepare_view1 +GO + +SELECT * FROM babel_4078_vu_prepare_view11 +GO + +SELECT * FROM babel_4078_vu_prepare_view2 +GO + +SELECT * FROM babel_4078_vu_prepare_view22 +GO + +EXEC babel_4078_vu_prepare_proc1 +GO + +EXEC babel_4078_vu_prepare_proc11 +GO + +EXEC babel_4078_vu_prepare_proc2 +GO + +EXEC babel_4078_vu_prepare_proc22 +GO + +SELECT * FROM babel_4078_vu_prepare_func1() +GO + +SELECT * FROM babel_4078_vu_prepare_func11() +GO + +SELECT * FROM babel_4078_vu_prepare_func2() +GO + +SELECT * FROM babel_4078_vu_prepare_func22() +GO + +SELECT * FROM babel_4078_vu_prepare_view3 +GO + +SELECT * FROM babel_4078_vu_prepare_view4 +GO + +SELECT * FROM babel_4078_vu_prepare_view5 +GO + +SELECT * FROM babel_4078_vu_prepare_view6 +GO + +SELECT * FROM babel_4078_vu_prepare_view7 +GO diff --git a/test/JDBC/jdbc_schedule b/test/JDBC/jdbc_schedule index 17b0342a21..2485c4b9a7 100644 --- a/test/JDBC/jdbc_schedule +++ b/test/JDBC/jdbc_schedule @@ -122,3 +122,8 @@ ignore#!#openquery_upgrd-vu-cleanup ignore#!#Test-Identity-before-14_7-or-15_2-vu-prepare ignore#!#Test-Identity-before-14_7-or-15_2-vu-verify ignore#!#Test-Identity-before-14_7-or-15_2-vu-cleanup + +# These tests are meant for upgrade scenario prior to (potential) 14_8 or 15_3 release +ignore#!#BABEL-4078-before-14_8-or-15_3-vu-prepare +ignore#!#BABEL-4078-before-14_8-or-15_3-vu-verify +ignore#!#BABEL-4078-before-14_8-or-15_3-vu-cleanup diff --git a/test/JDBC/upgrade/13_4/schedule b/test/JDBC/upgrade/13_4/schedule index 7b5385c581..97822bc322 100644 --- a/test/JDBC/upgrade/13_4/schedule +++ b/test/JDBC/upgrade/13_4/schedule @@ -203,3 +203,4 @@ BABEL-3474 datetime2fromparts timefromparts BABEL-3215 +BABEL-4078-before-14_8-or-15_3 diff --git a/test/JDBC/upgrade/13_5/schedule b/test/JDBC/upgrade/13_5/schedule index 03da225e81..dc2795f16f 100644 --- a/test/JDBC/upgrade/13_5/schedule +++ b/test/JDBC/upgrade/13_5/schedule @@ -254,3 +254,4 @@ BABEL-3474 datetime2fromparts timefromparts BABEL-3215 +BABEL-4078-before-14_8-or-15_3 diff --git a/test/JDBC/upgrade/13_6/schedule b/test/JDBC/upgrade/13_6/schedule index 657a64e1d3..b68ff8dcbd 100644 --- a/test/JDBC/upgrade/13_6/schedule +++ b/test/JDBC/upgrade/13_6/schedule @@ -313,3 +313,4 @@ BABEL-3474 datetime2fromparts timefromparts BABEL-3215 +BABEL-4078-before-14_8-or-15_3 diff --git a/test/JDBC/upgrade/13_7/schedule b/test/JDBC/upgrade/13_7/schedule index a170009382..f84e5f7502 100644 --- a/test/JDBC/upgrade/13_7/schedule +++ b/test/JDBC/upgrade/13_7/schedule @@ -308,3 +308,4 @@ BABEL-3474 datetime2fromparts timefromparts BABEL-3215 +BABEL-4078-before-14_8-or-15_3 diff --git a/test/JDBC/upgrade/13_8/schedule b/test/JDBC/upgrade/13_8/schedule index a170009382..f84e5f7502 100644 --- a/test/JDBC/upgrade/13_8/schedule +++ b/test/JDBC/upgrade/13_8/schedule @@ -308,3 +308,4 @@ BABEL-3474 datetime2fromparts timefromparts BABEL-3215 +BABEL-4078-before-14_8-or-15_3 diff --git a/test/JDBC/upgrade/13_9/schedule b/test/JDBC/upgrade/13_9/schedule index d01b39cf98..00e29b74d7 100644 --- a/test/JDBC/upgrade/13_9/schedule +++ b/test/JDBC/upgrade/13_9/schedule @@ -311,3 +311,4 @@ BABEL-3474 datetime2fromparts timefromparts BABEL-3215 +BABEL-4078-before-14_8-or-15_3 diff --git a/test/JDBC/upgrade/14_3/schedule b/test/JDBC/upgrade/14_3/schedule index b8625299a2..d62ff431c6 100644 --- a/test/JDBC/upgrade/14_3/schedule +++ b/test/JDBC/upgrade/14_3/schedule @@ -327,3 +327,4 @@ BABEL-3818 datetime2fromparts timefromparts BABEL-3215 +BABEL-4078-before-14_8-or-15_3 diff --git a/test/JDBC/upgrade/14_5/schedule b/test/JDBC/upgrade/14_5/schedule index c3705c0492..2e65ad5d5b 100644 --- a/test/JDBC/upgrade/14_5/schedule +++ b/test/JDBC/upgrade/14_5/schedule @@ -341,3 +341,4 @@ BABEL-3474 datetime2fromparts timefromparts BABEL-3215 +BABEL-4078-before-14_8-or-15_3 diff --git a/test/JDBC/upgrade/14_6/schedule b/test/JDBC/upgrade/14_6/schedule index 2dc690061d..59b73e477b 100644 --- a/test/JDBC/upgrade/14_6/schedule +++ b/test/JDBC/upgrade/14_6/schedule @@ -368,3 +368,4 @@ dateadd_internal_df datetime2fromparts timefromparts BABEL-3215 +BABEL-4078-before-14_8-or-15_3 diff --git a/test/JDBC/upgrade/14_7/schedule b/test/JDBC/upgrade/14_7/schedule index cf1ded9dee..c7f8dacb52 100644 --- a/test/JDBC/upgrade/14_7/schedule +++ b/test/JDBC/upgrade/14_7/schedule @@ -399,3 +399,4 @@ dateadd_internal_df datetime2fromparts timefromparts BABEL-3215 +BABEL-4078-before-14_8-or-15_3 diff --git a/test/JDBC/upgrade/14_8/schedule b/test/JDBC/upgrade/14_8/schedule index 1582912acc..d72b44b58e 100644 --- a/test/JDBC/upgrade/14_8/schedule +++ b/test/JDBC/upgrade/14_8/schedule @@ -398,3 +398,4 @@ datetime2fromparts timefromparts orderby-before-15_3 BABEL-3215 +BABEL-4078-before-14_8-or-15_3 diff --git a/test/JDBC/upgrade/15_1/schedule b/test/JDBC/upgrade/15_1/schedule index 0772c69168..44e75219ef 100644 --- a/test/JDBC/upgrade/15_1/schedule +++ b/test/JDBC/upgrade/15_1/schedule @@ -378,3 +378,4 @@ datetime2fromparts timefromparts orderby-before-15_3 BABEL-3215 +BABEL-4078-before-14_8-or-15_3 diff --git a/test/JDBC/upgrade/15_2/schedule b/test/JDBC/upgrade/15_2/schedule index b0eeaa0175..eaa36477af 100644 --- a/test/JDBC/upgrade/15_2/schedule +++ b/test/JDBC/upgrade/15_2/schedule @@ -416,3 +416,4 @@ dateadd_internal_df datetime2fromparts timefromparts orderby-before-15_3 +BABEL-4078-before-14_8-or-15_3 diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index b6988e3248..0b6551375f 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -427,3 +427,4 @@ timefromparts orderby sys_sysusers_dep BABEL-3215 +BABEL-4078 From 0006671e9d9754f16b8ec7f71726d1c21860d081 Mon Sep 17 00:00:00 2001 From: Zhibai Date: Fri, 14 Apr 2023 09:26:00 -0700 Subject: [PATCH 060/363] fix the issue alter table with unique will crash (#1432) Previously alter table add unique will crash the instance due to not handle the node type properly in post analyzer. This commit fix this issue by properly handle indexElem in post analyzer. Task: BABEL-3823 Signed-off-by: Zhibai Song Co-authored-by: Zhibai Song --- contrib/babelfishpg_tsql/src/pl_handler.c | 13 +++- test/JDBC/expected/alter_table.out | 72 +++++++++++++++++++++++ test/JDBC/input/alter_table.sql | 46 +++++++++++++++ 3 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 test/JDBC/expected/alter_table.out create mode 100644 test/JDBC/input/alter_table.sql diff --git a/contrib/babelfishpg_tsql/src/pl_handler.c b/contrib/babelfishpg_tsql/src/pl_handler.c index c8d5cdb932..583c1ec7ae 100644 --- a/contrib/babelfishpg_tsql/src/pl_handler.c +++ b/contrib/babelfishpg_tsql/src/pl_handler.c @@ -1517,11 +1517,20 @@ is_nullable_constraint(Constraint *cst, Oid rel_oid) /* Loop through the constraint keys */ foreach(lc, cst->keys) { - String *strval = (String *) lfirst(lc); + Node *node = (Node *) lfirst(lc); + String *strval; const char *col_name = NULL; AttrNumber attnum = InvalidAttrNumber; - col_name = strVal(strval); + if (nodeTag(node) == T_IndexElem){ + col_name = ((IndexElem *)node)->name; + } + else + { + strval = (String *)node; + col_name = strVal(strval); + } + attnum = get_attnum(rel_oid, col_name); if (get_attnotnull(rel_oid, attnum)) diff --git a/test/JDBC/expected/alter_table.out b/test/JDBC/expected/alter_table.out new file mode 100644 index 0000000000..786f1934c4 --- /dev/null +++ b/test/JDBC/expected/alter_table.out @@ -0,0 +1,72 @@ + +create table trans2(id int identity(1,1) primary key, source int not null , target int not null, amount int ); +insert into TRANS2 (source, amount, a, c ) values (1,1,1) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "a" of relation "trans2" does not exist)~~ + + +ALTER TABLE trans2 ADD a int4 default 3; +GO + +ALTER TABLE trans2 ADD b varchar; +GO + +ALTER TABLE trans2 ADD c varchar(10) NOT null; +GO + +ALTER TABLE trans2 ADD c varchar(10) NOT null; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "c" of relation "trans2" already exists)~~ + + +ALTER TABLE trans2 ADD c varchar(30) not null default 'aaa'; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "c" of relation "trans2" already exists)~~ + + +ALTER TABLE trans2 WITH NOCHECK ADD CONSTRAINT exd_check CHECK (source > 1) ; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'ALTER TABLE WITH [NO]CHECK ADD' is not currently supported in Babelfish. please use babelfishpg_tsql.escape_hatch_nocheck_add_constraint to ignore)~~ + + +ALTER TABLE trans2 ADD CONSTRAINT col_b_def DEFAULT 50 FOR target ; +GO + +insert into TRANS2 (source, amount, a, c ) values (3,1,1,'ddd') +GO +~~ROW COUNT: 1~~ + + +ALTER TABLE trans2 ADD AddDate smalldatetime NULL CONSTRAINT AddDateDflt DEFAULT GETDATE() with values ; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'values' is not currently supported in Babelfish)~~ + + +ALTER TABLE trans2 ADD AddDate smalldatetime NULL CONSTRAINT AddDateDflt DEFAULT GETDATE() ; +GO + +alter table trans2 add unique (source asc); +GO + +insert into TRANS2 (source, amount, a, c ) values (3,1,1,'ddd') +GO +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "trans2_source_key")~~ + + +ALTER TABLE trans2 DROP COLUMN AddDate +GO + +drop table trans2 +GO diff --git a/test/JDBC/input/alter_table.sql b/test/JDBC/input/alter_table.sql new file mode 100644 index 0000000000..8b97d57b32 --- /dev/null +++ b/test/JDBC/input/alter_table.sql @@ -0,0 +1,46 @@ +create table trans2(id int identity(1,1) primary key, source int not null , target int not null, amount int ); + +insert into TRANS2 (source, amount, a, c ) values (1,1,1) +GO + +ALTER TABLE trans2 ADD a int4 default 3; +GO + +ALTER TABLE trans2 ADD b varchar; +GO + +ALTER TABLE trans2 ADD c varchar(10) NOT null; +GO + +ALTER TABLE trans2 ADD c varchar(10) NOT null; +GO + +ALTER TABLE trans2 ADD c varchar(30) not null default 'aaa'; +go + +ALTER TABLE trans2 WITH NOCHECK ADD CONSTRAINT exd_check CHECK (source > 1) ; +GO + +ALTER TABLE trans2 ADD CONSTRAINT col_b_def DEFAULT 50 FOR target ; +GO + +insert into TRANS2 (source, amount, a, c ) values (3,1,1,'ddd') +GO + +ALTER TABLE trans2 ADD AddDate smalldatetime NULL CONSTRAINT AddDateDflt DEFAULT GETDATE() with values ; +GO + +ALTER TABLE trans2 ADD AddDate smalldatetime NULL CONSTRAINT AddDateDflt DEFAULT GETDATE() ; +GO + +alter table trans2 add unique (source asc); +GO + +insert into TRANS2 (source, amount, a, c ) values (3,1,1,'ddd') +GO + +ALTER TABLE trans2 DROP COLUMN AddDate +GO + +drop table trans2 +GO \ No newline at end of file From 5aec2121b89c310fb4d3cc3e9c6215be432910c1 Mon Sep 17 00:00:00 2001 From: pratikzode <73869399+pratikzode@users.noreply.github.com> Date: Fri, 14 Apr 2023 10:16:46 -0700 Subject: [PATCH 061/363] Support DATABASE_PRINCIPAL_ID() T-SQL function (#1429) Add dependency test for user_id, and add it to all upgrade schedules Task: BABEL-1199 Signed-off-by: pratikzode --- contrib/babelfishpg_tsql/src/rolecmds.c | 2 +- .../expected/sys-userid-dep-vu-cleanup.out | 11 +++++ .../expected/sys-userid-dep-vu-prepare.out | 21 ++++++++++ .../expected/sys-userid-dep-vu-verify.out | 40 +++++++++++++++++++ .../functions/sys-userid-dep-vu-cleanup.sql | 11 +++++ .../functions/sys-userid-dep-vu-prepare.sql | 21 ++++++++++ .../functions/sys-userid-dep-vu-verify.sql | 15 +++++++ test/JDBC/upgrade/13_4/schedule | 1 + test/JDBC/upgrade/13_5/schedule | 1 + test/JDBC/upgrade/13_6/schedule | 1 + test/JDBC/upgrade/13_7/schedule | 1 + test/JDBC/upgrade/13_8/schedule | 1 + test/JDBC/upgrade/13_9/schedule | 1 + test/JDBC/upgrade/14_3/schedule | 1 + test/JDBC/upgrade/14_5/schedule | 1 + test/JDBC/upgrade/14_6/schedule | 1 + test/JDBC/upgrade/14_7/schedule | 1 + test/JDBC/upgrade/14_8/schedule | 1 + test/JDBC/upgrade/15_1/schedule | 1 + test/JDBC/upgrade/15_2/schedule | 1 + 20 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 test/JDBC/expected/sys-userid-dep-vu-cleanup.out create mode 100644 test/JDBC/expected/sys-userid-dep-vu-prepare.out create mode 100644 test/JDBC/expected/sys-userid-dep-vu-verify.out create mode 100644 test/JDBC/input/functions/sys-userid-dep-vu-cleanup.sql create mode 100644 test/JDBC/input/functions/sys-userid-dep-vu-prepare.sql create mode 100644 test/JDBC/input/functions/sys-userid-dep-vu-verify.sql diff --git a/contrib/babelfishpg_tsql/src/rolecmds.c b/contrib/babelfishpg_tsql/src/rolecmds.c index 18032b9e4a..393c212a71 100644 --- a/contrib/babelfishpg_tsql/src/rolecmds.c +++ b/contrib/babelfishpg_tsql/src/rolecmds.c @@ -720,7 +720,7 @@ user_id(PG_FUNCTION_ARGS) Oid ret; size_t len; - user_input = text_to_cstring(PG_GETARG_TEXT_PP(0)); + user_input = PG_ARGISNULL(0) ? NULL : text_to_cstring(PG_GETARG_TEXT_PP(0)); db_name = get_cur_db_name(); if (!db_name) diff --git a/test/JDBC/expected/sys-userid-dep-vu-cleanup.out b/test/JDBC/expected/sys-userid-dep-vu-cleanup.out new file mode 100644 index 0000000000..4dfc6a1d95 --- /dev/null +++ b/test/JDBC/expected/sys-userid-dep-vu-cleanup.out @@ -0,0 +1,11 @@ +DROP VIEW current_user_id_v1; +GO + +DROP PROCEDURE current_user_id_p1; +GO + +DROP VIEW current_user_id_v2; +GO + +DROP PROCEDURE current_user_id_p2; +GO diff --git a/test/JDBC/expected/sys-userid-dep-vu-prepare.out b/test/JDBC/expected/sys-userid-dep-vu-prepare.out new file mode 100644 index 0000000000..15a49e90c0 --- /dev/null +++ b/test/JDBC/expected/sys-userid-dep-vu-prepare.out @@ -0,0 +1,21 @@ +CREATE VIEW dbo.current_user_id_v1 AS +SELECT user_name(user_id()); +GO + +CREATE PROCEDURE dbo.current_user_id_p1 +AS +BEGIN + SELECT user_name(user_id()); +END; +GO + +CREATE VIEW dbo.current_user_id_v2 AS +SELECT user_name(user_id('dbo')); +GO + +CREATE PROCEDURE dbo.current_user_id_p2 +AS +BEGIN + SELECT user_name(user_id('dbo')); +END; +GO diff --git a/test/JDBC/expected/sys-userid-dep-vu-verify.out b/test/JDBC/expected/sys-userid-dep-vu-verify.out new file mode 100644 index 0000000000..2779cc9eec --- /dev/null +++ b/test/JDBC/expected/sys-userid-dep-vu-verify.out @@ -0,0 +1,40 @@ +SELECT * FROM current_user_id_v1; +GO +~~START~~ +nvarchar +dbo +~~END~~ + + +EXEC current_user_id_p1; +GO +~~START~~ +nvarchar +dbo +~~END~~ + + + +SELECT * FROM current_user_id_v2; +GO +~~START~~ +nvarchar +dbo +~~END~~ + + +EXEC current_user_id_p2; +GO +~~START~~ +nvarchar +dbo +~~END~~ + + +SELECT user_name(user_id()); +GO +~~START~~ +nvarchar +dbo +~~END~~ + diff --git a/test/JDBC/input/functions/sys-userid-dep-vu-cleanup.sql b/test/JDBC/input/functions/sys-userid-dep-vu-cleanup.sql new file mode 100644 index 0000000000..4dfc6a1d95 --- /dev/null +++ b/test/JDBC/input/functions/sys-userid-dep-vu-cleanup.sql @@ -0,0 +1,11 @@ +DROP VIEW current_user_id_v1; +GO + +DROP PROCEDURE current_user_id_p1; +GO + +DROP VIEW current_user_id_v2; +GO + +DROP PROCEDURE current_user_id_p2; +GO diff --git a/test/JDBC/input/functions/sys-userid-dep-vu-prepare.sql b/test/JDBC/input/functions/sys-userid-dep-vu-prepare.sql new file mode 100644 index 0000000000..016d439d0f --- /dev/null +++ b/test/JDBC/input/functions/sys-userid-dep-vu-prepare.sql @@ -0,0 +1,21 @@ +CREATE VIEW dbo.current_user_id_v1 AS +SELECT user_name(user_id()); +GO + +CREATE PROCEDURE dbo.current_user_id_p1 +AS +BEGIN + SELECT user_name(user_id()); +END; +GO + +CREATE VIEW dbo.current_user_id_v2 AS +SELECT user_name(user_id('dbo')); +GO + +CREATE PROCEDURE dbo.current_user_id_p2 +AS +BEGIN + SELECT user_name(user_id('dbo')); +END; +GO \ No newline at end of file diff --git a/test/JDBC/input/functions/sys-userid-dep-vu-verify.sql b/test/JDBC/input/functions/sys-userid-dep-vu-verify.sql new file mode 100644 index 0000000000..e54d4b534c --- /dev/null +++ b/test/JDBC/input/functions/sys-userid-dep-vu-verify.sql @@ -0,0 +1,15 @@ +SELECT * FROM current_user_id_v1; +GO + +EXEC current_user_id_p1; +GO + + +SELECT * FROM current_user_id_v2; +GO + +EXEC current_user_id_p2; +GO + +SELECT user_name(user_id()); +GO \ No newline at end of file diff --git a/test/JDBC/upgrade/13_4/schedule b/test/JDBC/upgrade/13_4/schedule index 97822bc322..821e85d40e 100644 --- a/test/JDBC/upgrade/13_4/schedule +++ b/test/JDBC/upgrade/13_4/schedule @@ -158,6 +158,7 @@ sys-indexes sys-table_types sys_all_objects sys-system_objects-for-13-x +sys-userid-dep BABEL-1683 schema_resolution_trigger sys-sp_pkeys diff --git a/test/JDBC/upgrade/13_5/schedule b/test/JDBC/upgrade/13_5/schedule index dc2795f16f..04ce5a278f 100644 --- a/test/JDBC/upgrade/13_5/schedule +++ b/test/JDBC/upgrade/13_5/schedule @@ -158,6 +158,7 @@ BABEL-1465 BABEL-1466 BABEL-1715 BABEL-2086 +sys-userid-dep BABEL-3314 BABEL-TABLEOPTIONS temp-tables diff --git a/test/JDBC/upgrade/13_6/schedule b/test/JDBC/upgrade/13_6/schedule index b68ff8dcbd..66d06fbd3d 100644 --- a/test/JDBC/upgrade/13_6/schedule +++ b/test/JDBC/upgrade/13_6/schedule @@ -270,6 +270,7 @@ sys-table_types-dep sys-sp_pkeys-dep sys-sp_statistics-dep sys-proc_param_helper-dep +sys-userid-dep BABEL-SPCOLUMNS-dep BABEL-SP_COLUMNS_MANAGED-dep BABEL-SP_SPECIAL_COLUMNS-dep diff --git a/test/JDBC/upgrade/13_7/schedule b/test/JDBC/upgrade/13_7/schedule index f84e5f7502..706eeec068 100644 --- a/test/JDBC/upgrade/13_7/schedule +++ b/test/JDBC/upgrade/13_7/schedule @@ -269,6 +269,7 @@ sys-table_types-dep sys-sp_pkeys-dep sys-sp_statistics-dep sys-proc_param_helper-dep +sys-userid-dep BABEL-SPCOLUMNS-dep BABEL-SP_COLUMNS_MANAGED-dep BABEL-SP_SPECIAL_COLUMNS-dep diff --git a/test/JDBC/upgrade/13_8/schedule b/test/JDBC/upgrade/13_8/schedule index f84e5f7502..706eeec068 100644 --- a/test/JDBC/upgrade/13_8/schedule +++ b/test/JDBC/upgrade/13_8/schedule @@ -269,6 +269,7 @@ sys-table_types-dep sys-sp_pkeys-dep sys-sp_statistics-dep sys-proc_param_helper-dep +sys-userid-dep BABEL-SPCOLUMNS-dep BABEL-SP_COLUMNS_MANAGED-dep BABEL-SP_SPECIAL_COLUMNS-dep diff --git a/test/JDBC/upgrade/13_9/schedule b/test/JDBC/upgrade/13_9/schedule index 00e29b74d7..f12b7d8914 100644 --- a/test/JDBC/upgrade/13_9/schedule +++ b/test/JDBC/upgrade/13_9/schedule @@ -266,6 +266,7 @@ sys-table_types-dep sys-sp_pkeys-dep sys-sp_statistics-dep sys-proc_param_helper-dep +sys-userid-dep BABEL-SPCOLUMNS-dep BABEL-SP_COLUMNS_MANAGED-dep BABEL-SP_SPECIAL_COLUMNS-dep diff --git a/test/JDBC/upgrade/14_3/schedule b/test/JDBC/upgrade/14_3/schedule index d62ff431c6..c4ad2656ee 100644 --- a/test/JDBC/upgrade/14_3/schedule +++ b/test/JDBC/upgrade/14_3/schedule @@ -274,6 +274,7 @@ sys-sql_modules-dep sys-sp_pkeys-dep sys-sp_statistics-dep sys-proc_param_helper-dep +sys-userid-dep BABEL-1756-dep BABEL-SP_COLUMNS_MANAGED-dep BABEL-SP_SPECIAL_COLUMNS-dep diff --git a/test/JDBC/upgrade/14_5/schedule b/test/JDBC/upgrade/14_5/schedule index 2e65ad5d5b..6236da993d 100644 --- a/test/JDBC/upgrade/14_5/schedule +++ b/test/JDBC/upgrade/14_5/schedule @@ -290,6 +290,7 @@ sys-views sys-xml_indexes sys-xml_schema_collections sys_all_objects +sys-userid-dep BABEL-1249 BABEL-1291 BABEL-1994-CHAR diff --git a/test/JDBC/upgrade/14_6/schedule b/test/JDBC/upgrade/14_6/schedule index 59b73e477b..cf45192a70 100644 --- a/test/JDBC/upgrade/14_6/schedule +++ b/test/JDBC/upgrade/14_6/schedule @@ -234,6 +234,7 @@ sys-system_sql_modules-dep sys-triggers-dep sys-sp_pkeys sys-sp_statistics +sys-userid-dep BABEL-APPLOCK BABEL-1438 BABEL-SP_DATATYPE_INFO diff --git a/test/JDBC/upgrade/14_7/schedule b/test/JDBC/upgrade/14_7/schedule index c7f8dacb52..f7af33a97b 100644 --- a/test/JDBC/upgrade/14_7/schedule +++ b/test/JDBC/upgrade/14_7/schedule @@ -328,6 +328,7 @@ sys-xml_indexes sys-xml_schema_collections sys_all_objects sys_babelfish_configurations_view +sys-userid-dep BABEL-1249 BABEL-1291 BABEL-1994-CHAR diff --git a/test/JDBC/upgrade/14_8/schedule b/test/JDBC/upgrade/14_8/schedule index d72b44b58e..0bf96dc978 100644 --- a/test/JDBC/upgrade/14_8/schedule +++ b/test/JDBC/upgrade/14_8/schedule @@ -244,6 +244,7 @@ sys-triggers-dep sys-proc_param_helper-dep sys-sp_pkeys sys-sp_statistics +sys-userid-dep BABEL-APPLOCK BABEL-1438 BABEL-SP_DATATYPE_INFO diff --git a/test/JDBC/upgrade/15_1/schedule b/test/JDBC/upgrade/15_1/schedule index 44e75219ef..98bb8f8298 100644 --- a/test/JDBC/upgrade/15_1/schedule +++ b/test/JDBC/upgrade/15_1/schedule @@ -201,6 +201,7 @@ sys-hash_indexes sys-plan_guides sp_tablecollations sys-assemblies +sys-userid-dep BABEL-LOGIN-USER-EXT bitwise_not-operator BABEL-1683 diff --git a/test/JDBC/upgrade/15_2/schedule b/test/JDBC/upgrade/15_2/schedule index eaa36477af..0ebaafc06d 100644 --- a/test/JDBC/upgrade/15_2/schedule +++ b/test/JDBC/upgrade/15_2/schedule @@ -208,6 +208,7 @@ sys-hash_indexes sys-plan_guides sp_tablecollations sys-assemblies +sys-userid-dep BABEL-LOGIN-USER-EXT bitwise_not-operator BABEL-1683 From 0d22a066acaf13186044951c5095d24184cb0bf3 Mon Sep 17 00:00:00 2001 From: Sumit Jaiswal <54075285+sumitj824@users.noreply.github.com> Date: Mon, 17 Apr 2023 11:52:39 +0530 Subject: [PATCH 062/363] Fix testfile name in 14_8 schedule file (#1438) We were getting upgrade failure when source version is 14_8 because test which was not suppose to run was running for that upgrade. This commit update test name in 14_8 upgrade schedule file. Signed-off-by: Sumit Jaiswal --- test/JDBC/upgrade/14_8/schedule | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/JDBC/upgrade/14_8/schedule b/test/JDBC/upgrade/14_8/schedule index 0bf96dc978..2db3ce7b69 100644 --- a/test/JDBC/upgrade/14_8/schedule +++ b/test/JDBC/upgrade/14_8/schedule @@ -399,4 +399,4 @@ datetime2fromparts timefromparts orderby-before-15_3 BABEL-3215 -BABEL-4078-before-14_8-or-15_3 +BABEL-4078 From 328e16510ec1aeab24e83c9764e896d4fedc0921 Mon Sep 17 00:00:00 2001 From: Shlok Kumar Kyal <68871659+skkyal@users.noreply.github.com> Date: Mon, 17 Apr 2023 19:01:15 +0530 Subject: [PATCH 063/363] Fix crash in ExecuteBulkCopy (#1439) In BulkCopy a new variable rel is created for each batch but for the case of implicit batching, the old value of rel is being used inside cstate->rel (set during the first batch). With this change we have made the change to set cstate->rel to new value of rel for each batch. authored-by: Shlok Kumar Kyal (skkyal@amazon.com) Signed-off-by: Kushaal Shroff (kushaal@amazon.com) --- contrib/babelfishpg_tsql/src/pltsql_bulkcopy.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contrib/babelfishpg_tsql/src/pltsql_bulkcopy.c b/contrib/babelfishpg_tsql/src/pltsql_bulkcopy.c index 29ab19b7ef..3342e120a8 100644 --- a/contrib/babelfishpg_tsql/src/pltsql_bulkcopy.c +++ b/contrib/babelfishpg_tsql/src/pltsql_bulkcopy.c @@ -102,6 +102,8 @@ BulkCopy(BulkCopyStmt *stmt, uint64 *processed) { if (!stmt->cstate) stmt->cstate = BeginBulkCopy(rel, attnums); + else + stmt->cstate->rel = rel; *processed = ExecuteBulkCopy(stmt->cstate, stmt->nrow, stmt->ncol, stmt->Values, stmt->Nulls); stmt->rows_processed += *processed; From 08d0df1e9dad41dfd0e522f717a0c895b4c6e55e Mon Sep 17 00:00:00 2001 From: "Ray\" DongHo Kim" <112982631+raydhkim@users.noreply.github.com> Date: Mon, 17 Apr 2023 14:56:57 -0700 Subject: [PATCH 064/363] Support sp_rename for additional OBJECT type (TRIGGER, TABLE_TYPE) (#1431) Previously, TRIGGER and TABLE_TYPE were not supported for sp_rename procedure. Now, these two subtypes are included in OBJECT objtype of sp_rename, allowing users to rename TRIGGER and TABLE_TYPE objects using sp_rename. Task: BABEL-3965 Signed-off-by: Ray Kim --- .../babelfishpg_tsql/sql/babelfishpg_tsql.sql | 33 ++- .../babelfishpg_tsql--3.1.0--3.2.0.sql | 33 ++- contrib/babelfishpg_tsql/src/catalog.c | 46 +++-- contrib/babelfishpg_tsql/src/procedures.c | 46 ++++- .../expected/Test-sp_rename-vu-cleanup.out | 6 + .../expected/Test-sp_rename-vu-prepare.out | 13 +- .../expected/Test-sp_rename-vu-verify.out | 191 +++++++++++++++--- .../Test-sp_rename-vu-cleanup.sql | 6 + .../Test-sp_rename-vu-prepare.sql | 13 +- .../Test-sp_rename-vu-verify.sql | 82 ++++++-- 10 files changed, 391 insertions(+), 78 deletions(-) diff --git a/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql index 2b032c0500..20c4d4b764 100644 --- a/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql +++ b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql @@ -3081,18 +3081,43 @@ BEGIN ELSE IF @objtype = 'OBJECT' BEGIN DECLARE @count INT; - SELECT @count = COUNT(*) FROM sys.objects o1 INNER JOIN sys.schemas s1 ON o1.schema_id = s1.schema_id + SELECT type INTO #tempTable FROM sys.objects o1 INNER JOIN sys.schemas s1 ON o1.schema_id = s1.schema_id WHERE s1.name = @schemaname AND o1.name = @subname; + SELECT @count = COUNT(*) FROM #tempTable; + IF @count > 1 BEGIN THROW 33557097, N'There are multiple objects with the given @objname.', 1; END IF @count < 1 BEGIN - THROW 33557097, N'There is no object with the given @objname.', 1; + -- TABLE TYPE: check if there is a match in sys.table_types (if we cannot alter sys.objects table_type naming) + SELECT @count = COUNT(*) FROM sys.table_types tt1 INNER JOIN sys.schemas s1 ON tt1.schema_id = s1.schema_id + WHERE s1.name = @schemaname AND tt1.name = @subname; + IF @count > 1 + BEGIN + THROW 33557097, N'There are multiple objects with the given @objname.', 1; + END + ELSE IF @count < 1 + BEGIN + THROW 33557097, N'There is no object with the given @objname.', 1; + END + ELSE + BEGIN + SET @currtype = 'TT' + END + END + IF @currtype IS NULL + BEGIN + SELECT @currtype = type from #tempTable; + END + IF @currtype = 'TR' OR @currtype = 'TA' + BEGIN + DECLARE @physical_schema_name sys.nvarchar(776) = ''; + SELECT @physical_schema_name = nspname FROM sys.babelfish_namespace_ext WHERE dbid = cast(sys.db_id() as oid) AND orig_name = @schemaname; + SELECT @curr_relname = relname FROM pg_catalog.pg_trigger tr LEFT JOIN pg_catalog.pg_class c ON tr.tgrelid = c.oid LEFT JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid + WHERE tr.tgname = @subname AND n.nspname = @physical_schema_name; END - SELECT @currtype = type FROM sys.objects o1 INNER JOIN sys.schemas s1 ON o1.schema_id = s1.schema_id - WHERE s1.name = @schemaname AND o1.name = @subname; END ELSE BEGIN diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql index a13248b74b..183848427c 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql @@ -1785,18 +1785,43 @@ BEGIN ELSE IF @objtype = 'OBJECT' BEGIN DECLARE @count INT; - SELECT @count = COUNT(*) FROM sys.objects o1 INNER JOIN sys.schemas s1 ON o1.schema_id = s1.schema_id + SELECT type INTO #tempTable FROM sys.objects o1 INNER JOIN sys.schemas s1 ON o1.schema_id = s1.schema_id WHERE s1.name = @schemaname AND o1.name = @subname; + SELECT @count = COUNT(*) FROM #tempTable; + IF @count > 1 BEGIN THROW 33557097, N'There are multiple objects with the given @objname.', 1; END IF @count < 1 BEGIN - THROW 33557097, N'There is no object with the given @objname.', 1; + -- TABLE TYPE: check if there is a match in sys.table_types (if we cannot alter sys.objects table_type naming) + SELECT @count = COUNT(*) FROM sys.table_types tt1 INNER JOIN sys.schemas s1 ON tt1.schema_id = s1.schema_id + WHERE s1.name = @schemaname AND tt1.name = @subname; + IF @count > 1 + BEGIN + THROW 33557097, N'There are multiple objects with the given @objname.', 1; + END + ELSE IF @count < 1 + BEGIN + THROW 33557097, N'There is no object with the given @objname.', 1; + END + ELSE + BEGIN + SET @currtype = 'TT' + END + END + IF @currtype IS NULL + BEGIN + SELECT @currtype = type from #tempTable; + END + IF @currtype = 'TR' OR @currtype = 'TA' + BEGIN + DECLARE @physical_schema_name sys.nvarchar(776) = ''; + SELECT @physical_schema_name = nspname FROM sys.babelfish_namespace_ext WHERE dbid = cast(sys.db_id() as oid) AND orig_name = @schemaname; + SELECT @curr_relname = relname FROM pg_catalog.pg_trigger tr LEFT JOIN pg_catalog.pg_class c ON tr.tgrelid = c.oid LEFT JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid + WHERE tr.tgname = @subname AND n.nspname = @physical_schema_name; END - SELECT @currtype = type FROM sys.objects o1 INNER JOIN sys.schemas s1 ON o1.schema_id = s1.schema_id - WHERE s1.name = @schemaname AND o1.name = @subname; END ELSE BEGIN diff --git a/contrib/babelfishpg_tsql/src/catalog.c b/contrib/babelfishpg_tsql/src/catalog.c index ad3a98d021..03537cc0d4 100644 --- a/contrib/babelfishpg_tsql/src/catalog.c +++ b/contrib/babelfishpg_tsql/src/catalog.c @@ -2419,6 +2419,10 @@ rename_update_bbf_catalog(RenameStmt *stmt) break; case OBJECT_SEQUENCE: break; + case OBJECT_TRIGGER: + break; + case OBJECT_TYPE: + break; case OBJECT_COLUMN: break; default: @@ -2436,17 +2440,12 @@ rename_view_update_bbf_catalog(RenameStmt *stmt) HeapTuple usertuple; HeapTuple new_tuple; TableScanDesc tblscan; - Datum new_record_view_def[BBF_VIEW_DEF_NUM_COLS]; - bool new_record_nulls_view_def[BBF_VIEW_DEF_NUM_COLS]; - bool new_record_repl_view_def[BBF_VIEW_DEF_NUM_COLS]; + Datum new_record_view_def[BBF_VIEW_DEF_NUM_COLS] = {0}; + bool new_record_nulls_view_def[BBF_VIEW_DEF_NUM_COLS] = {false}; + bool new_record_repl_view_def[BBF_VIEW_DEF_NUM_COLS] = {false}; int16 dbid; const char *logical_schema_name; - /* build the tuple to insert */ - MemSet(new_record_view_def, 0, sizeof(new_record_view_def)); - MemSet(new_record_nulls_view_def, false, sizeof(new_record_nulls_view_def)); - MemSet(new_record_repl_view_def, false, sizeof(new_record_repl_view_def)); - /* open the catalog table */ bbf_view_def_rel = table_open(get_bbf_view_def_oid(), RowExclusiveLock); @@ -2516,24 +2515,19 @@ rename_procfunc_update_bbf_catalog(RenameStmt *stmt) HeapTuple sec_tuple; HeapTuple new_tuple; TableScanDesc tblscan; - Datum new_record_func_ext[BBF_FUNCTION_EXT_NUM_COLS]; - bool new_record_nulls_func_ext[BBF_FUNCTION_EXT_NUM_COLS]; - bool new_record_repl_func_ext[BBF_FUNCTION_EXT_NUM_COLS]; + Datum new_record_func_ext[BBF_FUNCTION_EXT_NUM_COLS] = {0}; + bool new_record_nulls_func_ext[BBF_FUNCTION_EXT_NUM_COLS] = {false}; + bool new_record_repl_func_ext[BBF_FUNCTION_EXT_NUM_COLS] = {false}; NameData *objname_data; NameData *schemaname_data; bool is_null; - char *funcsign, - *new_funcsign; + char *funcsign; + StringInfoData new_funcsign; Datum funcsign_datum; Node *schema; char *schemaname; ObjectWithArgs *objwargs = (ObjectWithArgs *) stmt->object; - /* build the tuple to insert */ - MemSet(new_record_func_ext, 0, sizeof(new_record_func_ext)); - MemSet(new_record_nulls_func_ext, false, sizeof(new_record_nulls_func_ext)); - MemSet(new_record_repl_func_ext, false, sizeof(new_record_repl_func_ext)); - /* open the catalog table */ bbf_func_ext_rel = table_open(get_bbf_function_ext_oid(), RowExclusiveLock); @@ -2576,14 +2570,20 @@ rename_procfunc_update_bbf_catalog(RenameStmt *stmt) funcsign_datum = heap_getattr(usertuple, Anum_bbf_function_ext_funcsignature, bbf_func_ext_rel->rd_att, &is_null); funcsign = pstrdup(TextDatumGetCString(funcsign_datum)); - new_funcsign = strcat(pstrdup(stmt->newname), strrchr(funcsign, '(')); + /* get new funcsignature */ + initStringInfo(&new_funcsign); + appendStringInfoString(&new_funcsign, stmt->newname); + appendStringInfoString(&new_funcsign, strrchr(funcsign, '(')); new_record_func_ext[Anum_bbf_function_ext_funcname - 1] = CStringGetDatum(stmt->newname); - new_record_func_ext[Anum_bbf_function_ext_orig_name - 1] = CStringGetTextDatum(orig_proc_funcname); - new_record_func_ext[Anum_bbf_function_ext_funcsignature - 1] = CStringGetTextDatum(new_funcsign); + new_record_func_ext[Anum_bbf_function_ext_funcsignature - 1] = CStringGetTextDatum(new_funcsign.data); new_record_repl_func_ext[Anum_bbf_function_ext_funcname - 1] = true; - new_record_repl_func_ext[Anum_bbf_function_ext_orig_name - 1] = true; new_record_repl_func_ext[Anum_bbf_function_ext_funcsignature - 1] = true; + if (orig_proc_funcname != NULL) + { + new_record_func_ext[Anum_bbf_function_ext_orig_name - 1] = CStringGetTextDatum(orig_proc_funcname); + new_record_repl_func_ext[Anum_bbf_function_ext_orig_name - 1] = true; + } new_tuple = heap_modify_tuple(usertuple, bbf_func_ext_dsc, @@ -2595,6 +2595,7 @@ rename_procfunc_update_bbf_catalog(RenameStmt *stmt) sec_tuple = heap_getnext(tblscan, ForwardScanDirection); if (HeapTupleIsValid(sec_tuple)) { + orig_proc_funcname = NULL; table_endscan(tblscan); table_close(bbf_func_ext_rel, RowExclusiveLock); ereport(ERROR, @@ -2604,6 +2605,7 @@ rename_procfunc_update_bbf_catalog(RenameStmt *stmt) CatalogTupleUpdate(bbf_func_ext_rel, &new_tuple->t_self, new_tuple); + orig_proc_funcname = NULL; heap_freetuple(new_tuple); table_endscan(tblscan); diff --git a/contrib/babelfishpg_tsql/src/procedures.c b/contrib/babelfishpg_tsql/src/procedures.c index b0aeab0ec2..9ed5dd6f7a 100644 --- a/contrib/babelfishpg_tsql/src/procedures.c +++ b/contrib/babelfishpg_tsql/src/procedures.c @@ -2961,8 +2961,8 @@ sp_rename_internal(PG_FUNCTION_ARGS) else if (strcmp(objtype, "TA") == 0 || strcmp(objtype, "TR") == 0) { /* TRIGGER */ - ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Feature not supported: renaming object type Trigger"))); + objtype_code = OBJECT_TRIGGER; + process_util_querystr = "(ALTER TRIGGER )"; } else if (strcmp(objtype, "C") == 0 || strcmp(objtype, "D") == 0 || strcmp(objtype, "PK") == 0 || strcmp(objtype, "UQ") == 0 || strcmp(objtype, "EC") == 0) @@ -2974,8 +2974,8 @@ sp_rename_internal(PG_FUNCTION_ARGS) else if (strcmp(objtype, "TT") == 0) { /* TABLE TYPE */ - ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Feature not supported: renaming object type Table-Type"))); + objtype_code = OBJECT_TYPE; + process_util_querystr = "(ALTER TABLE )"; } else if (strcmp(objtype, "CO") == 0) { @@ -3069,6 +3069,13 @@ gen_sp_rename_subcmds(const char *objname, const char *newname, const char *sche case OBJECT_SEQUENCE: appendStringInfo(&query, "ALTER SEQUENCE dummy RENAME TO dummy; "); break; + case OBJECT_TRIGGER: + appendStringInfo(&query, "ALTER TRIGGER dummy ON dummy RENAME TO dummy; "); + appendStringInfo(&query, "ALTER FUNCTION dummy RENAME TO dummy; "); + break; + case OBJECT_TYPE: + appendStringInfo(&query, "ALTER TABLE dummy RENAME TO dummy; "); + break; case OBJECT_COLUMN: appendStringInfo(&query, "ALTER TABLE dummy RENAME COLUMN dummy TO dummy; "); appendStringInfo(&query, "ALTER TABLE dummy ALTER COLUMN dummy SET (dummy = 'dummy'); "); @@ -3081,7 +3088,7 @@ gen_sp_rename_subcmds(const char *objname, const char *newname, const char *sche } res = raw_parser(query.data, RAW_PARSE_DEFAULT); - if ((objtype != OBJECT_COLUMN) && (list_length(res) != 1)) + if ((objtype != OBJECT_COLUMN) && (objtype != OBJECT_TRIGGER) && (list_length(res) != 1)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("Expected 1 statement but get %d statements after parsing", list_length(res)))); @@ -3110,6 +3117,35 @@ gen_sp_rename_subcmds(const char *objname, const char *newname, const char *sche renamestmt->subname = pstrdup(lowerstr(objname)); renamestmt->newname = pstrdup(lowerstr(newname)); } + else if ((objtype == OBJECT_TRIGGER)) + { + ObjectWithArgs *objwargs; + renamestmt->renameType = objtype; + renamestmt->relation->schemaname = pstrdup(lowerstr(schemaname)); + renamestmt->relation->relname = pstrdup(lowerstr(curr_relname)); + renamestmt->subname = pstrdup(lowerstr(objname)); + renamestmt->newname = pstrdup(lowerstr(newname)); + rewrite_object_refs(stmt); + + // extra query nodes for ALTER FUNCTION + stmt = parsetree_nth_stmt(res, 1); + renamestmt = (RenameStmt *) stmt; + if (!IsA(renamestmt, RenameStmt)) + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("query is not a RenameStmt"))); + objwargs = (ObjectWithArgs *) renamestmt->object; + renamestmt->renameType = OBJECT_FUNCTION; + objwargs->objname = list_make2(makeString(pstrdup(lowerstr(schemaname))), makeString(pstrdup(lowerstr(objname)))); + renamestmt->subname = pstrdup(lowerstr(objname)); + renamestmt->newname = pstrdup(lowerstr(newname)); + } + else if ((objtype == OBJECT_TYPE)) + { + renamestmt->renameType = OBJECT_TABLE; + renamestmt->subname = pstrdup(lowerstr(objname)); + renamestmt->newname = pstrdup(lowerstr(newname)); + renamestmt->relation->schemaname = pstrdup(lowerstr(schemaname)); + renamestmt->relation->relname = pstrdup(lowerstr(objname)); + } else { /* COLUMN */ diff --git a/test/JDBC/expected/Test-sp_rename-vu-cleanup.out b/test/JDBC/expected/Test-sp_rename-vu-cleanup.out index 09fcb264a4..ed558f3eaf 100644 --- a/test/JDBC/expected/Test-sp_rename-vu-cleanup.out +++ b/test/JDBC/expected/Test-sp_rename-vu-cleanup.out @@ -44,5 +44,11 @@ GO DROP SEQUENCE sp_rename_vu_schema1.sp_rename_vu_seq1_new2; GO +DROP TYPE sp_rename_vu_tabletype1_new; +GO + +DROP TYPE sp_rename_vu_schema1.sp_rename_vu_tabletype1_schema1_new; +GO + DROP SCHEMA sp_rename_vu_schema1; GO diff --git a/test/JDBC/expected/Test-sp_rename-vu-prepare.out b/test/JDBC/expected/Test-sp_rename-vu-prepare.out index 76d2534da3..142be26384 100644 --- a/test/JDBC/expected/Test-sp_rename-vu-prepare.out +++ b/test/JDBC/expected/Test-sp_rename-vu-prepare.out @@ -72,7 +72,14 @@ START WITH 1 INCREMENT BY 1; GO -CREATE TRIGGER sp_rename_vu_trig1 ON sp_rename_vu_table2 -AFTER INSERT, UPDATE AS -RAISERROR ('Testing sp_rename', 16, 10); +CREATE TRIGGER sp_rename_vu_trig1 ON sp_rename_vu_table2 AFTER INSERT, UPDATE AS RAISERROR ('Testing sp_rename trigger', 16, 10); +GO + +CREATE TRIGGER sp_rename_vu_schema1.sp_rename_vu_trig1 ON sp_rename_vu_schema1.sp_rename_vu_table2 AFTER INSERT, UPDATE AS RAISERROR ('Testing sp_rename trigger', 16, 10); +GO + +CREATE TYPE sp_rename_vu_tabletype1 AS TABLE(a int); +GO + +CREATE TYPE sp_rename_vu_schema1.sp_rename_vu_tabletype1 AS TABLE(a int); GO diff --git a/test/JDBC/expected/Test-sp_rename-vu-verify.out b/test/JDBC/expected/Test-sp_rename-vu-verify.out index e16e97e5dd..8a06784712 100644 --- a/test/JDBC/expected/Test-sp_rename-vu-verify.out +++ b/test/JDBC/expected/Test-sp_rename-vu-verify.out @@ -11,9 +11,11 @@ GO nvarchar#!#nvarchar#!#varchar#!#varchar master#!#dbo#!#sp_rename_vu_table1#!#BASE TABLE master#!#dbo#!#sp_rename_vu_table2#!#BASE TABLE +master#!#dbo#!#sp_rename_vu_tabletype1#!#BASE TABLE master#!#dbo#!#sp_rename_vu_view1#!#VIEW master#!#sp_rename_vu_schema1#!#sp_rename_vu_table1#!#BASE TABLE master#!#sp_rename_vu_schema1#!#sp_rename_vu_table2#!#BASE TABLE +master#!#sp_rename_vu_schema1#!#sp_rename_vu_tabletype1#!#BASE TABLE master#!#sp_rename_vu_schema1#!#sp_rename_vu_view1#!#VIEW ~~END~~ @@ -48,9 +50,11 @@ GO nvarchar#!#nvarchar#!#varchar#!#varchar master#!#dbo#!#sp_rename_vu_table1_new#!#BASE TABLE master#!#dbo#!#sp_rename_vu_table2#!#BASE TABLE +master#!#dbo#!#sp_rename_vu_tabletype1#!#BASE TABLE master#!#dbo#!#sp_rename_vu_view1_new#!#VIEW master#!#sp_rename_vu_schema1#!#sp_rename_vu_table1#!#BASE TABLE master#!#sp_rename_vu_schema1#!#sp_rename_vu_table2_new#!#BASE TABLE +master#!#sp_rename_vu_schema1#!#sp_rename_vu_tabletype1#!#BASE TABLE master#!#sp_rename_vu_schema1#!#sp_rename_vu_view1_new2#!#VIEW ~~END~~ @@ -76,9 +80,11 @@ GO nvarchar#!#nvarchar#!#varchar#!#varchar master#!#dbo#!#sp_rename_vu_table1_new#!#BASE TABLE master#!#dbo#!#sp_rename_vu_table2#!#BASE TABLE +master#!#dbo#!#sp_rename_vu_tabletype1#!#BASE TABLE master#!#dbo#!#sp_rename_vu_view1_new#!#VIEW master#!#sp_rename_vu_schema1#!#sp_rename_vu_table1#!#BASE TABLE master#!#sp_rename_vu_schema1#!#sp_rename_vu_table2_new#!#BASE TABLE +master#!#sp_rename_vu_schema1#!#sp_rename_vu_tabletype1#!#BASE TABLE master#!#sp_rename_vu_schema1#!#sp_rename_vu_view1_new#!#VIEW ~~END~~ @@ -120,6 +126,7 @@ master_dbo#!#sp_rename_vu_proc1#!#sp_rename_vu_proc1#!#sp_rename_vu_proc1() master_dbo#!#sp_rename_vu_trig1#!##!#sp_rename_vu_trig1() master_sp_rename_vu_schema1#!#sp_rename_vu_func3#!#sp_rename_vu_func3#!#sp_rename_vu_func3(integer) master_sp_rename_vu_schema1#!#sp_rename_vu_proc2#!#sp_rename_vu_proc2#!#sp_rename_vu_proc2() +master_sp_rename_vu_schema1#!#sp_rename_vu_trig1#!##!#sp_rename_vu_trig1() ~~END~~ @@ -161,6 +168,7 @@ master_dbo#!#sp_rename_vu_proc1_new#!#sp_rename_vu_proc1_new#!#sp_rename_vu_proc master_dbo#!#sp_rename_vu_trig1#!##!#sp_rename_vu_trig1() master_sp_rename_vu_schema1#!#sp_rename_vu_func3_new#!#sp_rename_vu_func3_new#!#sp_rename_vu_func3_new(integer) master_sp_rename_vu_schema1#!#sp_rename_vu_proc2_new#!#sp_rename_vu_proc2_new#!#sp_rename_vu_proc2_new() +master_sp_rename_vu_schema1#!#sp_rename_vu_trig1#!##!#sp_rename_vu_trig1() ~~END~~ @@ -278,9 +286,11 @@ GO nvarchar#!#nvarchar#!#varchar#!#varchar master#!#dbo#!#sp_rename_vu_table1_case_insensitive1#!#BASE TABLE master#!#dbo#!#sp_rename_vu_table2#!#BASE TABLE +master#!#dbo#!#sp_rename_vu_tabletype1#!#BASE TABLE master#!#dbo#!#sp_rename_vu_view1#!#VIEW master#!#sp_rename_vu_schema1#!#sp_rename_vu_table1#!#BASE TABLE master#!#sp_rename_vu_schema1#!#sp_rename_vu_table2_new#!#BASE TABLE +master#!#sp_rename_vu_schema1#!#sp_rename_vu_tabletype1#!#BASE TABLE master#!#sp_rename_vu_schema1#!#sp_rename_vu_view1_new#!#VIEW ~~END~~ @@ -295,9 +305,11 @@ GO nvarchar#!#nvarchar#!#varchar#!#varchar master#!#dbo#!#sp_rename_vu_table1_case_insensitive2#!#BASE TABLE master#!#dbo#!#sp_rename_vu_table2#!#BASE TABLE +master#!#dbo#!#sp_rename_vu_tabletype1#!#BASE TABLE master#!#dbo#!#sp_rename_vu_view1#!#VIEW master#!#sp_rename_vu_schema1#!#sp_rename_vu_table1#!#BASE TABLE master#!#sp_rename_vu_schema1#!#sp_rename_vu_table2_new#!#BASE TABLE +master#!#sp_rename_vu_schema1#!#sp_rename_vu_tabletype1#!#BASE TABLE master#!#sp_rename_vu_schema1#!#sp_rename_vu_view1_new#!#VIEW ~~END~~ @@ -312,9 +324,11 @@ GO nvarchar#!#nvarchar#!#varchar#!#varchar master#!#dbo#!#sp_rename_vu_table1_case_insensitive2#!#BASE TABLE master#!#dbo#!#sp_rename_vu_table2#!#BASE TABLE +master#!#dbo#!#sp_rename_vu_tabletype1#!#BASE TABLE master#!#dbo#!#sp_rename_vu_view1_case_insensitive1#!#VIEW master#!#sp_rename_vu_schema1#!#sp_rename_vu_table1#!#BASE TABLE master#!#sp_rename_vu_schema1#!#sp_rename_vu_table2_new#!#BASE TABLE +master#!#sp_rename_vu_schema1#!#sp_rename_vu_tabletype1#!#BASE TABLE master#!#sp_rename_vu_schema1#!#sp_rename_vu_view1_new#!#VIEW ~~END~~ @@ -349,9 +363,11 @@ GO nvarchar#!#nvarchar#!#varchar#!#varchar master#!#dbo#!#sp_rename_vu_table1_case_insensitive2#!#BASE TABLE master#!#dbo#!#sp_rename_vu_table2#!#BASE TABLE +master#!#dbo#!#sp_rename_vu_tabletype1#!#BASE TABLE master#!#dbo#!#sp_rename_vu_view1#!#VIEW master#!#sp_rename_vu_schema1#!#sp_rename_vu_table1#!#BASE TABLE master#!#sp_rename_vu_schema1#!#sp_rename_vu_table2_new#!#BASE TABLE +master#!#sp_rename_vu_schema1#!#sp_rename_vu_tabletype1#!#BASE TABLE master#!#sp_rename_vu_schema1#!#sp_rename_vu_view1_new#!#VIEW ~~END~~ @@ -394,6 +410,7 @@ master_dbo#!#sp_rename_vu_proc1_new2#!#sp_rename_vu_PRoc1_new2#!#sp_rename_vu_pr master_dbo#!#sp_rename_vu_trig1#!##!#sp_rename_vu_trig1() master_sp_rename_vu_schema1#!#sp_rename_vu_func3_new#!#sp_rename_vu_func3_new#!#sp_rename_vu_func3_new(integer) master_sp_rename_vu_schema1#!#sp_rename_vu_proc2_new#!#sp_rename_vu_proc2_new#!#sp_rename_vu_proc2_new() +master_sp_rename_vu_schema1#!#sp_rename_vu_trig1#!##!#sp_rename_vu_trig1() ~~END~~ @@ -428,7 +445,142 @@ master#!#sp_rename_vu_schema1#!#sp_rename_vu_seq1_new2 ~~END~~ --- ****Given objtype is valid but not supported yet**** +-- Trigger +SELECT name, parent_class +FROM sys.triggers WHERE name LIKE '%sp_rename_vu%' +ORDER BY parent_class, name +GO +~~START~~ +varchar#!#tinyint +sp_rename_vu_trig1#!#1 +sp_rename_vu_trig1#!#1 +~~END~~ + + +SELECT nspname, funcname, orig_name, funcsignature +FROM sys.babelfish_function_ext WHERE funcname LIKE '%sp_rename_vu%' +ORDER BY nspname, funcname, orig_name, funcsignature +GO +~~START~~ +varchar#!#varchar#!#nvarchar#!#text +master_dbo#!#sp_rename_vu_func1_new#!#sp_rename_vu_func1_new#!#sp_rename_vu_func1_new() +master_dbo#!#sp_rename_vu_func2_new#!#sp_rename_vu_FUNC2_neW#!#sp_rename_vu_func2_new(integer) +master_dbo#!#sp_rename_vu_proc1_new2#!#sp_rename_vu_PRoc1_new2#!#sp_rename_vu_proc1_new2() +master_dbo#!#sp_rename_vu_trig1#!##!#sp_rename_vu_trig1() +master_sp_rename_vu_schema1#!#sp_rename_vu_func3_new#!#sp_rename_vu_func3_new#!#sp_rename_vu_func3_new(integer) +master_sp_rename_vu_schema1#!#sp_rename_vu_proc2_new#!#sp_rename_vu_proc2_new#!#sp_rename_vu_proc2_new() +master_sp_rename_vu_schema1#!#sp_rename_vu_trig1#!##!#sp_rename_vu_trig1() +~~END~~ + + +INSERT INTO sp_rename_vu_table2(sp_rename_vu_t2_col1, sp_rename_vu_t2_col2) VALUES (1, 2); +GO +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Testing sp_rename trigger)~~ + + +EXEC sp_rename 'sp_rename_vu_trig1', 'sp_rename_vu_trig1_new', 'OBJECT'; +GO + +EXEC sp_rename 'sp_rename_vu_schema1.sp_rename_vu_trig1', 'sp_rename_vu_trig1_schema1_new', 'OBJECT'; +GO + +SELECT name, parent_class +FROM sys.triggers WHERE name LIKE '%sp_rename_vu%' +ORDER BY parent_class, name +GO +~~START~~ +varchar#!#tinyint +sp_rename_vu_trig1_new#!#1 +sp_rename_vu_trig1_schema1_new#!#1 +~~END~~ + + +SELECT nspname, funcname, orig_name, funcsignature +FROM sys.babelfish_function_ext WHERE funcname LIKE '%sp_rename_vu%' +ORDER BY nspname, funcname, orig_name, funcsignature +GO +~~START~~ +varchar#!#varchar#!#nvarchar#!#text +master_dbo#!#sp_rename_vu_func1_new#!#sp_rename_vu_func1_new#!#sp_rename_vu_func1_new() +master_dbo#!#sp_rename_vu_func2_new#!#sp_rename_vu_FUNC2_neW#!#sp_rename_vu_func2_new(integer) +master_dbo#!#sp_rename_vu_proc1_new2#!#sp_rename_vu_PRoc1_new2#!#sp_rename_vu_proc1_new2() +master_dbo#!#sp_rename_vu_trig1_new#!##!#sp_rename_vu_trig1_new() +master_sp_rename_vu_schema1#!#sp_rename_vu_func3_new#!#sp_rename_vu_func3_new#!#sp_rename_vu_func3_new(integer) +master_sp_rename_vu_schema1#!#sp_rename_vu_proc2_new#!#sp_rename_vu_proc2_new#!#sp_rename_vu_proc2_new() +master_sp_rename_vu_schema1#!#sp_rename_vu_trig1_schema1_new#!##!#sp_rename_vu_trig1_schema1_new() +~~END~~ + + +INSERT INTO sp_rename_vu_table2(sp_rename_vu_t2_col1, sp_rename_vu_t2_col2) VALUES (1, 2); +GO +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Testing sp_rename trigger)~~ + + +-- Table Type +SELECT name FROM sys.table_types +WHERE name LIKE '%sp_rename_vu%' +ORDER BY schema_id, type_table_object_id, name; +GO +~~START~~ +text +sp_rename_vu_tabletype1 +sp_rename_vu_tabletype1 +~~END~~ + + +SELECT * FROM information_schema.tables WHERE TABLE_NAME LIKE '%sp_rename_vu%' +ORDER BY TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME +GO +~~START~~ +nvarchar#!#nvarchar#!#varchar#!#varchar +master#!#dbo#!#sp_rename_vu_table1_case_insensitive2#!#BASE TABLE +master#!#dbo#!#sp_rename_vu_table2#!#BASE TABLE +master#!#dbo#!#sp_rename_vu_tabletype1#!#BASE TABLE +master#!#dbo#!#sp_rename_vu_view1#!#VIEW +master#!#sp_rename_vu_schema1#!#sp_rename_vu_table1#!#BASE TABLE +master#!#sp_rename_vu_schema1#!#sp_rename_vu_table2_new#!#BASE TABLE +master#!#sp_rename_vu_schema1#!#sp_rename_vu_tabletype1#!#BASE TABLE +master#!#sp_rename_vu_schema1#!#sp_rename_vu_view1_new#!#VIEW +~~END~~ + + +EXEC sp_rename 'sp_rename_vu_tabletype1', 'sp_rename_vu_tabletype1_new', 'OBJECT'; +GO + +EXEC sp_rename 'sp_rename_vu_schema1.sp_rename_vu_tabletype1', 'sp_rename_vu_tabletype1_schema1_new', 'OBJECT'; +GO + +SELECT name FROM sys.table_types +WHERE name LIKE '%sp_rename_vu%' +ORDER BY schema_id, type_table_object_id, name; +GO +~~START~~ +text +sp_rename_vu_tabletype1_new +sp_rename_vu_tabletype1_schema1_new +~~END~~ + + +SELECT * FROM information_schema.tables WHERE TABLE_NAME LIKE '%sp_rename_vu%' +ORDER BY TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME +GO +~~START~~ +nvarchar#!#nvarchar#!#varchar#!#varchar +master#!#dbo#!#sp_rename_vu_table1_case_insensitive2#!#BASE TABLE +master#!#dbo#!#sp_rename_vu_table2#!#BASE TABLE +master#!#dbo#!#sp_rename_vu_tabletype1_new#!#BASE TABLE +master#!#dbo#!#sp_rename_vu_view1#!#VIEW +master#!#sp_rename_vu_schema1#!#sp_rename_vu_table1#!#BASE TABLE +master#!#sp_rename_vu_schema1#!#sp_rename_vu_table2_new#!#BASE TABLE +master#!#sp_rename_vu_schema1#!#sp_rename_vu_tabletype1_schema1_new#!#BASE TABLE +master#!#sp_rename_vu_schema1#!#sp_rename_vu_view1_new#!#VIEW +~~END~~ + + -- Column EXEC sp_rename 'sp_rename_vu_table1_case_insensitive2', 'sp_rename_vu_table1', 'OBJECT'; GO @@ -508,6 +660,21 @@ GO ~~ERROR (Message: column "sp_rename_vu_s1_t2_wrong_col" does not exist)~~ +-- Helper Function +DECLARE @sp_rename_helperfunc_out1 nvarchar(776); +DECLARE @sp_rename_helperfunc_out2 nvarchar(776); +DECLARE @sp_rename_helperfunc_out3 nvarchar(776); +DECLARE @sp_rename_helperfunc_out4 nvarchar(776); +EXEC sys.babelfish_sp_rename_word_parse 'sp_rename_vu_schema1.sp_rename_vu_table2_new.sp_rename_vu_s1_t2_col1_new', 'COLUMN', @sp_rename_helperfunc_out1 OUT, @sp_rename_helperfunc_out2 OUT, @sp_rename_helperfunc_out3 OUT, @sp_rename_helperfunc_out4 OUT; +SELECT @sp_rename_helperfunc_out1, @sp_rename_helperfunc_out2, @sp_rename_helperfunc_out3, @sp_rename_helperfunc_out4; +GO +~~START~~ +nvarchar#!#nvarchar#!#nvarchar#!#nvarchar +sp_rename_vu_s1_t2_col1_new#!#sp_rename_vu_table2_new#!#sp_rename_vu_schema1#!# +~~END~~ + + +-- ****Given objtype is valid but not supported yet**** -- Index EXEC sp_rename N'sp_rename_vu_index1', N'sp_rename_vu_index2', N'INDEX'; GO @@ -531,25 +698,3 @@ GO ~~ERROR (Message: Feature not supported: renaming object type User-defined Data Type alias)~~ - --- Trigger -EXEC sp_rename 'sp_rename_vu_trig1', 'sp_rename_vu_trig2', 'OBJECT'; -GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: Feature not supported: renaming object type Trigger)~~ - - --- Helper Function -DECLARE @sp_rename_helperfunc_out1 nvarchar(776); -DECLARE @sp_rename_helperfunc_out2 nvarchar(776); -DECLARE @sp_rename_helperfunc_out3 nvarchar(776); -DECLARE @sp_rename_helperfunc_out4 nvarchar(776); -EXEC sys.babelfish_sp_rename_word_parse 'sp_rename_vu_schema1.sp_rename_vu_table2_new.sp_rename_vu_s1_t2_col1_new', 'COLUMN', @sp_rename_helperfunc_out1 OUT, @sp_rename_helperfunc_out2 OUT, @sp_rename_helperfunc_out3 OUT, @sp_rename_helperfunc_out4 OUT; -SELECT @sp_rename_helperfunc_out1, @sp_rename_helperfunc_out2, @sp_rename_helperfunc_out3, @sp_rename_helperfunc_out4; -GO -~~START~~ -nvarchar#!#nvarchar#!#nvarchar#!#nvarchar -sp_rename_vu_s1_t2_col1_new#!#sp_rename_vu_table2_new#!#sp_rename_vu_schema1#!# -~~END~~ - diff --git a/test/JDBC/input/storedProcedures/Test-sp_rename-vu-cleanup.sql b/test/JDBC/input/storedProcedures/Test-sp_rename-vu-cleanup.sql index e01114d2d4..8af214172d 100644 --- a/test/JDBC/input/storedProcedures/Test-sp_rename-vu-cleanup.sql +++ b/test/JDBC/input/storedProcedures/Test-sp_rename-vu-cleanup.sql @@ -44,5 +44,11 @@ GO DROP SEQUENCE sp_rename_vu_schema1.sp_rename_vu_seq1_new2; GO +DROP TYPE sp_rename_vu_tabletype1_new; +GO + +DROP TYPE sp_rename_vu_schema1.sp_rename_vu_tabletype1_schema1_new; +GO + DROP SCHEMA sp_rename_vu_schema1; GO \ No newline at end of file diff --git a/test/JDBC/input/storedProcedures/Test-sp_rename-vu-prepare.sql b/test/JDBC/input/storedProcedures/Test-sp_rename-vu-prepare.sql index e36d9b8dec..eb1ba11e6b 100644 --- a/test/JDBC/input/storedProcedures/Test-sp_rename-vu-prepare.sql +++ b/test/JDBC/input/storedProcedures/Test-sp_rename-vu-prepare.sql @@ -72,7 +72,14 @@ START WITH 1 INCREMENT BY 1; GO -CREATE TRIGGER sp_rename_vu_trig1 ON sp_rename_vu_table2 -AFTER INSERT, UPDATE AS -RAISERROR ('Testing sp_rename', 16, 10); +CREATE TRIGGER sp_rename_vu_trig1 ON sp_rename_vu_table2 AFTER INSERT, UPDATE AS RAISERROR ('Testing sp_rename trigger', 16, 10); +GO + +CREATE TRIGGER sp_rename_vu_schema1.sp_rename_vu_trig1 ON sp_rename_vu_schema1.sp_rename_vu_table2 AFTER INSERT, UPDATE AS RAISERROR ('Testing sp_rename trigger', 16, 10); +GO + +CREATE TYPE sp_rename_vu_tabletype1 AS TABLE(a int); +GO + +CREATE TYPE sp_rename_vu_schema1.sp_rename_vu_tabletype1 AS TABLE(a int); GO \ No newline at end of file diff --git a/test/JDBC/input/storedProcedures/Test-sp_rename-vu-verify.sql b/test/JDBC/input/storedProcedures/Test-sp_rename-vu-verify.sql index a86a19b98e..b37474b92e 100644 --- a/test/JDBC/input/storedProcedures/Test-sp_rename-vu-verify.sql +++ b/test/JDBC/input/storedProcedures/Test-sp_rename-vu-verify.sql @@ -207,7 +207,64 @@ FROM information_schema.sequences WHERE SEQUENCE_NAME LIKE '%sp_rename_vu%' ORDER BY SEQUENCE_CATALOG, SEQUENCE_SCHEMA, SEQUENCE_NAME GO --- ****Given objtype is valid but not supported yet**** +-- Trigger +SELECT name, parent_class +FROM sys.triggers WHERE name LIKE '%sp_rename_vu%' +ORDER BY parent_class, name +GO + +SELECT nspname, funcname, orig_name, funcsignature +FROM sys.babelfish_function_ext WHERE funcname LIKE '%sp_rename_vu%' +ORDER BY nspname, funcname, orig_name, funcsignature +GO + +INSERT INTO sp_rename_vu_table2(sp_rename_vu_t2_col1, sp_rename_vu_t2_col2) VALUES (1, 2); +GO + +EXEC sp_rename 'sp_rename_vu_trig1', 'sp_rename_vu_trig1_new', 'OBJECT'; +GO + +EXEC sp_rename 'sp_rename_vu_schema1.sp_rename_vu_trig1', 'sp_rename_vu_trig1_schema1_new', 'OBJECT'; +GO + +SELECT name, parent_class +FROM sys.triggers WHERE name LIKE '%sp_rename_vu%' +ORDER BY parent_class, name +GO + +SELECT nspname, funcname, orig_name, funcsignature +FROM sys.babelfish_function_ext WHERE funcname LIKE '%sp_rename_vu%' +ORDER BY nspname, funcname, orig_name, funcsignature +GO + +INSERT INTO sp_rename_vu_table2(sp_rename_vu_t2_col1, sp_rename_vu_t2_col2) VALUES (1, 2); +GO + +-- Table Type +SELECT name FROM sys.table_types +WHERE name LIKE '%sp_rename_vu%' +ORDER BY schema_id, type_table_object_id, name; +GO + +SELECT * FROM information_schema.tables WHERE TABLE_NAME LIKE '%sp_rename_vu%' +ORDER BY TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME +GO + +EXEC sp_rename 'sp_rename_vu_tabletype1', 'sp_rename_vu_tabletype1_new', 'OBJECT'; +GO + +EXEC sp_rename 'sp_rename_vu_schema1.sp_rename_vu_tabletype1', 'sp_rename_vu_tabletype1_schema1_new', 'OBJECT'; +GO + +SELECT name FROM sys.table_types +WHERE name LIKE '%sp_rename_vu%' +ORDER BY schema_id, type_table_object_id, name; +GO + +SELECT * FROM information_schema.tables WHERE TABLE_NAME LIKE '%sp_rename_vu%' +ORDER BY TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME +GO + -- Column EXEC sp_rename 'sp_rename_vu_table1_case_insensitive2', 'sp_rename_vu_table1', 'OBJECT'; GO @@ -248,6 +305,16 @@ GO EXEC sp_rename 'sp_rename_vu_schema1.sp_rename_vu_table2_new.sp_rename_vu_s1_t2_wrong_col', 'sp_rename_vu_s1_t2_col1_new', 'COLUMN'; GO +-- Helper Function +DECLARE @sp_rename_helperfunc_out1 nvarchar(776); +DECLARE @sp_rename_helperfunc_out2 nvarchar(776); +DECLARE @sp_rename_helperfunc_out3 nvarchar(776); +DECLARE @sp_rename_helperfunc_out4 nvarchar(776); +EXEC sys.babelfish_sp_rename_word_parse 'sp_rename_vu_schema1.sp_rename_vu_table2_new.sp_rename_vu_s1_t2_col1_new', 'COLUMN', @sp_rename_helperfunc_out1 OUT, @sp_rename_helperfunc_out2 OUT, @sp_rename_helperfunc_out3 OUT, @sp_rename_helperfunc_out4 OUT; +SELECT @sp_rename_helperfunc_out1, @sp_rename_helperfunc_out2, @sp_rename_helperfunc_out3, @sp_rename_helperfunc_out4; +GO + +-- ****Given objtype is valid but not supported yet**** -- Index EXEC sp_rename N'sp_rename_vu_index1', N'sp_rename_vu_index2', N'INDEX'; GO @@ -258,17 +325,4 @@ GO -- USERDATATYPE EXEC sp_rename 'sp_rename_vu_alias1', 'sp_rename_vu_alias2', 'USERDATATYPE'; -GO - --- Trigger -EXEC sp_rename 'sp_rename_vu_trig1', 'sp_rename_vu_trig2', 'OBJECT'; -GO - --- Helper Function -DECLARE @sp_rename_helperfunc_out1 nvarchar(776); -DECLARE @sp_rename_helperfunc_out2 nvarchar(776); -DECLARE @sp_rename_helperfunc_out3 nvarchar(776); -DECLARE @sp_rename_helperfunc_out4 nvarchar(776); -EXEC sys.babelfish_sp_rename_word_parse 'sp_rename_vu_schema1.sp_rename_vu_table2_new.sp_rename_vu_s1_t2_col1_new', 'COLUMN', @sp_rename_helperfunc_out1 OUT, @sp_rename_helperfunc_out2 OUT, @sp_rename_helperfunc_out3 OUT, @sp_rename_helperfunc_out4 OUT; -SELECT @sp_rename_helperfunc_out1, @sp_rename_helperfunc_out2, @sp_rename_helperfunc_out3, @sp_rename_helperfunc_out4; GO \ No newline at end of file From 972d632a0a64d638cb074c4a77e016e823528ed4 Mon Sep 17 00:00:00 2001 From: Jake Owen Date: Tue, 18 Apr 2023 14:27:30 -0400 Subject: [PATCH 065/363] Select Sequences - Gives error while in user created databases (#1414) Currently Babelfish gives an error when sequences are created in any database other than 'master'. This change was made to improve Babelfish functional correctness and resolve a customer blocker. Task: BABEL-4098 Signed-off-by: Jake Owen --- contrib/babelfishpg_tsql/src/tsqlIface.cpp | 21 ++++++++++++++++++-- test/JDBC/expected/BABEL-4098-vu-cleanup.out | 16 +++++++++++++++ test/JDBC/expected/BABEL-4098-vu-prepare.out | 15 ++++++++++++++ test/JDBC/expected/BABEL-4098-vu-verify.out | 18 +++++++++++++++++ test/JDBC/input/BABEL-4098-vu-cleanup.sql | 16 +++++++++++++++ test/JDBC/input/BABEL-4098-vu-prepare.sql | 15 ++++++++++++++ test/JDBC/input/BABEL-4098-vu-verify.sql | 8 ++++++++ test/JDBC/upgrade/14_7/schedule | 2 ++ test/JDBC/upgrade/14_8/schedule | 2 ++ test/JDBC/upgrade/15_2/schedule | 1 + test/JDBC/upgrade/latest/schedule | 1 + 11 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 test/JDBC/expected/BABEL-4098-vu-cleanup.out create mode 100644 test/JDBC/expected/BABEL-4098-vu-prepare.out create mode 100644 test/JDBC/expected/BABEL-4098-vu-verify.out create mode 100644 test/JDBC/input/BABEL-4098-vu-cleanup.sql create mode 100644 test/JDBC/input/BABEL-4098-vu-prepare.sql create mode 100644 test/JDBC/input/BABEL-4098-vu-verify.sql diff --git a/contrib/babelfishpg_tsql/src/tsqlIface.cpp b/contrib/babelfishpg_tsql/src/tsqlIface.cpp index 051278b7ed..8b9b3a9278 100644 --- a/contrib/babelfishpg_tsql/src/tsqlIface.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlIface.cpp @@ -37,6 +37,7 @@ extern "C" { #include "pltsql-2.h" #include "pl_explain.h" #include "session.h" +#include "multidb.h" #include "catalog/namespace.h" #include "catalog/pg_proc.h" @@ -1825,10 +1826,26 @@ class tsqlBuilder : public tsqlCommonMutator std::string nextval_string = "nextval('" + seq_name + "')"; if (fctx->schema) { + TSqlParser::IdContext *dctx = fctx->database; TSqlParser::IdContext *sctx = fctx->schema; TSqlParser::IdContext *octx = fctx->object_name; - // Need to directly use the backend schema name since nextval is a postgres function - nextval_string = "nextval('master_" + ::stripQuoteFromId(sctx) + '.' + ::stripQuoteFromId(octx) + "')"; + char *database; + char *schema; + + if(dctx) + database = pstrdup(stripQuoteFromId(dctx).c_str()); + else + database = get_cur_db_name(); + + schema = get_physical_schema_name(database, stripQuoteFromId(sctx).c_str()); + + if(strcmp(schema, "") == 0) + nextval_string = "nextval('" + ::stripQuoteFromId(octx) + "')"; + else + // Need to directly use the backend schema name since nextval is a postgres function + nextval_string = "nextval('" + std::string(schema) + '.' + ::stripQuoteFromId(octx) + "')"; + + pfree(database); } rewritten_query_fragment.emplace(std::make_pair(ctx->NEXT()->getSymbol()->getStartIndex(), std::make_pair(::getFullText(ctx->NEXT()), ""))); diff --git a/test/JDBC/expected/BABEL-4098-vu-cleanup.out b/test/JDBC/expected/BABEL-4098-vu-cleanup.out new file mode 100644 index 0000000000..f48f101bcc --- /dev/null +++ b/test/JDBC/expected/BABEL-4098-vu-cleanup.out @@ -0,0 +1,16 @@ +use babel_4098_db; +go + +DROP SEQUENCE babel_4098.seq1; +GO +DROP SEQUENCE seq2; +GO + +DROP SCHEMA babel_4098; +GO + +use master; +go + +DROP DATABASE babel_4098_db; +go diff --git a/test/JDBC/expected/BABEL-4098-vu-prepare.out b/test/JDBC/expected/BABEL-4098-vu-prepare.out new file mode 100644 index 0000000000..6fea6f7a45 --- /dev/null +++ b/test/JDBC/expected/BABEL-4098-vu-prepare.out @@ -0,0 +1,15 @@ + +CREATE DATABASE babel_4098_db; +GO + +use babel_4098_db; +GO + +create schema babel_4098; +go + +CREATE SEQUENCE babel_4098.seq1 AS INT START WITH 10 INCREMENT BY 5 MINVALUE 0 MAXVALUE 100; +go + +CREATE SEQUENCE seq2 AS INT START WITH 0 INCREMENT BY 1 MINVALUE 0 MAXVALUE 100; +go diff --git a/test/JDBC/expected/BABEL-4098-vu-verify.out b/test/JDBC/expected/BABEL-4098-vu-verify.out new file mode 100644 index 0000000000..dfa2adcaf2 --- /dev/null +++ b/test/JDBC/expected/BABEL-4098-vu-verify.out @@ -0,0 +1,18 @@ +use babel_4098_db; +go + +SELECT NEXT VALUE FOR babel_4098.seq1 +GO +~~START~~ +bigint +10 +~~END~~ + + +SELECT NEXT VALUE FOR seq2 +GO +~~START~~ +bigint +0 +~~END~~ + diff --git a/test/JDBC/input/BABEL-4098-vu-cleanup.sql b/test/JDBC/input/BABEL-4098-vu-cleanup.sql new file mode 100644 index 0000000000..0ad7158317 --- /dev/null +++ b/test/JDBC/input/BABEL-4098-vu-cleanup.sql @@ -0,0 +1,16 @@ +use babel_4098_db; +go + +DROP SEQUENCE babel_4098.seq1; +GO +DROP SEQUENCE seq2; +GO + +DROP SCHEMA babel_4098; +GO + +use master; +go + +DROP DATABASE babel_4098_db; +go \ No newline at end of file diff --git a/test/JDBC/input/BABEL-4098-vu-prepare.sql b/test/JDBC/input/BABEL-4098-vu-prepare.sql new file mode 100644 index 0000000000..7bd19a9246 --- /dev/null +++ b/test/JDBC/input/BABEL-4098-vu-prepare.sql @@ -0,0 +1,15 @@ + +CREATE DATABASE babel_4098_db; +GO + +use babel_4098_db; +GO + +create schema babel_4098; +go + +CREATE SEQUENCE babel_4098.seq1 AS INT START WITH 10 INCREMENT BY 5 MINVALUE 0 MAXVALUE 100; +go + +CREATE SEQUENCE seq2 AS INT START WITH 0 INCREMENT BY 1 MINVALUE 0 MAXVALUE 100; +go \ No newline at end of file diff --git a/test/JDBC/input/BABEL-4098-vu-verify.sql b/test/JDBC/input/BABEL-4098-vu-verify.sql new file mode 100644 index 0000000000..07d95a6848 --- /dev/null +++ b/test/JDBC/input/BABEL-4098-vu-verify.sql @@ -0,0 +1,8 @@ +use babel_4098_db; +go + +SELECT NEXT VALUE FOR babel_4098.seq1 +GO + +SELECT NEXT VALUE FOR seq2 +GO \ No newline at end of file diff --git a/test/JDBC/upgrade/14_7/schedule b/test/JDBC/upgrade/14_7/schedule index f7af33a97b..0751725d3a 100644 --- a/test/JDBC/upgrade/14_7/schedule +++ b/test/JDBC/upgrade/14_7/schedule @@ -400,4 +400,6 @@ dateadd_internal_df datetime2fromparts timefromparts BABEL-3215 +BABEL-NEXT-VALUE-FOR +BABEL-4098 BABEL-4078-before-14_8-or-15_3 diff --git a/test/JDBC/upgrade/14_8/schedule b/test/JDBC/upgrade/14_8/schedule index 2db3ce7b69..0a998a9620 100644 --- a/test/JDBC/upgrade/14_8/schedule +++ b/test/JDBC/upgrade/14_8/schedule @@ -399,4 +399,6 @@ datetime2fromparts timefromparts orderby-before-15_3 BABEL-3215 +BABEL-NEXT-VALUE-FOR +BABEL-4098 BABEL-4078 diff --git a/test/JDBC/upgrade/15_2/schedule b/test/JDBC/upgrade/15_2/schedule index 0ebaafc06d..a9f5a37e73 100644 --- a/test/JDBC/upgrade/15_2/schedule +++ b/test/JDBC/upgrade/15_2/schedule @@ -408,6 +408,7 @@ BABEL-3657 BABEL-733 BABEL-3938 BABEL-NEXT-VALUE-FOR +BABEL-4098 binary-index rowcount # test_windows_sp_helpuser diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index 0b6551375f..6830f8371f 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -413,6 +413,7 @@ BABEL-745 BABEL-3938 sys-userid BABEL-NEXT-VALUE-FOR +BABEL-4098 babel_context_info binary-index test_windows_sp_helpuser From 46e0fe24c979a2671338aa93c551fa2bbf60a6de Mon Sep 17 00:00:00 2001 From: Zhibai Date: Tue, 18 Apr 2023 11:48:33 -0700 Subject: [PATCH 066/363] fix the problem, fetch not work properly in psql endpoint (#1446) previously fetch will return all rows in psql endpoint it's due to wrongly change the fetch row to 0 in not Tsql dialect Task: babel-4102 Signed-off-by: Zhibai Song Co-authored-by: Zhibai Song --- contrib/babelfishpg_tsql/src/hooks.c | 4 ++- test/JDBC/expected/pg_fetch.out | 40 ++++++++++++++++++++++++++++ test/JDBC/input/pg_fetch.mix | 26 ++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 test/JDBC/expected/pg_fetch.out create mode 100644 test/JDBC/input/pg_fetch.mix diff --git a/contrib/babelfishpg_tsql/src/hooks.c b/contrib/babelfishpg_tsql/src/hooks.c index 7a28f4d7b3..7001d34088 100644 --- a/contrib/babelfishpg_tsql/src/hooks.c +++ b/contrib/babelfishpg_tsql/src/hooks.c @@ -465,7 +465,9 @@ pltsql_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, return; } - if ((count == 0 || count > pltsql_rowcount) && queryDesc->operation == CMD_SELECT) + if ((count == 0 || (count > pltsql_rowcount && pltsql_rowcount != 0)) + && queryDesc->operation == CMD_SELECT + && sql_dialect == SQL_DIALECT_TSQL) count = pltsql_rowcount; if (prev_ExecutorRun) diff --git a/test/JDBC/expected/pg_fetch.out b/test/JDBC/expected/pg_fetch.out new file mode 100644 index 0000000000..f8aa7e6e95 --- /dev/null +++ b/test/JDBC/expected/pg_fetch.out @@ -0,0 +1,40 @@ +-- psql + +create table t1( a int); +GO + +insert into t1 select generate_series(1,5); +GO +~~ROW COUNT: 5~~ + + +begin; +GO + +DECLARE _test_cursor CURSOR FOR SELECT a from only t1; +GO + +FETCH 2 from _test_cursor; +GO +~~START~~ +int4 +1 +2 +~~END~~ + + +FETCH 2 from _test_cursor; +GO +~~START~~ +int4 +3 +4 +~~END~~ + + +commit; +GO + +drop table t1; +GO + diff --git a/test/JDBC/input/pg_fetch.mix b/test/JDBC/input/pg_fetch.mix new file mode 100644 index 0000000000..8a11fc7371 --- /dev/null +++ b/test/JDBC/input/pg_fetch.mix @@ -0,0 +1,26 @@ +-- psql + +create table t1( a int); +GO + +insert into t1 select generate_series(1,5); +GO + +begin; +GO + +DECLARE _test_cursor CURSOR FOR SELECT a from only t1; +GO + +FETCH 2 from _test_cursor; +GO + +FETCH 2 from _test_cursor; +GO + +commit; +GO + +drop table t1; +GO + From 2f24a3765f65aa0683540a345cf753898e5c3119 Mon Sep 17 00:00:00 2001 From: "Ray\" DongHo Kim" <112982631+raydhkim@users.noreply.github.com> Date: Wed, 19 Apr 2023 09:10:58 -0700 Subject: [PATCH 067/363] Support sp_rename for USERDATATYPE type (#1441) Previously, User Defined Type: alias was not supported for sp_rename procedure. Now, this objtype is supported for sp_rename, allowing users to rename User Defined Type: alias using sp_rename. Task: BABEL-3892 Signed-off-by: Ray Kim --- .../babelfishpg_tsql/sql/babelfishpg_tsql.sql | 19 ++++- .../babelfishpg_tsql--3.1.0--3.2.0.sql | 19 ++++- contrib/babelfishpg_tsql/src/multidb.c | 6 +- contrib/babelfishpg_tsql/src/procedures.c | 28 +++---- .../expected/Test-sp_rename-vu-cleanup.out | 12 +++ .../expected/Test-sp_rename-vu-prepare.out | 14 +++- .../expected/Test-sp_rename-vu-verify.out | 82 +++++++++++++++++-- .../Test-sp_rename-vu-cleanup.sql | 12 +++ .../Test-sp_rename-vu-prepare.sql | 14 +++- .../Test-sp_rename-vu-verify.sql | 44 +++++++++- 10 files changed, 208 insertions(+), 42 deletions(-) diff --git a/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql index 20c4d4b764..adca986fef 100644 --- a/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql +++ b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql @@ -3053,10 +3053,6 @@ BEGIN BEGIN THROW 33557097, N'Feature not supported: renaming object type Statistics', 1; END - ELSE IF @objtype = 'USERDATATYPE' - BEGIN - THROW 33557097, N'Feature not supported: renaming object type User-defined Data Type alias', 1; - END ELSE BEGIN DECLARE @subname sys.nvarchar(776); @@ -3078,6 +3074,21 @@ BEGIN END SET @currtype = 'CO'; END + ELSE IF @objtype = 'USERDATATYPE' + BEGIN + DECLARE @alias_count INT; + SELECT @alias_count = COUNT(*) FROM sys.types t1 INNER JOIN sys.schemas s1 ON t1.schema_id = s1.schema_id + WHERE s1.name = @schemaname AND t1.name = @subname; + IF @alias_count > 1 + BEGIN + THROW 33557097, N'There are multiple objects with the given @objname.', 1; + END + IF @alias_count < 1 + BEGIN + THROW 33557097, N'There is no object with the given @objname.', 1; + END + SET @currtype = 'AL'; + END ELSE IF @objtype = 'OBJECT' BEGIN DECLARE @count INT; diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql index 183848427c..13f2e58b37 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql @@ -1757,10 +1757,6 @@ BEGIN BEGIN THROW 33557097, N'Feature not supported: renaming object type Statistics', 1; END - ELSE IF @objtype = 'USERDATATYPE' - BEGIN - THROW 33557097, N'Feature not supported: renaming object type User-defined Data Type alias', 1; - END ELSE BEGIN DECLARE @subname sys.nvarchar(776); @@ -1782,6 +1778,21 @@ BEGIN END SET @currtype = 'CO'; END + ELSE IF @objtype = 'USERDATATYPE' + BEGIN + DECLARE @alias_count INT; + SELECT @alias_count = COUNT(*) FROM sys.types t1 INNER JOIN sys.schemas s1 ON t1.schema_id = s1.schema_id + WHERE s1.name = @schemaname AND t1.name = @subname; + IF @alias_count > 1 + BEGIN + THROW 33557097, N'There are multiple objects with the given @objname.', 1; + END + IF @alias_count < 1 + BEGIN + THROW 33557097, N'There is no object with the given @objname.', 1; + END + SET @currtype = 'AL'; + END ELSE IF @objtype = 'OBJECT' BEGIN DECLARE @count INT; diff --git a/contrib/babelfishpg_tsql/src/multidb.c b/contrib/babelfishpg_tsql/src/multidb.c index 22198d0df0..9abcc01404 100644 --- a/contrib/babelfishpg_tsql/src/multidb.c +++ b/contrib/babelfishpg_tsql/src/multidb.c @@ -504,11 +504,15 @@ rewrite_object_refs(Node *stmt) { case OBJECT_FUNCTION: case OBJECT_PROCEDURE: - case OBJECT_TYPE: { rewrite_objectwithargs((ObjectWithArgs *) rename->object); break; } + case OBJECT_TYPE: + { + rewrite_plain_name((List *) rename->object); + break; + } case OBJECT_SCHEMA: { char *cur_db = get_cur_db_name(); diff --git a/contrib/babelfishpg_tsql/src/procedures.c b/contrib/babelfishpg_tsql/src/procedures.c index 9ed5dd6f7a..40ef6ef59b 100644 --- a/contrib/babelfishpg_tsql/src/procedures.c +++ b/contrib/babelfishpg_tsql/src/procedures.c @@ -2931,7 +2931,7 @@ sp_rename_internal(PG_FUNCTION_ARGS) /* 4. for each obj type, generate the corresponding RenameStmt */ /* update variables based on the target objtype */ if (strcmp(objtype, "U") == 0 || strcmp(objtype, "IT") == 0 || strcmp(objtype, "S") == 0 || - strcmp(objtype, "ET") == 0) + strcmp(objtype, "ET") == 0 || strcmp(objtype, "TT") == 0) { objtype_code = OBJECT_TABLE; process_util_querystr = "(ALTER TABLE )"; @@ -2971,11 +2971,11 @@ sp_rename_internal(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Feature not supported: renaming object type Constraint"))); } - else if (strcmp(objtype, "TT") == 0) + else if (strcmp(objtype, "AL") == 0) { - /* TABLE TYPE */ + /* USER DEFINED TYPES ALIAS*/ objtype_code = OBJECT_TYPE; - process_util_querystr = "(ALTER TABLE )"; + process_util_querystr = "(ALTER TYPE )"; } else if (strcmp(objtype, "CO") == 0) { @@ -2992,10 +2992,6 @@ sp_rename_internal(PG_FUNCTION_ARGS) /* Advance cmd counter to make the delete visible */ CommandCounterIncrement(); - /* - * parsetree_list = gen_sp_rename_subcmds(obj_name, new_name, - * schema_name, objtype); - */ parsetree_list = gen_sp_rename_subcmds(obj_name, new_name, schema_name, objtype_code, curr_relname); /* 5. run all commands */ @@ -3015,7 +3011,6 @@ sp_rename_internal(PG_FUNCTION_ARGS) /* do this step */ ProcessUtility(wrapper, pstrdup(process_util_querystr), - /* "(ALTER TABLE )", */ false, PROCESS_UTILITY_SUBCOMMAND, NULL, @@ -3073,13 +3068,13 @@ gen_sp_rename_subcmds(const char *objname, const char *newname, const char *sche appendStringInfo(&query, "ALTER TRIGGER dummy ON dummy RENAME TO dummy; "); appendStringInfo(&query, "ALTER FUNCTION dummy RENAME TO dummy; "); break; - case OBJECT_TYPE: - appendStringInfo(&query, "ALTER TABLE dummy RENAME TO dummy; "); - break; case OBJECT_COLUMN: appendStringInfo(&query, "ALTER TABLE dummy RENAME COLUMN dummy TO dummy; "); appendStringInfo(&query, "ALTER TABLE dummy ALTER COLUMN dummy SET (dummy = 'dummy'); "); break; + case OBJECT_TYPE: + appendStringInfo(&query, "ALTER TYPE dummy RENAME TO dummy; "); + break; default: ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), @@ -3138,13 +3133,12 @@ gen_sp_rename_subcmds(const char *objname, const char *newname, const char *sche renamestmt->subname = pstrdup(lowerstr(objname)); renamestmt->newname = pstrdup(lowerstr(newname)); } - else if ((objtype == OBJECT_TYPE)) + else if (objtype == OBJECT_TYPE) { - renamestmt->renameType = OBJECT_TABLE; + renamestmt->renameType = objtype; + renamestmt->object = (Node *)list_make2(makeString(pstrdup(lowerstr(schemaname))), makeString(pstrdup(lowerstr(objname)))); renamestmt->subname = pstrdup(lowerstr(objname)); renamestmt->newname = pstrdup(lowerstr(newname)); - renamestmt->relation->schemaname = pstrdup(lowerstr(schemaname)); - renamestmt->relation->relname = pstrdup(lowerstr(objname)); } else { @@ -3181,4 +3175,4 @@ gen_sp_rename_subcmds(const char *objname, const char *newname, const char *sche rewrite_object_refs(stmt); return res; -} +} \ No newline at end of file diff --git a/test/JDBC/expected/Test-sp_rename-vu-cleanup.out b/test/JDBC/expected/Test-sp_rename-vu-cleanup.out index ed558f3eaf..3f8fb490e8 100644 --- a/test/JDBC/expected/Test-sp_rename-vu-cleanup.out +++ b/test/JDBC/expected/Test-sp_rename-vu-cleanup.out @@ -44,6 +44,18 @@ GO DROP SEQUENCE sp_rename_vu_schema1.sp_rename_vu_seq1_new2; GO +DROP TABLE sp_rename_vu_alias1_table1; +GO + +DROP TABLE sp_rename_vu_alias1_table2; +GO + +DROP TYPE sp_rename_vu_alias2; +GO + +DROP TYPE sp_rename_vu_schema1.sp_rename_vu_alias2; +GO + DROP TYPE sp_rename_vu_tabletype1_new; GO diff --git a/test/JDBC/expected/Test-sp_rename-vu-prepare.out b/test/JDBC/expected/Test-sp_rename-vu-prepare.out index 142be26384..dc25e50ba5 100644 --- a/test/JDBC/expected/Test-sp_rename-vu-prepare.out +++ b/test/JDBC/expected/Test-sp_rename-vu-prepare.out @@ -72,10 +72,14 @@ START WITH 1 INCREMENT BY 1; GO -CREATE TRIGGER sp_rename_vu_trig1 ON sp_rename_vu_table2 AFTER INSERT, UPDATE AS RAISERROR ('Testing sp_rename trigger', 16, 10); +CREATE TRIGGER sp_rename_vu_trig1 ON sp_rename_vu_table2 +AFTER INSERT, UPDATE AS +RAISERROR ('Testing sp_rename trigger', 16, 10); GO -CREATE TRIGGER sp_rename_vu_schema1.sp_rename_vu_trig1 ON sp_rename_vu_schema1.sp_rename_vu_table2 AFTER INSERT, UPDATE AS RAISERROR ('Testing sp_rename trigger', 16, 10); +CREATE TRIGGER sp_rename_vu_schema1.sp_rename_vu_trig1 ON sp_rename_vu_schema1.sp_rename_vu_table2 +AFTER INSERT, UPDATE AS +RAISERROR ('Testing sp_rename trigger', 16, 10); GO CREATE TYPE sp_rename_vu_tabletype1 AS TABLE(a int); @@ -83,3 +87,9 @@ GO CREATE TYPE sp_rename_vu_schema1.sp_rename_vu_tabletype1 AS TABLE(a int); GO + +CREATE TYPE sp_rename_vu_alias1 FROM VARCHAR(11) NOT NULL; +GO + +CREATE TYPE sp_rename_vu_schema1.sp_rename_vu_alias1 FROM VARCHAR(11) NOT NULL; +GO diff --git a/test/JDBC/expected/Test-sp_rename-vu-verify.out b/test/JDBC/expected/Test-sp_rename-vu-verify.out index 8a06784712..e85338248b 100644 --- a/test/JDBC/expected/Test-sp_rename-vu-verify.out +++ b/test/JDBC/expected/Test-sp_rename-vu-verify.out @@ -660,6 +660,80 @@ GO ~~ERROR (Message: column "sp_rename_vu_s1_t2_wrong_col" does not exist)~~ +-- USERDATATYPE +SELECT t1.name, s1.name +FROM sys.types t1 INNER JOIN sys.schemas s1 ON t1.schema_id = s1.schema_id +WHERE t1.is_user_defined = 1 AND t1.name LIKE '%sp_rename_vu%' +ORDER BY t1.name, s1.name; +GO +~~START~~ +text#!#varchar +sp_rename_vu_alias1#!#dbo +sp_rename_vu_alias1#!#sp_rename_vu_schema1 +sp_rename_vu_tabletype1_new#!#dbo +sp_rename_vu_tabletype1_schema1_new#!#sp_rename_vu_schema1 +~~END~~ + + +CREATE TABLE sp_rename_vu_alias1_table1(col1 sp_rename_vu_alias1); +GO + +EXEC sp_rename 'sp_rename_vu_alias1', 'sp_rename_vu_alias2', 'USERDATATYPE'; +GO + +EXEC sp_rename 'sp_rename_vu_schema1.sp_rename_vu_alias1', 'sp_rename_vu_alias2', 'USERDATATYPE'; +GO + +SELECT t1.name, s1.name +FROM sys.types t1 INNER JOIN sys.schemas s1 ON t1.schema_id = s1.schema_id +WHERE t1.is_user_defined = 1 AND t1.name LIKE '%sp_rename_vu%' +ORDER BY t1.name, s1.name; +GO +~~START~~ +text#!#varchar +sp_rename_vu_alias2#!#dbo +sp_rename_vu_alias2#!#sp_rename_vu_schema1 +sp_rename_vu_tabletype1_new#!#dbo +sp_rename_vu_tabletype1_schema1_new#!#sp_rename_vu_schema1 +~~END~~ + + +CREATE TABLE sp_rename_vu_alias1_table2(col1 sp_rename_vu_alias1); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: type "sp_rename_vu_alias1" does not exist)~~ + + +CREATE TABLE sp_rename_vu_alias1_table2(col1 sp_rename_vu_alias2); +GO + +INSERT INTO sp_rename_vu_alias1_table1(col1) VALUES ('abc'); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO sp_rename_vu_alias1_table2(col1) VALUES ('abcd'); +GO +~~ROW COUNT: 1~~ + + +SELECT * FROM sp_rename_vu_alias1_table1; +GO +~~START~~ +varchar +abc +~~END~~ + + +SELECT * FROM sp_rename_vu_alias1_table2; +GO +~~START~~ +varchar +abcd +~~END~~ + + -- Helper Function DECLARE @sp_rename_helperfunc_out1 nvarchar(776); DECLARE @sp_rename_helperfunc_out2 nvarchar(776); @@ -690,11 +764,3 @@ GO ~~ERROR (Message: Feature not supported: renaming object type Statistics)~~ - --- USERDATATYPE -EXEC sp_rename 'sp_rename_vu_alias1', 'sp_rename_vu_alias2', 'USERDATATYPE'; -GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: Feature not supported: renaming object type User-defined Data Type alias)~~ - diff --git a/test/JDBC/input/storedProcedures/Test-sp_rename-vu-cleanup.sql b/test/JDBC/input/storedProcedures/Test-sp_rename-vu-cleanup.sql index 8af214172d..495f702866 100644 --- a/test/JDBC/input/storedProcedures/Test-sp_rename-vu-cleanup.sql +++ b/test/JDBC/input/storedProcedures/Test-sp_rename-vu-cleanup.sql @@ -44,6 +44,18 @@ GO DROP SEQUENCE sp_rename_vu_schema1.sp_rename_vu_seq1_new2; GO +DROP TABLE sp_rename_vu_alias1_table1; +GO + +DROP TABLE sp_rename_vu_alias1_table2; +GO + +DROP TYPE sp_rename_vu_alias2; +GO + +DROP TYPE sp_rename_vu_schema1.sp_rename_vu_alias2; +GO + DROP TYPE sp_rename_vu_tabletype1_new; GO diff --git a/test/JDBC/input/storedProcedures/Test-sp_rename-vu-prepare.sql b/test/JDBC/input/storedProcedures/Test-sp_rename-vu-prepare.sql index eb1ba11e6b..5c18c0673d 100644 --- a/test/JDBC/input/storedProcedures/Test-sp_rename-vu-prepare.sql +++ b/test/JDBC/input/storedProcedures/Test-sp_rename-vu-prepare.sql @@ -72,14 +72,24 @@ START WITH 1 INCREMENT BY 1; GO -CREATE TRIGGER sp_rename_vu_trig1 ON sp_rename_vu_table2 AFTER INSERT, UPDATE AS RAISERROR ('Testing sp_rename trigger', 16, 10); +CREATE TRIGGER sp_rename_vu_trig1 ON sp_rename_vu_table2 +AFTER INSERT, UPDATE AS +RAISERROR ('Testing sp_rename trigger', 16, 10); GO -CREATE TRIGGER sp_rename_vu_schema1.sp_rename_vu_trig1 ON sp_rename_vu_schema1.sp_rename_vu_table2 AFTER INSERT, UPDATE AS RAISERROR ('Testing sp_rename trigger', 16, 10); +CREATE TRIGGER sp_rename_vu_schema1.sp_rename_vu_trig1 ON sp_rename_vu_schema1.sp_rename_vu_table2 +AFTER INSERT, UPDATE AS +RAISERROR ('Testing sp_rename trigger', 16, 10); GO CREATE TYPE sp_rename_vu_tabletype1 AS TABLE(a int); GO CREATE TYPE sp_rename_vu_schema1.sp_rename_vu_tabletype1 AS TABLE(a int); +GO + +CREATE TYPE sp_rename_vu_alias1 FROM VARCHAR(11) NOT NULL; +GO + +CREATE TYPE sp_rename_vu_schema1.sp_rename_vu_alias1 FROM VARCHAR(11) NOT NULL; GO \ No newline at end of file diff --git a/test/JDBC/input/storedProcedures/Test-sp_rename-vu-verify.sql b/test/JDBC/input/storedProcedures/Test-sp_rename-vu-verify.sql index b37474b92e..29b87ca609 100644 --- a/test/JDBC/input/storedProcedures/Test-sp_rename-vu-verify.sql +++ b/test/JDBC/input/storedProcedures/Test-sp_rename-vu-verify.sql @@ -305,6 +305,46 @@ GO EXEC sp_rename 'sp_rename_vu_schema1.sp_rename_vu_table2_new.sp_rename_vu_s1_t2_wrong_col', 'sp_rename_vu_s1_t2_col1_new', 'COLUMN'; GO +-- USERDATATYPE +SELECT t1.name, s1.name +FROM sys.types t1 INNER JOIN sys.schemas s1 ON t1.schema_id = s1.schema_id +WHERE t1.is_user_defined = 1 AND t1.name LIKE '%sp_rename_vu%' +ORDER BY t1.name, s1.name; +GO + +CREATE TABLE sp_rename_vu_alias1_table1(col1 sp_rename_vu_alias1); +GO + +EXEC sp_rename 'sp_rename_vu_alias1', 'sp_rename_vu_alias2', 'USERDATATYPE'; +GO + +EXEC sp_rename 'sp_rename_vu_schema1.sp_rename_vu_alias1', 'sp_rename_vu_alias2', 'USERDATATYPE'; +GO + +SELECT t1.name, s1.name +FROM sys.types t1 INNER JOIN sys.schemas s1 ON t1.schema_id = s1.schema_id +WHERE t1.is_user_defined = 1 AND t1.name LIKE '%sp_rename_vu%' +ORDER BY t1.name, s1.name; +GO + +CREATE TABLE sp_rename_vu_alias1_table2(col1 sp_rename_vu_alias1); +GO + +CREATE TABLE sp_rename_vu_alias1_table2(col1 sp_rename_vu_alias2); +GO + +INSERT INTO sp_rename_vu_alias1_table1(col1) VALUES ('abc'); +GO + +INSERT INTO sp_rename_vu_alias1_table2(col1) VALUES ('abcd'); +GO + +SELECT * FROM sp_rename_vu_alias1_table1; +GO + +SELECT * FROM sp_rename_vu_alias1_table2; +GO + -- Helper Function DECLARE @sp_rename_helperfunc_out1 nvarchar(776); DECLARE @sp_rename_helperfunc_out2 nvarchar(776); @@ -322,7 +362,3 @@ GO -- Statistics EXEC sp_rename 'sp_rename_vu_stat1', 'sp_rename_vu_stat2', 'STATISTICS'; GO - --- USERDATATYPE -EXEC sp_rename 'sp_rename_vu_alias1', 'sp_rename_vu_alias2', 'USERDATATYPE'; -GO \ No newline at end of file From bbe7c498ed036dc98d2c580fd48da2af24cf07dd Mon Sep 17 00:00:00 2001 From: Suthapalli-Ramya-satya-vasavi-srija <110654856+Suthapalli-Ramya-satya-vasavi-srija@users.noreply.github.com> Date: Fri, 21 Apr 2023 02:02:03 +0530 Subject: [PATCH 068/363] Disallow alter role for babelfish created roles (#1455) [OSS-ONLY] Previously, it is possible for an PG user to break a Babelfish instance by ALTER ROLE of babelfish created logins/users/roles or master user to block logins, change role membership, change passwords, and other changes that would have a dramatic effect on Babelfish functionality. This commit fixes the issue by disallowing few ALTER ROLE operations of babelfish created logins/users/roles and master user in PG for users other than superuser. Only a few ALTER ROLE operations are allowed for babelfish created logins/users/roles which are password change, valid until and connection limit and ALTER ROLE of master user is only allowed to change password. As allowing limited ALTER ROLE operations for roles will help in case of babelfish extensions got disabled. Task: BABEL-2976 Signed-off-by: vasavi suthapalli --- .../src/backend/tds/tdsutils.c | 191 +++++- .../ownership_restrictions_from_pg.out | 631 +++++++++++++++++- .../input/ownership_restrictions_from_pg.mix | 274 +++++++- 3 files changed, 1074 insertions(+), 22 deletions(-) diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdsutils.c b/contrib/babelfishpg_tds/src/backend/tds/tdsutils.c index 2bc6de7041..d376807618 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tdsutils.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tdsutils.c @@ -48,7 +48,7 @@ void tdsutils_ProcessUtility(PlannedStmt *pstmt, const char *queryString, bool ProcessUtility_hook_type next_ProcessUtility = NULL; static void call_next_ProcessUtility(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *completionTag); static void check_babelfish_droprole_restrictions(char *role); -static void check_babelfish_renamerole_restrictions(char *role); +static void check_babelfish_alterrole_restictions(bool allow_alter_role_operation); static void check_babelfish_renamedb_restrictions(Oid target_db_id); static void check_babelfish_dropdb_restrictions(Oid target_db_id); static bool is_babelfish_ownership_enabled(ArrayType *array); @@ -57,6 +57,8 @@ static bool is_babelfish_role(const char *role); /* Role specific handlers */ static bool handle_drop_role(DropRoleStmt *drop_role_stmt); static bool handle_rename(RenameStmt *rename_stmt); +static bool handle_alter_role(AlterRoleStmt* alter_role_stmt); +static bool handle_alter_role_set (AlterRoleSetStmt* alter_role_set_stmt); /* Drop database handler */ static bool handle_dropdb(DropdbStmt *dropdb_stmt); @@ -705,6 +707,12 @@ tdsutils_ProcessUtility(PlannedStmt *pstmt, case T_DropdbStmt: handle_result = handle_dropdb((DropdbStmt *) parsetree); break; + case T_AlterRoleStmt: + handle_result = handle_alter_role((AlterRoleStmt*)parsetree); + break; + case T_AlterRoleSetStmt: + handle_result = handle_alter_role_set((AlterRoleSetStmt*)parsetree); + break; default: break; } @@ -888,14 +896,14 @@ check_babelfish_droprole_restrictions(char *role) pfree(role); /* avoid mem leak */ ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("Babelfish-created users/roles cannot be dropped or altered outside of a Babelfish session"))); + errmsg("Babelfish-created logins/users/roles cannot be dropped or altered outside of a Babelfish session"))); } } /* * is_babelfish_role * - * Helper function to check if a given role is babelfish user or role + * Helper function to check if a given role is babelfish user or role or login * * Notes: * Direct evidence of babelfish membership is stored in babelfish catalog, @@ -911,6 +919,9 @@ is_babelfish_role(const char *role) { Oid sysadmin_oid; Oid role_oid; + Oid bbf_master_guest_oid; + Oid bbf_tempdb_guest_oid; + Oid bbf_msdb_guest_oid; sysadmin_oid = get_role_oid(BABELFISH_SYSADMIN, true); /* missing OK */ role_oid = get_role_oid(role, true); /* missing OK */ @@ -921,6 +932,17 @@ is_babelfish_role(const char *role) if (is_member_of_role(sysadmin_oid, role_oid)) return true; + bbf_master_guest_oid = get_role_oid("master_guest", true); + bbf_tempdb_guest_oid = get_role_oid("tempdb_guest", true); + bbf_msdb_guest_oid = get_role_oid("msdb_guest", true); + if (OidIsValid(bbf_master_guest_oid) + && OidIsValid(bbf_tempdb_guest_oid) + && OidIsValid(bbf_msdb_guest_oid) + && is_member_of_role(role_oid, bbf_master_guest_oid) + && is_member_of_role(role_oid, bbf_tempdb_guest_oid) + && is_member_of_role(role_oid, bbf_msdb_guest_oid)) + return true; + return false; } @@ -944,7 +966,17 @@ handle_rename(RenameStmt *rename_stmt) * triggers, so we need to ignore those. */ if (OBJECT_ROLE == rename_stmt->renameType) - check_babelfish_renamerole_restrictions(rename_stmt->subname); + { + if (sql_dialect != SQL_DIALECT_TSQL && is_babelfish_role(rename_stmt->subname)) + { + /* + * Renaming of an babelfish role/user/login + * shouldn't be allowed for an any pg user + * other than superuser + */ + check_babelfish_alterrole_restictions(false); + } + } else if (OBJECT_DATABASE == rename_stmt->renameType) { @@ -972,23 +1004,152 @@ handle_rename(RenameStmt *rename_stmt) } /* - * check_babelfish_renamerole_restrictions + * check_babelfish_alterrole_restictions * - * Implements following one additional limitation to drop role stmt - * block renaming an active babelfish role/user + * Implements following one additional limitation to alter role stmt + * + * Will throw a error when any pg user other than superuser tried to alter an active + * babelfish role/user/login and which is not an allowed alter role operation */ static void -check_babelfish_renamerole_restrictions(char *role) +check_babelfish_alterrole_restictions(bool allow_alter_role_operation) { - if (sql_dialect == SQL_DIALECT_TSQL) - return; - if (is_babelfish_role(role)) - { - pfree(role); /* avoid mem leak */ + if(!allow_alter_role_operation) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("Babelfish-created users/roles cannot be dropped or altered outside of a Babelfish session"))); - } + errmsg("Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session"))); +} + +/* + * handle_alter_role + * + * Description: This function handles dealing with ALTER ROLE WITH. + * + * Returns: true - We're not attempting to modify something we shouldn't have access to. Normal security checks. + * false - We've reported an error and should not continue executing this call. + */ +static bool +handle_alter_role(AlterRoleStmt* alter_role_stmt) +{ + char *name = get_role_name(alter_role_stmt->role); + const char *babelfish_db_name = NULL; + bool allow_alter_role_operation; + bool master_user = false; + List *options = alter_role_stmt->options; + ListCell *opt; + Oid role_oid; + Oid babelfish_db_oid; + + /* If the role does not exist, just let the normal Postgres checks happen. */ + if (name == NULL) + { + return true; + } + + if (sql_dialect != SQL_DIALECT_TSQL && is_babelfish_role(name)) + { + babelfish_db_name = GetConfigOption("babelfishpg_tsql.database_name", true, false); + babelfish_db_oid = get_database_oid(babelfish_db_name, true); + role_oid = get_role_oid(name, true); + + /* Permission checks */ + if (OidIsValid(role_oid) && OidIsValid(babelfish_db_oid) && pg_database_ownercheck(babelfish_db_oid, role_oid)) + master_user = true; + + /* + * For any pg user, there are only few operations which need to be allowed for + * ALTER ROLE WITH. The allowed operations to alter master user is password change + * and the allowed operations to alter babelfish created logins/users/roles are + * password change, connection limit and valid until. + * + * If any non-allowed option is given among the options of alter role then disallow the operation. + * + * In fututre, if need to allow more operations then add those options into the list. + */ + foreach(opt, options) + { + DefElem *defel = (DefElem *) lfirst(opt); + if(master_user) + { + if (strcmp(defel->defname, "password") == 0) + allow_alter_role_operation = true; + else + { + allow_alter_role_operation = false; + break; + } + } + else + { + if (strcmp(defel->defname, "password") == 0 || + strcmp(defel->defname, "connectionlimit") == 0 || + strcmp(defel->defname, "validUntil") == 0) + allow_alter_role_operation = true; + else + { + allow_alter_role_operation = false; + break; + } + } + } + check_babelfish_alterrole_restictions(allow_alter_role_operation); + } + pfree(name); + return true; +} + +/* handle_alter_role_set + * + * Description: This function handles dealing with ALTER ROLE SET. + * + * Returns: true - We're not attempting to modify something we shouldn't have access to, continue on. + * false - We've reported an error and should not continue executing this call. + */ +static bool +handle_alter_role_set (AlterRoleSetStmt* alter_role_set_stmt) +{ + char *name; + + /* + * If this is an ALTER ROLE ALL [ IN DATABASE ] SET statement, + * alter_role_set_stmt->role will be NULL. While we don't want users + * altering our "protected" roles, we can pass through here because + * PostgreSQL already handles those situations correctly. + * + * The ALTER ROLE ALL SET variant of this command can only be run by + * superusers, and the ALTER ROLE ALL IN DATABASE SET variant is the same as + * ALTER DATABASE SET, which is handled via the regular database ownership + * checks. (Customers should not be able to obtain ownership of our + * "protected" databases thanks to handle_alter_owner().) + */ + if (alter_role_set_stmt->role == NULL) + { + const char *babelfish_db_name = NULL; + babelfish_db_name = GetConfigOption("babelfishpg_tsql.database_name", true, false); + if(babelfish_db_name && alter_role_set_stmt->database && strcmp(alter_role_set_stmt->database, babelfish_db_name) == 0) + check_babelfish_alterrole_restictions(false); + return true; + } + + name = get_role_name(alter_role_set_stmt->role); + + /* If the role does not exist, just let the normal Postgres checks happen.*/ + if (name == NULL) + { + return true; + } + + if (sql_dialect != SQL_DIALECT_TSQL && is_babelfish_role(name)) + { + check_babelfish_alterrole_restictions(false); + } + + /* + * Reaching here does not mean that this user has permission to modify the role. + * Those permissions checks are done through normal handling. + */ + pfree(name); + return true; } /* diff --git a/test/JDBC/expected/ownership_restrictions_from_pg.out b/test/JDBC/expected/ownership_restrictions_from_pg.out index 393440515c..8f8277b99e 100644 --- a/test/JDBC/expected/ownership_restrictions_from_pg.out +++ b/test/JDBC/expected/ownership_restrictions_from_pg.out @@ -3,21 +3,628 @@ CREATE LOGIN ownership_restrictions_from_pg_login1 WITH password = '123'; GO CREATE ROLE ownership_restrictions_from_pg_role1; -go +GO + +CREATE DATABASE ownership_restrictions_from_pg_db; +GO + +DECLARE @ownership_restrictions_from_pg_test_variable int = 100; +GO -- psql CREATE USER ownership_restrictions_from_pg_test_user WITH PASSWORD '12345678' inherit; go +CREATE USER ownership_restrictions_from_pg_test_su_user WITH SUPERUSER LOGIN PASSWORD 'abc'; +GO + +-- psql user=ownership_restrictions_from_pg_login1 password=12345678 +-- If tsql login connected through psql Alter ROLE of an bbf created logins/user/roles for password, +-- connection limit and valid until should be working fine +-- and the rest of alter role operations should throw an error. +DROP ROLE master_ownership_restrictions_from_pg_role1; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be dropped or altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 VALID UNTIL 'infinity'; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 rename to master_ownership_restrictions_from_pg_role5; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 with ENCRYPTED password '123'; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 with password '123'; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 with password NULL; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOCREATEROLE; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 CREATEROLE; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOCREATEDB; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 CREATEDB; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOLOGIN; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 LOGIN; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOSUPERUSER; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 SUPERUSER; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOINHERIT; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 INHERIT; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 REPLICATION; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOREPLICATION; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 BYPASSRLS; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOBYPASSRLS; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 WITH CONNECTION LIMIT 1; +GO + +ALTER ROLE ALL IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: database "ownership_restrictions_from_pg_db" does not exist + Server SQLState: 3D000)~~ + + +ALTER ROLE ALL IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE CURRENT_ROLE IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE CURRENT_USER IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE SESSION_USER IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE CURRENT_ROLE IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE CURRENT_USER IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE SESSION_USER IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE ownership_restrictions_from_pg_login1 RENAME TO ownership_restrictions_from_pg_role2; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE ownership_restrictions_from_pg_login1 VALID UNTIL 'infinity'; +GO + +alter role ownership_restrictions_from_pg_login1 with password '123'; +GO + +ALTER ROLE ownership_restrictions_from_pg_login1 IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE ownership_restrictions_from_pg_login1 IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +-- If the stmt contains a non-allowed option then altering of role not allowed +ALTER ROLE master_ownership_restrictions_from_pg_role1 WITH NOCREATEDB CONNECTION LIMIT 1 password '123'; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE ownership_restrictions_from_pg_login1 WITH NOCREATEDB CONNECTION LIMIT 1 password '123'; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + -- psql user=ownership_restrictions_from_pg_test_user password=12345678 +-- For plain psql user Alter ROLE of an bbf created logins/user/roles for password, +-- connection limit and valid until should be working fine +-- and the rest of alter role operations should throw an error. DROP ROLE master_ownership_restrictions_from_pg_role1; GO ~~ERROR (Code: 0)~~ -~~ERROR (Message: ERROR: Babelfish-created users/roles cannot be dropped or altered outside of a Babelfish session +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be dropped or altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 VALID UNTIL 'infinity'; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: permission denied Server SQLState: 42501)~~ +ALTER ROLE master_ownership_restrictions_from_pg_role1 rename to master_ownership_restrictions_from_pg_role5; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 with ENCRYPTED password '123'; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: permission denied + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 with password '123'; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: permission denied + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 with password NULL; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: permission denied + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOCREATEROLE; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 CREATEROLE; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOCREATEDB; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 CREATEDB; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOLOGIN; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 LOGIN; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOSUPERUSER; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 SUPERUSER; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOINHERIT; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 INHERIT; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 REPLICATION; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOREPLICATION; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 BYPASSRLS; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOBYPASSRLS; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 WITH CONNECTION LIMIT 1; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: permission denied + Server SQLState: 42501)~~ + + +ALTER ROLE ALL IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: database "ownership_restrictions_from_pg_db" does not exist + Server SQLState: 3D000)~~ + + +ALTER ROLE ALL IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE CURRENT_ROLE IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: database "ownership_restrictions_from_pg_db" does not exist + Server SQLState: 3D000)~~ + + +ALTER ROLE CURRENT_USER IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: database "ownership_restrictions_from_pg_db" does not exist + Server SQLState: 3D000)~~ + + +ALTER ROLE SESSION_USER IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: database "ownership_restrictions_from_pg_db" does not exist + Server SQLState: 3D000)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE CURRENT_ROLE IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: permission denied to set parameter "babelfishpg_tsql.ownership_restrictions_from_pg_test_variable" + Server SQLState: 42501)~~ + + +ALTER ROLE CURRENT_USER IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: permission denied to set parameter "babelfishpg_tsql.ownership_restrictions_from_pg_test_variable" + Server SQLState: 42501)~~ + + +ALTER ROLE SESSION_USER IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: permission denied to set parameter "babelfishpg_tsql.ownership_restrictions_from_pg_test_variable" + Server SQLState: 42501)~~ + + +ALTER ROLE ownership_restrictions_from_pg_login1 RENAME TO ownership_restrictions_from_pg_role2; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE ownership_restrictions_from_pg_login1 VALID UNTIL 'infinity'; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: permission denied + Server SQLState: 42501)~~ + + +alter role ownership_restrictions_from_pg_login1 with password '123'; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: permission denied + Server SQLState: 42501)~~ + + +ALTER ROLE ownership_restrictions_from_pg_login1 IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE ownership_restrictions_from_pg_login1 IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +-- If the stmt contains a non-allowed option then altering of role not allowed +ALTER ROLE master_ownership_restrictions_from_pg_role1 WITH NOCREATEDB CONNECTION LIMIT 1 password '123'; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE ownership_restrictions_from_pg_login1 WITH NOCREATEDB CONNECTION LIMIT 1 password '123'; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +-- psql user=ownership_restrictions_from_pg_test_su_user password=abc +-- Altering of babelfish created logins/roles should suceeded for superuser +ALTER ROLE ownership_restrictions_from_pg_login1 VALID UNTIL 'infinity'; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 WITH NOCREATEDB CONNECTION LIMIT 1 password '123'; +GO + -- psql -- Dropping login from psql port should fail DROP ROLE ownership_restrictions_from_pg_login1; @@ -83,12 +690,28 @@ GO DROP ROLE ownership_restrictions_from_pg_role4; GO +SET enable_drop_babelfish_role = true; +go +DROP USER ownership_restrictions_from_pg_test_su_user; +go +SET enable_drop_babelfish_role = false; +go + DROP USER ownership_restrictions_from_pg_test_user; GO --- tsql -DROP ROLE ownership_restrictions_from_pg_role1; +-- Need to terminate active session before cleaning up the login +SELECT pg_terminate_backend(pid) FROM pg_stat_get_activity(NULL) +WHERE sys.suser_name(usesysid) = 'ownership_restrictions_from_pg_login1' AND backend_type = 'client backend' AND usesysid IS NOT NULL; GO +~~START~~ +bool +t +~~END~~ + +-- tsql +DROP DATABASE ownership_restrictions_from_pg_db; +DROP ROLE ownership_restrictions_from_pg_role1; DROP LOGIN ownership_restrictions_from_pg_login1; GO diff --git a/test/JDBC/input/ownership_restrictions_from_pg.mix b/test/JDBC/input/ownership_restrictions_from_pg.mix index e5a049e97a..dc373e93b8 100644 --- a/test/JDBC/input/ownership_restrictions_from_pg.mix +++ b/test/JDBC/input/ownership_restrictions_from_pg.mix @@ -3,16 +3,273 @@ CREATE LOGIN ownership_restrictions_from_pg_login1 WITH password = '123'; GO CREATE ROLE ownership_restrictions_from_pg_role1; -go +GO + +CREATE DATABASE ownership_restrictions_from_pg_db; +GO + +DECLARE @ownership_restrictions_from_pg_test_variable int = 100; +GO -- psql CREATE USER ownership_restrictions_from_pg_test_user WITH PASSWORD '12345678' inherit; go +CREATE USER ownership_restrictions_from_pg_test_su_user WITH SUPERUSER LOGIN PASSWORD 'abc'; +GO + +-- psql user=ownership_restrictions_from_pg_login1 password=12345678 +-- If tsql login connected through psql Alter ROLE of an bbf created logins/user/roles for password, +-- connection limit and valid until should be working fine +-- and the rest of alter role operations should throw an error. +DROP ROLE master_ownership_restrictions_from_pg_role1; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 VALID UNTIL 'infinity'; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 rename to master_ownership_restrictions_from_pg_role5; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 with ENCRYPTED password '123'; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 with password '123'; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 with password NULL; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOCREATEROLE; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 CREATEROLE; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOCREATEDB; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 CREATEDB; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOLOGIN; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 LOGIN; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOSUPERUSER; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 SUPERUSER; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOINHERIT; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 INHERIT; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 REPLICATION; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOREPLICATION; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 BYPASSRLS; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOBYPASSRLS; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 WITH CONNECTION LIMIT 1; +GO + +ALTER ROLE ALL IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE ALL IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE CURRENT_ROLE IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE CURRENT_USER IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE SESSION_USER IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE CURRENT_ROLE IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE CURRENT_USER IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE SESSION_USER IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE ownership_restrictions_from_pg_login1 RENAME TO ownership_restrictions_from_pg_role2; +GO + +ALTER ROLE ownership_restrictions_from_pg_login1 VALID UNTIL 'infinity'; +GO + +alter role ownership_restrictions_from_pg_login1 with password '123'; +GO + +ALTER ROLE ownership_restrictions_from_pg_login1 IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE ownership_restrictions_from_pg_login1 IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +-- If the stmt contains a non-allowed option then altering of role not allowed +ALTER ROLE master_ownership_restrictions_from_pg_role1 WITH NOCREATEDB CONNECTION LIMIT 1 password '123'; +GO + +ALTER ROLE ownership_restrictions_from_pg_login1 WITH NOCREATEDB CONNECTION LIMIT 1 password '123'; +GO + -- psql user=ownership_restrictions_from_pg_test_user password=12345678 +-- For plain psql user Alter ROLE of an bbf created logins/user/roles for password, +-- connection limit and valid until should be working fine +-- and the rest of alter role operations should throw an error. DROP ROLE master_ownership_restrictions_from_pg_role1; GO +ALTER ROLE master_ownership_restrictions_from_pg_role1 VALID UNTIL 'infinity'; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 rename to master_ownership_restrictions_from_pg_role5; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 with ENCRYPTED password '123'; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 with password '123'; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 with password NULL; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOCREATEROLE; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 CREATEROLE; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOCREATEDB; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 CREATEDB; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOLOGIN; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 LOGIN; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOSUPERUSER; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 SUPERUSER; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOINHERIT; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 INHERIT; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 REPLICATION; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOREPLICATION; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 BYPASSRLS; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOBYPASSRLS; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 WITH CONNECTION LIMIT 1; +GO + +ALTER ROLE ALL IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE ALL IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE CURRENT_ROLE IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE CURRENT_USER IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE SESSION_USER IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE CURRENT_ROLE IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE CURRENT_USER IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE SESSION_USER IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE ownership_restrictions_from_pg_login1 RENAME TO ownership_restrictions_from_pg_role2; +GO + +ALTER ROLE ownership_restrictions_from_pg_login1 VALID UNTIL 'infinity'; +GO + +alter role ownership_restrictions_from_pg_login1 with password '123'; +GO + +ALTER ROLE ownership_restrictions_from_pg_login1 IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE ownership_restrictions_from_pg_login1 IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +-- If the stmt contains a non-allowed option then altering of role not allowed +ALTER ROLE master_ownership_restrictions_from_pg_role1 WITH NOCREATEDB CONNECTION LIMIT 1 password '123'; +GO + +ALTER ROLE ownership_restrictions_from_pg_login1 WITH NOCREATEDB CONNECTION LIMIT 1 password '123'; +GO + +-- psql user=ownership_restrictions_from_pg_test_su_user password=abc +-- Altering of babelfish created logins/roles should suceeded for superuser +ALTER ROLE ownership_restrictions_from_pg_login1 VALID UNTIL 'infinity'; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 WITH NOCREATEDB CONNECTION LIMIT 1 password '123'; +GO + -- psql -- Dropping login from psql port should fail DROP ROLE ownership_restrictions_from_pg_login1; @@ -63,12 +320,23 @@ GO DROP ROLE ownership_restrictions_from_pg_role4; GO +SET enable_drop_babelfish_role = true; +go +DROP USER ownership_restrictions_from_pg_test_su_user; +go +SET enable_drop_babelfish_role = false; +go + DROP USER ownership_restrictions_from_pg_test_user; GO --- tsql -DROP ROLE ownership_restrictions_from_pg_role1; +-- Need to terminate active session before cleaning up the login +SELECT pg_terminate_backend(pid) FROM pg_stat_get_activity(NULL) +WHERE sys.suser_name(usesysid) = 'ownership_restrictions_from_pg_login1' AND backend_type = 'client backend' AND usesysid IS NOT NULL; GO +-- tsql +DROP DATABASE ownership_restrictions_from_pg_db; +DROP ROLE ownership_restrictions_from_pg_role1; DROP LOGIN ownership_restrictions_from_pg_login1; GO From 231afc91df154630a75f4b12f11e7d26d36a4ffa Mon Sep 17 00:00:00 2001 From: Kristian Lejao <1741885+lejaokri@users.noreply.github.com> Date: Thu, 20 Apr 2023 18:27:26 -0700 Subject: [PATCH 069/363] Add missing upgrade testcases in opensource. (#1452) * Add missing mvu testcases in opensource. * Keep schedule files in alphabetical order to reduce merge conflicts Task: [NO-JIRA] Signed-off-by: Kristian Lejao --- test/JDBC/upgrade/13_4/schedule | 321 ++++----- test/JDBC/upgrade/13_5/schedule | 379 ++++++----- test/JDBC/upgrade/13_6/schedule | 483 ++++++------- test/JDBC/upgrade/13_7/schedule | 473 ++++++------- test/JDBC/upgrade/13_8/schedule | 473 ++++++------- test/JDBC/upgrade/13_9/schedule | 479 +++++++------ test/JDBC/upgrade/14_3/schedule | 512 +++++++------- test/JDBC/upgrade/14_5/schedule | 506 +++++++------- test/JDBC/upgrade/14_6/schedule | 543 +++++++-------- test/JDBC/upgrade/14_7/schedule | 590 ++++++++-------- test/JDBC/upgrade/14_8/schedule | 588 ++++++++-------- test/JDBC/upgrade/15_1/schedule | 554 ++++++++------- test/JDBC/upgrade/15_2/schedule | 610 ++++++++--------- test/JDBC/upgrade/latest/schedule | 636 +++++++++--------- test/JDBC/upgrade/master/schedule | 548 ++++++--------- .../expected_dependency.out | 5 - 16 files changed, 3789 insertions(+), 3911 deletions(-) diff --git a/test/JDBC/upgrade/13_4/schedule b/test/JDBC/upgrade/13_4/schedule index 821e85d40e..305feb763b 100644 --- a/test/JDBC/upgrade/13_4/schedule +++ b/test/JDBC/upgrade/13_4/schedule @@ -1,6 +1,6 @@ # Schedule File for JDBC Test Framework for local run # 1. Lines starting with '#' will be treated as comments -# 2. To run a postgres command: cmd#!#postgresql#!# +# 2. To run a postgres command: cmd#!#postgresql#!# # 3. To run a T-SQL command: cmd#!#sqlserver#!# # 4. Keyword "all" is equivalent to running all test files in input folder # 5. To add a test, add test name (without extension, , and . For example if test file name is TestBigInt.txt write TestBigInt) on a new line @@ -8,200 +8,205 @@ # This should be the first test to check there are no duplicated object_ids BABEL-3613 -babelfish_cast_floor -babel_try_parse -TestBigInt -TestBinary -TestBIT -TestChar -TestDate -TestDatetime -TestDatetime2 -TestFloat -TestImage -TestInt -TestMoney -TestReal -TestSmallDatetime -TestSmallInt -TestSmallMoney -TestSQLVariant -TestText -TestTime -TestTinyInt -TestUDD -TestUniqueIdentifier -TestVarChar -TestXML -BABEL-2934 -BABEL-3121 -BABEL-3166 -BABEL-3192 -BABEL-3369 -BABEL-3370 -sys-check_constraints -sys-computed_columns -sys-databases -sys-dm_exec_connections -sys-dm_os_host_info -sys-endpoints -sys-extended_properties -sys-index_columns -sys-key_constraints -sys-schemas -sys-sp_databases -sys-sp_tables_view -sys-syscharsets -sys-sysforeignkeys -sys-tables -sys-types -sys-views -fulltextserviceproperty -is_srvrolemember -sys-column-property -sys-datefirst -sys-lock_timeout -sys-max_connections -sys-objects -sys-original_login -sys-procedures -sys-schema-name -identity_function -sys-sysdatabases -sys-sysobjects -sys-trigger_nestlevel -routines_definition_before-14_7-or-15_2 -constraint_column_usage -column_domain_usage -sp_describe_first_result_set -schema_resolution_proc -SYSTEM_USER -Test-Default-Columns BABEL-1189 +BABEL-1206 +BABEL-1243 +BABEL-1249 +BABEL-1251 +BABEL-1291 +BABEL-1319 +BABEL-1438 +BABEL-1444 +BABEL-1465 +BABEL-1466 +BABEL-1475 +BABEL-1510 +BABEL-1625 +BABEL-1683 BABEL-1963 +BABEL-1994-CHAR +BABEL-1994-VARCHAR +BABEL-2086 BABEL-2203 BABEL-2208 BABEL-2257 BABEL-2535 +BABEL-2701 BABEL-2787-2 +BABEL-2795 BABEL-2845 BABEL-2884 +BABEL-2934 +BABEL-3000 +BABEL-3000-dep +BABEL-3010-before-14_6 +BABEL-3121 +BABEL-3147-before-14_5 +BABEL-3166 +BABEL-3192 +BABEL-3213 +BABEL-3215 BABEL-3249 +BABEL-3314 +BABEL-3369 +BABEL-3370 +BABEL-3474 +BABEL-3556-before-14_6 BABEL-3588 -BABEL-PROCID -babel_trigger -nested_trigger_inside_proc -nested_trigger_with_dml -triggers_with_transaction -Test-sp_addrole -Test-sp_addrolemember -Test-sp_droprole -Test-sp_droprolemember -Test-sp_helpdbfixedrole -Test-sp_helpsrvrolemember +BABEL-3655 +BABEL-3657 +BABEL-3938 BABEL-404 +BABEL-4078-before-14_8-or-15_3 +babel_417 BABEL-493 BABEL-621 +BABEL-728 +BABEL-741 BABEL-775 -BABEL-1206 -BABEL-1251 -BABEL-1319 -BABEL-1444 -BABEL-1465 -BABEL-1466 -BABEL-2086 -BABEL-3314 -BABEL-TABLEOPTIONS -temp-tables -TestNotNull -Test-Identity-before-14_7-or-15_2 -TestTableType +BABEL-889 +BABEL-APPLOCK +babel_char +BABEL-CHECK-CONSTRAINT-before-14_6 BABEL-CROSS-DB -BABEL-LOGIN -BABEL-ROLE -babelfish_sysdatabases -babelfish_namespace_ext +babel_datatype_sqlvariant +BABEL-EXTENDEDPROPERTY babelfish_authid_login_ext +babelfish_cast_floor babelfish_migration_mode -schema_resolution_func -BABEL-3147-before-14_5 -babel_char -BABEL-SQUARE -BABEL-728 +babelfish_namespace_ext +babelfish_sysdatabases babel_function_string +BABEL_GRANT_CONNECT babel_isnumeric -HAS_DBACCESS -BABEL-1475 -BABEL-1510 -BABEL-3213 +BABEL-LOGIN +BABEL-PG-SYSTEM-FUNCTIONS +BABEL-PROCID BABEL-RAND -BABEL-741 -BABEL-EXTENDEDPROPERTY -TestErrorHelperFunctionsUpgrade -BABEL-1249 -BABEL-1291 -BABEL-1994-CHAR -BABEL-1994-VARCHAR -BABEL-889 -babel_417 +BABEL-ROLE +BABEL-SPCOLUMNS +BABEL-SPCOLUMNS-dep +BABEL-SP_DATATYPE_INFO +BABEL-sp_helpdb +BABEL-SP_SPROC_COLUMNS +BABEL-SP_STORED_PROCEDURES +BABEL-SP_TABLE_PRIVILIGES +BABEL-SP_TABLES babel_sqlvariant_cast_compare -tdscollation -babel_datatype_sqlvariant +BABEL-SQUARE +BABEL-TABLEOPTIONS +babel_trigger +babel_try_parse +case_insensitive_collation-before-13-5 +column_domain_usage +constraint_column_usage +datetime2fromparts +fulltextserviceproperty +HAS_DBACCESS +identity_function +is_srvrolemember +nested_trigger_inside_proc +nested_trigger_with_dml +routines_definition_before-14_7-or-15_2 +rowcount +schema_resolution_func +schema_resolution_proc +schema_resolution_trigger +sp_describe_first_result_set sys-all_columns +sys_all_objects sys-all_parameters +sys-check_constraints +sys-column-property +sys-computed_columns +sys-databases +sys-datefirst sys-default_constraints +sys-dm_exec_connections sys-dm_exec_sessions +sys-dm_os_host_info +sys-endpoints +sys-extended_properties sys-foreign_key_columns +sys-foreign_key_columns-dep +sys-foreign_keys-dep sys-identity_columns sys-identity_columns-dep-for-13-x +sys-index_columns sys-indexes -sys-table_types -sys_all_objects -sys-system_objects-for-13-x -sys-userid-dep -BABEL-1683 -schema_resolution_trigger -sys-sp_pkeys -sys-sp_statistics -BABEL-APPLOCK -BABEL-1438 -BABEL-SP_DATATYPE_INFO -BABEL-SPCOLUMNS -BABEL-SP_TABLES -BABEL-SP_TABLE_PRIVILIGES -BABEL-SP_STORED_PROCEDURES -BABEL-SP_SPROC_COLUMNS -BABEL-3000 -sys-foreign_key_columns-dep -sys-foreign_keys-dep sys-indexes-dep +sys-key_constraints sys-key_constraints-dep +sys-lock_timeout +sys-max_connections +sys-objects +sys-original_login +sys-procedures +sys-schema-name +sys-schemas sys-schemas-dep +sys_server_principals_dep_for_13_x +sys-sp_databases +sys-sp_pkeys +sys-sp_statistics +sys-sp_tables_view sys-sp_tables_view-dep +sys-suser_sid +sys-suser_sname +sys-syscharsets +sys-syscolumns +sys-sysdatabases +sys-sysforeignkeys sys-sysforeignkeys-dep +sys-sysobjects +sys-system_objects-for-13-x +sys-tables sys-tables-dep +sys-table_types +sys-table_types_internal +SYSTEM_USER +sys-trigger_nestlevel +sys-types sys-types-dep +sys-userid-dep +sys-views sys-views-dep -BABEL-SPCOLUMNS-dep -BABEL-3000-dep -BABEL-3556-before-14_6 -BABEL-3010-before-14_6 -BABEL_GRANT_CONNECT -BABEL-sp_helpdb -BABEL-2795 -BABEL-PG-SYSTEM-FUNCTIONS -BABEL-3655 -sys-table_types_internal -BABEL-CHECK-CONSTRAINT-before-14_6 -sys_server_principals_dep_for_13_x -case_insensitive_collation-before-13-5 +tdscollation +temp-tables +TestBigInt +TestBinary +TestBIT +TestChar +TestDate +TestDatetime +TestDatetime2 +Test-Default-Columns +TestErrorHelperFunctionsUpgrade +TestFloat +Test-Identity-before-14_7-or-15_2 +TestImage +TestInt +TestMoney +TestNotNull +TestReal +TestSmallDatetime +TestSmallInt +TestSmallMoney +Test-sp_addrole +Test-sp_addrolemember +Test-sp_droprole +Test-sp_droprolemember +Test-sp_helpdbfixedrole +Test-sp_helpsrvrolemember +TestSQLVariant +TestTableType +TestText +TestTime +TestTinyInt +TestUDD +TestUniqueIdentifier +TestVarChar test_windows_login_before_15_2 -BABEL-3657 -BABEL-3938 -rowcount -BABEL-1625 -BABEL-3474 -datetime2fromparts +TestXML timefromparts -BABEL-3215 -BABEL-4078-before-14_8-or-15_3 +triggers_with_transaction diff --git a/test/JDBC/upgrade/13_5/schedule b/test/JDBC/upgrade/13_5/schedule index 04ce5a278f..90ab236dd0 100644 --- a/test/JDBC/upgrade/13_5/schedule +++ b/test/JDBC/upgrade/13_5/schedule @@ -1,62 +1,151 @@ # Schedule File for JDBC Test Framework for local run # 1. Lines starting with '#' will be treated as comments -# 2. To run a postgres command: cmd#!#postgresql#!# +# 2. To run a postgres command: cmd#!#postgresql#!# # 3. To run a T-SQL command: cmd#!#sqlserver#!# -# 4. Keyword "all" is equivalent to running all test files in -# input folder -# 5. To add a test, add test name (without extension, -vu-prepare, -vu-verify and -vu-cleanup. For example if test file name is TestBigInt-vu-prepare.txt write TestBigInt) on a new line +# 4. Keyword "all" is equivalent to running all test files in input folder +# 5. To add a test, add test name (without extension, , and . For example if test file name is TestBigInt.txt write TestBigInt) on a new line # This should be the first test to check there are no duplicated object_ids BABEL-3613 -babelfish_cast_floor -babel_try_parse -TestBigInt -TestBinary -TestBIT -TestChar -TestDate -TestDatetime -TestDatetime2 -TestDecimal -TestFloat -TestImage -TestInt -TestMoney -TestNumeric -TestReal -TestSmallDatetime -TestSmallInt -TestSmallMoney -TestSQLVariant -TestText -TestTime -TestTinyInt -TestUDD -TestUniqueIdentifier -TestVarChar -TestXML +BABEL-1189 +BABEL-1206 +BABEL-1243 +BABEL-1249 +BABEL-1251 +BABEL-1291 +BABEL-1319 +BABEL-1438 +BABEL-1444 +BABEL-1465 +BABEL-1466 +BABEL-1475 +BABEL-1493 +BABEL-1510 +BABEL-1625 +BABEL-1683 +BABEL-1715 +BABEL-1963 +BABEL-1994-CHAR +BABEL-1994-VARCHAR +BABEL-2086 +BABEL-2203 +BABEL-2208 +BABEL-2257 +BABEL-2535 +BABEL-2701 +BABEL-2787-2 +BABEL-2795 +BABEL-2845 +BABEL-2884 BABEL-2934 +BABEL-3000 +BABEL-3000-dep +BABEL-3010-before-14_6 BABEL-3121 +BABEL-3147-before-14_5 BABEL-3166 BABEL-3192 -BABEL-3221 BABEL-3204 +BABEL-3213 +BABEL-3215 +BABEL-3221 +BABEL-3249 +BABEL-3314 +BABEL-3347-before-14_6 +BABEL-3360 BABEL-3369 BABEL-3370 +BABEL-3474 +BABEL-3556-before-14_6 +BABEL-3588 +BABEL-3655 +BABEL-3657 +BABEL-3938 +BABEL-404 +BABEL-4078-before-14_8-or-15_3 +babel_417 +BABEL-493 +BABEL-621 +BABEL-728 +BABEL-741 +BABEL-775 +BABEL-889 +BABEL-APPLOCK +babel_char +BABEL-CHECK-CONSTRAINT-before-14_6 +BABEL-CROSS-DB +babel_datatype_sqlvariant +BABEL-EXTENDEDPROPERTY +babelfish_authid_login_ext +babelfish_cast_floor +babelfish_migration_mode +babelfish_namespace_ext +babelfish_sysdatabases +babel_function_string +BABEL_GRANT_CONNECT +babel_isnumeric +BABEL-LOGIN +BABEL-LOGIN-USER-EXT +BABEL-PG-SYSTEM-FUNCTIONS +BABEL-PROCID +BABEL-RAND +BABEL-ROLE +BABEL-SPCOLUMNS +BABEL-SPCOLUMNS-dep +BABEL-SP_DATATYPE_INFO +BABEL-sp_helpdb +BABEL-SP_SPECIAL_COLUMNS +BABEL-SP_SPROC_COLUMNS +BABEL-SP_STORED_PROCEDURES +BABEL-SP_TABLE_PRIVILIGES +BABEL-SP_TABLES +babel_sqlvariant_cast_compare +BABEL-SQUARE +BABEL-TABLEOPTIONS +babel_trigger +babel_try_parse +case_insensitive_collation-before-13-5 +column_domain_usage +constraint_column_usage +datetime2fromparts +fulltextserviceproperty +HAS_DBACCESS +identity_function +is_srvrolemember +msdb-dbo-fn_syspolicy_is_automation_enabled msdb-dbo-syspolicy_system_health_state +nested_trigger_inside_proc +nested_trigger_with_dml +objectpropertyex +routines_definition_before-14_7-or-15_2 +rowcount +schema_resolution_func +schema_resolution_proc +schema_resolution_trigger +sp_describe_first_result_set +sp_tablecollations sys-all_columns +sys_all_objects sys-all_parameters +sys-assemblies sys-assembly_modules sys-change_tracking_databases sys-change_tracking_tables +sys-check_constraints-dep +sys-column-property sys-computed_columns -sys-data_spaces +sys-computed_columns-dep sys-database_files sys-database_filestream_options sys-database_recovery_status +sys-databases +sys-data_spaces +sys-datefirst sys-dm_exec_connections +sys-dm_exec_connections-dep sys-dm_exec_sessions +sys-dm_exec_sessions-dep sys-dm_hadr_cluster sys-dm_hadr_database_replica_states sys-dm_os_host_info @@ -64,7 +153,9 @@ sys-endpoints sys-extended_properties sys-filetable_system_defined_objects sys-foreign_key_columns +sys-foreign_key_columns-dep sys-foreign_keys +sys-foreign_keys-dep sys-fulltext_catalogs sys-fulltext_index_columns sys-fulltext_languages @@ -72,187 +163,103 @@ sys-fulltext_stoplists sys-identity_columns sys-identity_columns-dep-for-13-x sys-index_columns +sys-index_columns-dep sys-indexes +sys-indexes-dep sys-key_constraints +sys-key_constraints-dep +sys-lock_timeout sys-master_files +sys-max_connections +sys-objects +sys-original_login sys-procedures +sys-proc_param_helper-dep sys-registered_search_property_lists +sys-schema-name sys-schemas +sys-schemas-dep sys-selective_xml_index_paths sys-server_principals +sys_server_principals_dep_for_13_x sys-sid_binary +sys-spatial_indexes +sys-spatial_index_tessellations sys-sp_databases +sys-sp_databases-dep +sys-sp_pkeys +sys-sp_pkeys-dep +sys-sp_statistics +sys-sp_statistics-dep sys-sp_tables_view -sys-spatial_index_tessellations -sys-spatial_indexes +sys-sp_tables_view-dep sys-stats sys-synonyms -sys-syscolumns sys-syscharsets +sys-syscolumns +sys-syscolumns-dep +sys-sysdatabases sys-sysforeignkeys +sys-sysforeignkeys-dep +sys-sysindexes sys-syslanguages -sys-table_types +sys-sysobjects +sys-system_objects-for-13-x +sys-system_sql_modules sys-tables +sys-tables-dep +sys-table_types +sys-table_types-dep +sys-table_types_internal +SYSTEM_USER +sys-trigger_nestlevel sys-types +sys-types-dep +sys-userid-dep sys-views +sys-views-dep sys-xml_indexes sys-xml_schema_collections -sys_all_objects -sys-system_objects-for-13-x -fulltextserviceproperty -is_srvrolemember -msdb-dbo-fn_syspolicy_is_automation_enabled -objectpropertyex -sys-column-property -sys-datefirst -sys-databases -sys-lock_timeout -sys-max_connections -sys-objects -sys-original_login -sys-schema-name -identity_function -sys-sysdatabases -sys-sysobjects -sys-trigger_nestlevel -routines_definition_before-14_7-or-15_2 -constraint_column_usage -column_domain_usage -sp_describe_first_result_set -schema_resolution_proc -SYSTEM_USER +table-variable +tdscollation +temp-tables +TestBigInt +TestBinary +TestBIT +TestChar +Test-Computed-Columns +TestDate +TestDatetime +TestDatetime2 +TestDecimal Test-Default-Columns -BABEL-1189 -BABEL-1243 -BABEL-1493 -BABEL-1963 -BABEL-2203 -BABEL-2208 -BABEL-2257 -BABEL-2535 -BABEL-2787-2 -BABEL-2845 -BABEL-2884 -BABEL-3249 -BABEL-3588 -BABEL-PROCID -babel_trigger -nested_trigger_inside_proc -nested_trigger_with_dml -triggers_with_transaction +TestErrorHelperFunctionsUpgrade +TestFloat +Test-Identity-before-14_7-or-15_2 +TestImage +TestInt +TestMoney +TestNotNull +TestNumeric +TestReal +TestSmallDatetime +TestSmallInt +TestSmallMoney Test-sp_addrole Test-sp_addrolemember Test-sp_droprole Test-sp_droprolemember Test-sp_helpdbfixedrole Test-sp_helpsrvrolemember -BABEL-404 -BABEL-493 -BABEL-621 -BABEL-775 -BABEL-1206 -BABEL-1251 -BABEL-1319 -BABEL-1444 -BABEL-1465 -BABEL-1466 -BABEL-1715 -BABEL-2086 -sys-userid-dep -BABEL-3314 -BABEL-TABLEOPTIONS -temp-tables -table-variable -TestNotNull -Test-Identity-before-14_7-or-15_2 -Test-Computed-Columns -babel_char -BABEL-SQUARE -BABEL-728 -babel_function_string -babel_isnumeric -HAS_DBACCESS -BABEL-1475 -BABEL-1510 -BABEL-3213 -BABEL-RAND -BABEL-741 -BABEL-3360 +TestSQLVariant TestTableType -BABEL-CROSS-DB -BABEL-LOGIN -BABEL-ROLE -babelfish_sysdatabases -babelfish_namespace_ext -babelfish_authid_login_ext -babelfish_migration_mode -schema_resolution_func -BABEL-3147-before-14_5 -BABEL-EXTENDEDPROPERTY -TestErrorHelperFunctionsUpgrade -BABEL-1249 -BABEL-1291 -BABEL-1994-CHAR -BABEL-1994-VARCHAR -BABEL-889 -babel_417 -babel_datatype_sqlvariant -babel_sqlvariant_cast_compare -tdscollation -BABEL-1683 -schema_resolution_trigger -sys-sp_pkeys -sys-sp_statistics -BABEL-APPLOCK -BABEL-1438 -BABEL-SP_DATATYPE_INFO -BABEL-SPCOLUMNS -BABEL-SP_TABLES -BABEL-SP_SPECIAL_COLUMNS -BABEL-SP_TABLE_PRIVILIGES -BABEL-SP_STORED_PROCEDURES -BABEL-SP_SPROC_COLUMNS -BABEL-3000 -sys-foreign_key_columns-dep -sys-foreign_keys-dep -sys-indexes-dep -sys-key_constraints-dep -sys-schemas-dep -sys-computed_columns-dep -sys-sp_tables_view-dep -sys-sysforeignkeys-dep -sys-tables-dep -sys-types-dep -sys-views-dep -sys-check_constraints-dep -sys-index_columns-dep -sys-sp_databases-dep -sys-syscolumns-dep -sys-sp_pkeys-dep -sys-sp_statistics-dep -sys-proc_param_helper-dep -BABEL-SPCOLUMNS-dep -BABEL-3000-dep -BABEL-3347-before-14_6 -BABEL-3556-before-14_6 -BABEL-3010-before-14_6 -BABEL_GRANT_CONNECT -BABEL-sp_helpdb -BABEL-2795 -BABEL-PG-SYSTEM-FUNCTIONS -BABEL-3655 -sys-table_types_internal -BABEL-CHECK-CONSTRAINT-before-14_6 -sys-sysindexes -sys_server_principals_dep_for_13_x -case_insensitive_collation-before-13-5 +TestText +TestTime +TestTinyInt +TestUDD +TestUniqueIdentifier +TestVarChar test_windows_login_before_15_2 -BABEL-3657 -BABEL-3938 -rowcount -BABEL-1625 -BABEL-3474 -datetime2fromparts +TestXML timefromparts -BABEL-3215 -BABEL-4078-before-14_8-or-15_3 +triggers_with_transaction diff --git a/test/JDBC/upgrade/13_6/schedule b/test/JDBC/upgrade/13_6/schedule index 66d06fbd3d..deca094bbe 100644 --- a/test/JDBC/upgrade/13_6/schedule +++ b/test/JDBC/upgrade/13_6/schedule @@ -1,65 +1,199 @@ # Schedule File for JDBC Test Framework for local run # 1. Lines starting with '#' will be treated as comments -# 2. To run a postgres command: cmd#!#postgresql#!# +# 2. To run a postgres command: cmd#!#postgresql#!# # 3. To run a T-SQL command: cmd#!#sqlserver#!# -# 4. Keyword "all" is equivalent to running all test files in -# input folder -# 5. To add a test, add test name (without extension, -vu-prepare, -vu-verify and -vu-cleanup. For example if test file name is TestBigInt-vu-prepare.txt write TestBigInt) on a new line +# 4. Keyword "all" is equivalent to running all test files in input folder +# 5. To add a test, add test name (without extension, , and . For example if test file name is TestBigInt.txt write TestBigInt) on a new line # This should be the first test to check there are no duplicated object_ids BABEL-3613 -babelfish_cast_floor -babel_try_parse -TestBigInt -TestBinary -TestBIT -TestChar -TestDate -TestDatetime -TestDatetime2 -TestDecimal -TestFloat -TestImage -TestInt -TestMoney -TestNumeric -TestReal -TestSmallDatetime -TestSmallInt -TestSmallMoney -TestSQLVariant -TestText -TestTime -TestTinyInt -TestUDD -TestUniqueIdentifier -TestVarChar -TestXML +AVG-Aggregate-common +AVG-Aggregate-Dep-before-15-2-or-14-7 +BABEL-1189 +BABEL-1206 +BABEL-1243 +BABEL-1249 +BABEL-1251 +BABEL-1291 +BABEL-1319 +BABEL-1438 +BABEL-1444 +BABEL-1465 +BABEL-1466 +BABEL-1475 +BABEL-1493 +BABEL-1510 +BABEL-1566 +BABEL-1625 +BABEL-1654 +BABEL-1683 +BABEL-1715 +BABEL-1756 +BABEL-1756-dep +BABEL-1963 +BABEL-1994-CHAR +BABEL-1994-VARCHAR +BABEL-2086 +BABEL-2203 +BABEL-2208 +BABEL-2257 +BABEL-2535 +BABEL-2701 +BABEL-2765 +BABEL-2787 +BABEL-2787-2 +BABEL-2795 +BABEL-2845 +BABEL-2884 +BABEL-2917 BABEL-2934 +BABEL-2944 +BABEL-2955 +BABEL-3000 +BABEL-3000-dep +BABEL-3010-before-14_6 +BABEL-3116 +BABEL-3118 BABEL-3121 +BABEL-3147-before-14_5 BABEL-3166 BABEL-3192 -BABEL-3221 BABEL-3204 +BABEL-3213 +BABEL-3215 +BABEL-3221 BABEL-3234 -BABEL-3402 +BABEL-3249 +BABEL-3314 +BABEL-3347-before-14_6 +BABEL-3360 BABEL-3369 BABEL-3370 +BABEL-3402 +BABEL-3474 +BABEL-3556-before-14_6 +BABEL-3588 +BABEL-3640 +BABEL-3646-before-14_6 +BABEL-3655 +BABEL-3657 +BABEL-3748-before-14_7 +BABEL-383 +BABEL-3938 +BABEL-404 +BABEL-405 +BABEL-4078-before-14_8-or-15_3 +babel_417 +BABEL-493 +BABEL-621 +BABEL-728 +BABEL-741 +BABEL-775 +BABEL-889 +BABEL-APPLOCK +babel_char +BABEL-CHECK-CONSTRAINT-before-14_6 +BABEL-CROSS-DB +babel_datatype_sqlvariant +BABEL-EXTENDEDPROPERTY +babelfish_authid_login_ext +babelfish_authid_user_ext +babelfish_cast_floor +babelfish_inconsistent_metadata +babelfish_migration_mode +babelfish_namespace_ext +babelfish_sysdatabases +babel_function_string +BABEL_GRANT_CONNECT +babel_isnumeric +BABEL-LOGIN +BABEL-LOGIN-USER-EXT +BABEL_OBJECT_ID +BABEL_OBJECT_NAME +BABEL-PG-SYSTEM-FUNCTIONS +BABEL-PROCID +BABEL-RAND +BABEL-ROLE +BABEL_SCHEMATA +BABEL-SPCOLUMNS +BABEL-SPCOLUMNS-dep +BABEL-SP_COLUMNS_MANAGED-dep +BABEL-SP_DATATYPE_INFO +BABEL-SP_FKEYS +BABEL-SP_FKEYS-dep +BABEL-sp_helpdb +BABEL-SP_SPECIAL_COLUMNS +BABEL-SP_SPECIAL_COLUMNS_100-dep +BABEL-SP_SPECIAL_COLUMNS-dep +BABEL-SP_SPROC_COLUMNS +BABEL-SP_STORED_PROCEDURES +BABEL-SP_STORED_PROCEDURES-dep +BABEL-SP_TABLE_PRIVILIGES +BABEL-SP_TABLES +babel_sqlvariant_cast_compare +BABEL-SQUARE +BABEL-TABLEOPTIONS +babel_trigger +babel_try_parse +BABEL-USER +bbf_view_def-before-14_5 +case_insensitive_collation +collation_tests +collation_tests_arabic +collation_tests_greek +collation_tests_mongolian +collation_tests_polish +column_domain_usage +constraint_column_usage +datepart +datetime2fromparts +fulltextserviceproperty +HAS_DBACCESS +identity_function +insteadof_nested_trigger_inside_proc +insteadof_nested_trigger_with_dml +insteadoftriggers_with_transaction +ISC-Columns +ISC-Table_Constraints +ISC-Tables +is_srvrolemember +msdb-dbo-fn_syspolicy_is_automation_enabled msdb-dbo-syspolicy_system_health_state +nested_trigger_inside_proc +nested_trigger_with_dml +objectpropertyex +routines_definition_before-14_7-or-15_2 +rowcount +schema_resolution_func +schema_resolution_proc +schema_resolution_trigger +sp_describe_first_result_set +sp_tablecollations sys-all_columns +sys_all_objects +sys-all_parameters +sys-all_sql_modules_before-14_5 +sys-assemblies sys-assembly_modules sys-change_tracking_databases sys-change_tracking_tables +sys-check_constraints-dep +sys-column-property sys-columns sys-computed_columns -sys-data_spaces +sys-computed_columns-dep sys-database_files -sys-databases sys-database_filestream_options +sys_database_principals_dep_for_13_x sys-database_recovery_status +sys-databases +sys-data_spaces +sys-datefirst sys-dm_exec_connections +sys-dm_exec_connections-dep sys-dm_exec_sessions +sys-dm_exec_sessions-dep sys-dm_hadr_cluster sys-dm_hadr_database_replica_states sys-dm_os_host_info @@ -67,7 +201,9 @@ sys-endpoints sys-extended_properties sys-filetable_system_defined_objects sys-foreign_key_columns +sys-foreign_key_columns-dep sys-foreign_keys +sys-foreign_keys-dep sys-fulltext_catalogs sys-fulltext_index_columns sys-fulltext_languages @@ -75,243 +211,108 @@ sys-fulltext_stoplists sys-identity_columns sys-identity_columns-dep-for-13-x sys-index_columns +sys-index_columns-dep sys-indexes +sys-indexes-dep sys-key_constraints +sys-key_constraints-dep +sys-lock_timeout sys-master_files +sys-max_connections +sys-objects +sys-original_login +sys-procedures +sys-proc_param_helper-dep sys-registered_search_property_lists +sys-schema-name sys-schemas +sys-schemas-dep sys-selective_xml_index_paths sys-server_principals +sys_server_principals_dep_for_13_x sys-sid_binary +sys-spatial_indexes +sys-spatial_index_tessellations sys-sp_databases +sys-sp_databases-dep +sys-sp_pkeys +sys-sp_pkeys-dep +sys-sp_statistics +sys-sp_statistics-dep sys-sp_tables_view -sys-spatial_index_tessellations -sys-spatial_indexes +sys-sp_tables_view-dep +sys-sql_modules_before-14_7-or-15_2 sys-stats +sys-suser_sid +sys-suser_sname sys-synonyms sys-syscharsets sys-syscolumns +sys-syscolumns-dep +sys-sysdatabases sys-sysforeignkeys +sys-sysforeignkeys-dep +sys-sysindexes sys-syslanguages +sys-sysobjects +sys-system_objects-for-13-x sys-system_sql_modules -sys-table_types sys-tables +sys-tables-dep +sys-table_types +sys-table_types-dep +sys-table_types_internal +SYSTEM_USER +sys-trigger_nestlevel sys-triggers sys-types +sys-types-dep +sys-userid-dep sys-views +sys-views-dep sys-xml_indexes sys-xml_schema_collections -sys_all_objects -sys-system_objects-for-13-x -fulltextserviceproperty -is_srvrolemember -msdb-dbo-fn_syspolicy_is_automation_enabled -objectpropertyex -sys-all_parameters -sys-column-property -sys-datefirst -sys-lock_timeout -sys-max_connections -sys-objects -sys-original_login -sys-procedures -sys-schema-name -sys-suser_sid -identity_function -sys-suser_sname -sys-sysdatabases -sys-sysobjects -sys-trigger_nestlevel -routines_definition_before-14_7-or-15_2 -constraint_column_usage -column_domain_usage -sp_describe_first_result_set -schema_resolution_proc -datepart -SYSTEM_USER +table-variable +tdscollation +temp-tables +TestBigInt +TestBinary +TestBIT +TestChar +Test-Computed-Columns +TestDate +TestDatetime +TestDatetime2 +TestDecimal Test-Default-Columns -BABEL-1189 -BABEL-1243 -BABEL-1493 -BABEL-1963 -BABEL-2203 -BABEL-2208 -BABEL-2257 -BABEL-2535 -BABEL-2787-2 -BABEL-2787 -BABEL-2845 -BABEL-2884 -BABEL-2944 -BABEL-3116 -BABEL-3118 -BABEL-3249 -BABEL-3588 -BABEL-383 -BABEL-405 -BABEL-PROCID -babel_trigger -insteadoftriggers_with_transaction -insteadof_nested_trigger_inside_proc -insteadof_nested_trigger_with_dml -nested_trigger_inside_proc -nested_trigger_with_dml -triggers_with_transaction +TestErrorHelperFunctionsUpgrade +TestFloat +Test-Identity-before-14_7-or-15_2 +TestImage +TestInt +TestMoney +TestNotNull +TestNumeric +TestReal +TestSmallDatetime +TestSmallInt +TestSmallMoney Test-sp_addrole Test-sp_addrolemember Test-sp_droprole Test-sp_droprolemember Test-sp_helpdbfixedrole Test-sp_helpsrvrolemember -BABEL-404 -BABEL-493 -BABEL-621 -BABEL-775 -BABEL-1206 -BABEL-1251 -BABEL-1319 -BABEL-1444 -BABEL-1465 -BABEL-1466 -BABEL-1654 -BABEL-1715 -BABEL-2086 -BABEL-3314 -BABEL-TABLEOPTIONS -BABEL-2765 -BABEL-2917 -BABEL-2955 -BABEL-3646-before-14_6 -BABEL-3748-before-14_7 -temp-tables -table-variable -TestNotNull -Test-Identity-before-14_7-or-15_2 -Test-Computed-Columns -babel_char -BABEL-SQUARE -BABEL-728 -babel_function_string -BABEL-2701 -BABEL-1566 -babel_isnumeric -HAS_DBACCESS -BABEL-1475 -BABEL-1510 -BABEL-3213 -BABEL-RAND -BABEL-741 -BABEL-3360 Test-sp_helpuser +TestSQLVariant TestTableType -BABEL-CROSS-DB -BABEL-LOGIN -BABEL-USER -BABEL-ROLE -babelfish_sysdatabases -babelfish_namespace_ext -babelfish_authid_login_ext -babelfish_authid_user_ext -babelfish_inconsistent_metadata -babelfish_migration_mode -schema_resolution_func -BABEL-3147-before-14_5 -collation_tests_arabic -collation_tests_greek -collation_tests_mongolian -collation_tests_polish -collation_tests -BABEL-EXTENDEDPROPERTY -TestErrorHelperFunctionsUpgrade -BABEL-1249 -BABEL-1291 -BABEL-1994-CHAR -BABEL-1994-VARCHAR -BABEL-889 -babel_417 -babel_datatype_sqlvariant -babel_sqlvariant_cast_compare -tdscollation -sp_tablecollations -sys-assemblies -BABEL-LOGIN-USER-EXT -BABEL-1683 -schema_resolution_trigger -sys-sp_pkeys -sys-sp_statistics -BABEL-APPLOCK -BABEL-1438 -BABEL-SP_DATATYPE_INFO -BABEL-SPCOLUMNS -BABEL-SP_TABLES -BABEL-SP_SPECIAL_COLUMNS -BABEL-SP_TABLE_PRIVILIGES -BABEL-SP_STORED_PROCEDURES -BABEL-SP_SPROC_COLUMNS -BABEL-3000 -sys-foreign_key_columns-dep -sys-foreign_keys-dep -sys-indexes-dep -sys-computed_columns-dep -sys-key_constraints-dep -sys-schemas-dep -sys-sp_tables_view-dep -sys-sysforeignkeys-dep -sys-tables-dep -sys-types-dep -sys-views-dep -sys-check_constraints-dep -sys-index_columns-dep -sys-sp_databases-dep -sys-syscolumns-dep -sys-dm_exec_connections-dep -sys-dm_exec_sessions-dep -sys-table_types-dep -sys-sp_pkeys-dep -sys-sp_statistics-dep -sys-proc_param_helper-dep -sys-userid-dep -BABEL-SPCOLUMNS-dep -BABEL-SP_COLUMNS_MANAGED-dep -BABEL-SP_SPECIAL_COLUMNS-dep -BABEL-SP_SPECIAL_COLUMNS_100-dep -BABEL-SP_STORED_PROCEDURES-dep -BABEL-3000-dep -BABEL-3347-before-14_6 -BABEL-3556-before-14_6 -BABEL-3010-before-14_6 -BABEL_GRANT_CONNECT -BABEL-sp_helpdb -BABEL-2795 -BABEL-PG-SYSTEM-FUNCTIONS -BABEL-3655 -sys-table_types_internal -BABEL-CHECK-CONSTRAINT-before-14_6 -BABEL-3640 -sys-sysindexes -ISC-Tables -ISC-Columns -ISC-Table_Constraints -sys_server_principals_dep_for_13_x -sys_database_principals_dep_for_13_x -case_insensitive_collation -AVG-Aggregate-common -AVG-Aggregate-Dep-before-15-2-or-14-7 -bbf_view_def-before-14_5 -sys-sql_modules_before-14_7-or-15_2 -sys-all_sql_modules_before-14_5 -BABEL_OBJECT_ID +TestText +TestTime +TestTinyInt +TestUDD +TestUniqueIdentifier +TestVarChar test_windows_login_before_15_2 -BABEL_SCHEMATA -BABEL-SP_FKEYS -BABEL-SP_FKEYS-dep -BABEL_OBJECT_NAME -BABEL-3657 -BABEL-3938 -rowcount -BABEL-1625 -BABEL-3474 -datetime2fromparts +TestXML timefromparts -BABEL-3215 -BABEL-4078-before-14_8-or-15_3 +triggers_with_transaction diff --git a/test/JDBC/upgrade/13_7/schedule b/test/JDBC/upgrade/13_7/schedule index 706eeec068..557f4e06a1 100644 --- a/test/JDBC/upgrade/13_7/schedule +++ b/test/JDBC/upgrade/13_7/schedule @@ -1,63 +1,194 @@ # Schedule File for JDBC Test Framework for local run # 1. Lines starting with '#' will be treated as comments -# 2. To run a postgres command: cmd#!#postgresql#!# +# 2. To run a postgres command: cmd#!#postgresql#!# # 3. To run a T-SQL command: cmd#!#sqlserver#!# -# 4. Keyword "all" is equivalent to running all test files in -# input folder -# 5. To add a test, add test name (without extension, -vu-prepare, -vu-verify and -vu-cleanup. For example if test file name is TestBigInt-vu-prepare.txt write TestBigInt) on a new line +# 4. Keyword "all" is equivalent to running all test files in input folder +# 5. To add a test, add test name (without extension, , and . For example if test file name is TestBigInt.txt write TestBigInt) on a new line # This should be the first test to check there are no duplicated object_ids BABEL-3613 -babelfish_cast_floor -babel_try_parse -TestBigInt -TestBinary -TestBIT -TestChar -TestDate -TestDatetime -TestDatetime2 -TestDecimal -TestFloat -TestImage -TestInt -TestMoney -TestNumeric -TestReal -TestSmallDatetime -TestSmallInt -TestSmallMoney -TestSQLVariant -TestText -TestTime -TestTinyInt -TestUDD -TestUniqueIdentifier -TestVarChar -TestXML +BABEL-1189 +BABEL-1206 +BABEL-1243 +BABEL-1249 +BABEL-1251 +BABEL-1291 +BABEL-1319 +BABEL-1438 +BABEL-1444 +BABEL-1465 +BABEL-1466 +BABEL-1475 +BABEL-1493 +BABEL-1510 +BABEL-1566 +BABEL-1625 +BABEL-1654 +BABEL-1683 +BABEL-1715 +BABEL-1756 +BABEL-1756-dep +BABEL-1963 +BABEL-1994-CHAR +BABEL-1994-VARCHAR +BABEL-2086 +BABEL-2203 +BABEL-2208 +BABEL-2257 +BABEL-2535 +BABEL-2701 +BABEL-2765 +BABEL-2787 +BABEL-2787-2 +BABEL-2795 +BABEL-2845 +BABEL-2884 +BABEL-2917 BABEL-2934 +BABEL-2944 +BABEL-2955 +BABEL-3000 +BABEL-3000-dep +BABEL-3010-before-14_6 +BABEL-3116 +BABEL-3118 BABEL-3121 +BABEL-3147-before-14_5 BABEL-3166 BABEL-3192 -BABEL-3221 BABEL-3204 +BABEL-3213 +BABEL-3215 +BABEL-3221 BABEL-3234 +BABEL-3249 +BABEL-3314 +BABEL-3347-before-14_6 +BABEL-3360 +BABEL-3369 +BABEL-3370 BABEL-3402 +BABEL-3474 +BABEL-3556-before-14_6 +BABEL-3588 +BABEL-3640 +BABEL-3646-before-14_6 +BABEL-3655 +BABEL-3657 +BABEL-3748-before-14_7 +BABEL-383 +BABEL-3938 +BABEL-404 +BABEL-405 +BABEL-4078-before-14_8-or-15_3 +babel_417 +BABEL-493 +BABEL-621 +BABEL-728 +BABEL-741 +BABEL-775 +BABEL-889 +BABEL-APPLOCK +babel_char +BABEL-CHECK-CONSTRAINT-before-14_6 +BABEL-CROSS-DB +babel_datatype_sqlvariant +BABEL-EXTENDEDPROPERTY +babelfish_authid_login_ext +babelfish_authid_user_ext +babelfish_cast_floor +babelfish_inconsistent_metadata +babelfish_migration_mode +babelfish_namespace_ext +babelfish_sysdatabases +babel_function_string +BABEL_GRANT_CONNECT +babel_isnumeric +BABEL-LOGIN +BABEL-LOGIN-USER-EXT +BABEL_OBJECT_ID +BABEL_OBJECT_NAME +BABEL-PG-SYSTEM-FUNCTIONS +BABEL-PROCID +BABEL-RAND +BABEL-ROLE +BABEL_SCHEMATA +BABEL-SPCOLUMNS +BABEL-SPCOLUMNS-dep +BABEL-SP_COLUMNS_MANAGED-dep +BABEL-SP_DATATYPE_INFO +BABEL-sp_helpdb +BABEL-SP_SPECIAL_COLUMNS +BABEL-SP_SPECIAL_COLUMNS_100-dep +BABEL-SP_SPECIAL_COLUMNS-dep +BABEL-SP_SPROC_COLUMNS +BABEL-SP_STORED_PROCEDURES +BABEL-SP_STORED_PROCEDURES-dep +BABEL-SP_TABLE_PRIVILIGES +BABEL-SP_TABLES +babel_sqlvariant_cast_compare +BABEL-SQUARE +BABEL-TABLEOPTIONS +babel_trigger +babel_try_parse +BABEL-USER +bbf_view_def-before-14_5 +case_insensitive_collation +collation_tests +collation_tests_arabic +collation_tests_greek +collation_tests_mongolian +collation_tests_polish +column_domain_usage +constraint_column_usage +datepart +datetime2fromparts +fulltextserviceproperty +HAS_DBACCESS +identity_function +insteadof_nested_trigger_inside_proc +insteadof_nested_trigger_with_dml +insteadoftriggers_with_transaction +ISC-Columns +ISC-Table_Constraints +ISC-Tables +is_srvrolemember +msdb-dbo-fn_syspolicy_is_automation_enabled msdb-dbo-syspolicy_system_health_state +nested_trigger_inside_proc +nested_trigger_with_dml +objectpropertyex +routines_definition_before-14_7-or-15_2 +rowcount +schema_resolution_func +schema_resolution_proc +schema_resolution_trigger +sp_describe_first_result_set +sp_tablecollations sys-all_columns +sys_all_objects sys-all_parameters +sys-all_sql_modules_before-14_5 +sys-assemblies sys-assembly_modules sys-change_tracking_databases sys-change_tracking_tables +sys-check_constraints-dep +sys-column-property sys-columns sys-computed_columns -sys-data_spaces +sys-computed_columns-dep sys-database_files sys-database_filestream_options +sys_database_principals_dep_for_13_x sys-database_recovery_status +sys-data_spaces +sys-datefirst sys-dm_exec_connections +sys-dm_exec_connections-dep sys-dm_exec_sessions +sys-dm_exec_sessions-dep sys-dm_hadr_cluster sys-dm_hadr_database_replica_states sys-dm_os_host_info @@ -65,7 +196,9 @@ sys-endpoints sys-extended_properties sys-filetable_system_defined_objects sys-foreign_key_columns +sys-foreign_key_columns-dep sys-foreign_keys +sys-foreign_keys-dep sys-fulltext_catalogs sys-fulltext_index_columns sys-fulltext_languages @@ -73,240 +206,108 @@ sys-fulltext_stoplists sys-identity_columns sys-identity_columns-dep-for-13-x sys-index_columns +sys-index_columns-dep sys-indexes +sys-indexes-dep sys-key_constraints +sys-key_constraints-dep +sys-lock_timeout sys-master_files +sys-max_connections +sys-objects +sys-original_login +sys-procedures +sys-proc_param_helper-dep sys-registered_search_property_lists +sys-schema-name sys-schemas +sys-schemas-dep sys-selective_xml_index_paths sys-server_principals +sys_server_principals_dep_for_13_x sys-sid_binary +sys-spatial_indexes +sys-spatial_index_tessellations sys-sp_databases +sys-sp_databases-dep +sys-sp_pkeys +sys-sp_pkeys-dep +sys-sp_statistics +sys-sp_statistics-dep sys-sp_tables_view -sys-spatial_index_tessellations -sys-spatial_indexes +sys-sp_tables_view-dep +sys-sql_modules_before-14_7-or-15_2 sys-stats +sys-suser_sid +sys-suser_sname sys-synonyms sys-syscharsets sys-syscolumns +sys-syscolumns-dep +sys-sysdatabases sys-sysforeignkeys +sys-sysforeignkeys-dep +sys-sysindexes sys-syslanguages +sys-sysobjects +sys-system_objects-for-13-x sys-system_sql_modules -sys-table_types sys-tables +sys-tables-dep +sys-table_types +sys-table_types-dep +sys-table_types_internal +SYSTEM_USER +sys-trigger_nestlevel sys-triggers sys-types +sys-types-dep +sys-userid-dep sys-views +sys-views-dep sys-xml_indexes sys-xml_schema_collections -sys_all_objects -sys-system_objects-for-13-x -fulltextserviceproperty -is_srvrolemember -msdb-dbo-fn_syspolicy_is_automation_enabled -objectpropertyex -sys-column-property -sys-datefirst -sys-lock_timeout -sys-max_connections -sys-objects -sys-original_login -sys-procedures -sys-schema-name -sys-suser_sid -identity_function -sys-suser_sname -sys-sysdatabases -sys-sysobjects -sys-trigger_nestlevel -routines_definition_before-14_7-or-15_2 -constraint_column_usage -column_domain_usage -sp_describe_first_result_set -schema_resolution_proc -datepart -SYSTEM_USER +table-variable +tdscollation +temp-tables +TestBigInt +TestBinary +TestBIT +TestChar +Test-Computed-Columns +TestDate +TestDatetime +TestDatetime2 +TestDecimal Test-Default-Columns -BABEL-1189 -BABEL-1243 -BABEL-1493 -BABEL-1963 -BABEL-2203 -BABEL-2208 -BABEL-2257 -BABEL-2535 -BABEL-2787-2 -BABEL-2787 -BABEL-2845 -BABEL-2884 -BABEL-2944 -BABEL-3116 -BABEL-3118 -BABEL-3249 -BABEL-3588 -BABEL-3369 -BABEL-3370 -BABEL-383 -BABEL-405 -BABEL-PROCID -babel_trigger -insteadoftriggers_with_transaction -insteadof_nested_trigger_inside_proc -insteadof_nested_trigger_with_dml -nested_trigger_inside_proc -nested_trigger_with_dml -triggers_with_transaction +TestErrorHelperFunctionsUpgrade +TestFloat +Test-Identity-before-14_7-or-15_2 +TestImage +TestInt +TestMoney +TestNotNull +TestNumeric +TestReal +TestSmallDatetime +TestSmallInt +TestSmallMoney Test-sp_addrole Test-sp_addrolemember Test-sp_droprole Test-sp_droprolemember Test-sp_helpdbfixedrole Test-sp_helpsrvrolemember -BABEL-404 -BABEL-493 -BABEL-621 -BABEL-775 -BABEL-1206 -BABEL-1251 -BABEL-1319 -BABEL-1444 -BABEL-1465 -BABEL-1466 -BABEL-1654 -BABEL-1715 -BABEL-2086 -BABEL-3314 -BABEL-TABLEOPTIONS -BABEL-2765 -BABEL-2917 -BABEL-2955 -BABEL-3646-before-14_6 -BABEL-3748-before-14_7 -temp-tables -table-variable -TestNotNull -Test-Identity-before-14_7-or-15_2 -Test-Computed-Columns -babel_char -BABEL-SQUARE -BABEL-728 -babel_function_string -BABEL-2701 -BABEL-1566 -babel_isnumeric -HAS_DBACCESS -BABEL-1475 -BABEL-1510 -BABEL-3213 -BABEL-RAND -BABEL-741 -BABEL-3360 Test-sp_helpuser +TestSQLVariant TestTableType -BABEL-CROSS-DB -BABEL-LOGIN -BABEL-USER -BABEL-ROLE -babelfish_sysdatabases -babelfish_namespace_ext -babelfish_authid_login_ext -babelfish_authid_user_ext -babelfish_inconsistent_metadata -babelfish_migration_mode -schema_resolution_func -BABEL-3147-before-14_5 -collation_tests_arabic -collation_tests_greek -collation_tests_mongolian -collation_tests_polish -collation_tests -BABEL-EXTENDEDPROPERTY -TestErrorHelperFunctionsUpgrade -BABEL-1249 -BABEL-1291 -BABEL-1994-CHAR -BABEL-1994-VARCHAR -BABEL-889 -babel_417 -babel_datatype_sqlvariant -babel_sqlvariant_cast_compare -tdscollation -sp_tablecollations -sys-assemblies -BABEL-LOGIN-USER-EXT -BABEL-1683 -schema_resolution_trigger -sys-sp_pkeys -sys-sp_statistics -BABEL-APPLOCK -BABEL-1438 -BABEL-SP_DATATYPE_INFO -BABEL-SPCOLUMNS -BABEL-SP_TABLES -BABEL-SP_SPECIAL_COLUMNS -BABEL-SP_TABLE_PRIVILIGES -BABEL-SP_STORED_PROCEDURES -BABEL-SP_SPROC_COLUMNS -BABEL-3000 -sys-foreign_key_columns-dep -sys-foreign_keys-dep -sys-indexes-dep -sys-computed_columns-dep -sys-key_constraints-dep -sys-schemas-dep -sys-sp_tables_view-dep -sys-sysforeignkeys-dep -sys-tables-dep -sys-types-dep -sys-views-dep -sys-check_constraints-dep -sys-index_columns-dep -sys-sp_databases-dep -sys-syscolumns-dep -sys-dm_exec_connections-dep -sys-dm_exec_sessions-dep -sys-table_types-dep -sys-sp_pkeys-dep -sys-sp_statistics-dep -sys-proc_param_helper-dep -sys-userid-dep -BABEL-SPCOLUMNS-dep -BABEL-SP_COLUMNS_MANAGED-dep -BABEL-SP_SPECIAL_COLUMNS-dep -BABEL-SP_SPECIAL_COLUMNS_100-dep -BABEL-SP_STORED_PROCEDURES-dep -BABEL-3000-dep -BABEL-3347-before-14_6 -BABEL-3556-before-14_6 -BABEL-3010-before-14_6 -BABEL_GRANT_CONNECT -BABEL-sp_helpdb -BABEL-2795 -BABEL-PG-SYSTEM-FUNCTIONS -BABEL-3655 -sys-table_types_internal -BABEL-CHECK-CONSTRAINT-before-14_6 -BABEL-3640 -sys-sysindexes -ISC-Tables -ISC-Columns -ISC-Table_Constraints -sys_server_principals_dep_for_13_x -sys_database_principals_dep_for_13_x -case_insensitive_collation -bbf_view_def-before-14_5 -sys-sql_modules_before-14_7-or-15_2 -sys-all_sql_modules_before-14_5 -BABEL_OBJECT_ID +TestText +TestTime +TestTinyInt +TestUDD +TestUniqueIdentifier +TestVarChar test_windows_login_before_15_2 -BABEL_OBJECT_NAME -BABEL_SCHEMATA -BABEL-3657 -BABEL-3938 -rowcount -BABEL-1625 -BABEL-3474 -datetime2fromparts +TestXML timefromparts -BABEL-3215 -BABEL-4078-before-14_8-or-15_3 +triggers_with_transaction diff --git a/test/JDBC/upgrade/13_8/schedule b/test/JDBC/upgrade/13_8/schedule index 706eeec068..557f4e06a1 100644 --- a/test/JDBC/upgrade/13_8/schedule +++ b/test/JDBC/upgrade/13_8/schedule @@ -1,63 +1,194 @@ # Schedule File for JDBC Test Framework for local run # 1. Lines starting with '#' will be treated as comments -# 2. To run a postgres command: cmd#!#postgresql#!# +# 2. To run a postgres command: cmd#!#postgresql#!# # 3. To run a T-SQL command: cmd#!#sqlserver#!# -# 4. Keyword "all" is equivalent to running all test files in -# input folder -# 5. To add a test, add test name (without extension, -vu-prepare, -vu-verify and -vu-cleanup. For example if test file name is TestBigInt-vu-prepare.txt write TestBigInt) on a new line +# 4. Keyword "all" is equivalent to running all test files in input folder +# 5. To add a test, add test name (without extension, , and . For example if test file name is TestBigInt.txt write TestBigInt) on a new line # This should be the first test to check there are no duplicated object_ids BABEL-3613 -babelfish_cast_floor -babel_try_parse -TestBigInt -TestBinary -TestBIT -TestChar -TestDate -TestDatetime -TestDatetime2 -TestDecimal -TestFloat -TestImage -TestInt -TestMoney -TestNumeric -TestReal -TestSmallDatetime -TestSmallInt -TestSmallMoney -TestSQLVariant -TestText -TestTime -TestTinyInt -TestUDD -TestUniqueIdentifier -TestVarChar -TestXML +BABEL-1189 +BABEL-1206 +BABEL-1243 +BABEL-1249 +BABEL-1251 +BABEL-1291 +BABEL-1319 +BABEL-1438 +BABEL-1444 +BABEL-1465 +BABEL-1466 +BABEL-1475 +BABEL-1493 +BABEL-1510 +BABEL-1566 +BABEL-1625 +BABEL-1654 +BABEL-1683 +BABEL-1715 +BABEL-1756 +BABEL-1756-dep +BABEL-1963 +BABEL-1994-CHAR +BABEL-1994-VARCHAR +BABEL-2086 +BABEL-2203 +BABEL-2208 +BABEL-2257 +BABEL-2535 +BABEL-2701 +BABEL-2765 +BABEL-2787 +BABEL-2787-2 +BABEL-2795 +BABEL-2845 +BABEL-2884 +BABEL-2917 BABEL-2934 +BABEL-2944 +BABEL-2955 +BABEL-3000 +BABEL-3000-dep +BABEL-3010-before-14_6 +BABEL-3116 +BABEL-3118 BABEL-3121 +BABEL-3147-before-14_5 BABEL-3166 BABEL-3192 -BABEL-3221 BABEL-3204 +BABEL-3213 +BABEL-3215 +BABEL-3221 BABEL-3234 +BABEL-3249 +BABEL-3314 +BABEL-3347-before-14_6 +BABEL-3360 +BABEL-3369 +BABEL-3370 BABEL-3402 +BABEL-3474 +BABEL-3556-before-14_6 +BABEL-3588 +BABEL-3640 +BABEL-3646-before-14_6 +BABEL-3655 +BABEL-3657 +BABEL-3748-before-14_7 +BABEL-383 +BABEL-3938 +BABEL-404 +BABEL-405 +BABEL-4078-before-14_8-or-15_3 +babel_417 +BABEL-493 +BABEL-621 +BABEL-728 +BABEL-741 +BABEL-775 +BABEL-889 +BABEL-APPLOCK +babel_char +BABEL-CHECK-CONSTRAINT-before-14_6 +BABEL-CROSS-DB +babel_datatype_sqlvariant +BABEL-EXTENDEDPROPERTY +babelfish_authid_login_ext +babelfish_authid_user_ext +babelfish_cast_floor +babelfish_inconsistent_metadata +babelfish_migration_mode +babelfish_namespace_ext +babelfish_sysdatabases +babel_function_string +BABEL_GRANT_CONNECT +babel_isnumeric +BABEL-LOGIN +BABEL-LOGIN-USER-EXT +BABEL_OBJECT_ID +BABEL_OBJECT_NAME +BABEL-PG-SYSTEM-FUNCTIONS +BABEL-PROCID +BABEL-RAND +BABEL-ROLE +BABEL_SCHEMATA +BABEL-SPCOLUMNS +BABEL-SPCOLUMNS-dep +BABEL-SP_COLUMNS_MANAGED-dep +BABEL-SP_DATATYPE_INFO +BABEL-sp_helpdb +BABEL-SP_SPECIAL_COLUMNS +BABEL-SP_SPECIAL_COLUMNS_100-dep +BABEL-SP_SPECIAL_COLUMNS-dep +BABEL-SP_SPROC_COLUMNS +BABEL-SP_STORED_PROCEDURES +BABEL-SP_STORED_PROCEDURES-dep +BABEL-SP_TABLE_PRIVILIGES +BABEL-SP_TABLES +babel_sqlvariant_cast_compare +BABEL-SQUARE +BABEL-TABLEOPTIONS +babel_trigger +babel_try_parse +BABEL-USER +bbf_view_def-before-14_5 +case_insensitive_collation +collation_tests +collation_tests_arabic +collation_tests_greek +collation_tests_mongolian +collation_tests_polish +column_domain_usage +constraint_column_usage +datepart +datetime2fromparts +fulltextserviceproperty +HAS_DBACCESS +identity_function +insteadof_nested_trigger_inside_proc +insteadof_nested_trigger_with_dml +insteadoftriggers_with_transaction +ISC-Columns +ISC-Table_Constraints +ISC-Tables +is_srvrolemember +msdb-dbo-fn_syspolicy_is_automation_enabled msdb-dbo-syspolicy_system_health_state +nested_trigger_inside_proc +nested_trigger_with_dml +objectpropertyex +routines_definition_before-14_7-or-15_2 +rowcount +schema_resolution_func +schema_resolution_proc +schema_resolution_trigger +sp_describe_first_result_set +sp_tablecollations sys-all_columns +sys_all_objects sys-all_parameters +sys-all_sql_modules_before-14_5 +sys-assemblies sys-assembly_modules sys-change_tracking_databases sys-change_tracking_tables +sys-check_constraints-dep +sys-column-property sys-columns sys-computed_columns -sys-data_spaces +sys-computed_columns-dep sys-database_files sys-database_filestream_options +sys_database_principals_dep_for_13_x sys-database_recovery_status +sys-data_spaces +sys-datefirst sys-dm_exec_connections +sys-dm_exec_connections-dep sys-dm_exec_sessions +sys-dm_exec_sessions-dep sys-dm_hadr_cluster sys-dm_hadr_database_replica_states sys-dm_os_host_info @@ -65,7 +196,9 @@ sys-endpoints sys-extended_properties sys-filetable_system_defined_objects sys-foreign_key_columns +sys-foreign_key_columns-dep sys-foreign_keys +sys-foreign_keys-dep sys-fulltext_catalogs sys-fulltext_index_columns sys-fulltext_languages @@ -73,240 +206,108 @@ sys-fulltext_stoplists sys-identity_columns sys-identity_columns-dep-for-13-x sys-index_columns +sys-index_columns-dep sys-indexes +sys-indexes-dep sys-key_constraints +sys-key_constraints-dep +sys-lock_timeout sys-master_files +sys-max_connections +sys-objects +sys-original_login +sys-procedures +sys-proc_param_helper-dep sys-registered_search_property_lists +sys-schema-name sys-schemas +sys-schemas-dep sys-selective_xml_index_paths sys-server_principals +sys_server_principals_dep_for_13_x sys-sid_binary +sys-spatial_indexes +sys-spatial_index_tessellations sys-sp_databases +sys-sp_databases-dep +sys-sp_pkeys +sys-sp_pkeys-dep +sys-sp_statistics +sys-sp_statistics-dep sys-sp_tables_view -sys-spatial_index_tessellations -sys-spatial_indexes +sys-sp_tables_view-dep +sys-sql_modules_before-14_7-or-15_2 sys-stats +sys-suser_sid +sys-suser_sname sys-synonyms sys-syscharsets sys-syscolumns +sys-syscolumns-dep +sys-sysdatabases sys-sysforeignkeys +sys-sysforeignkeys-dep +sys-sysindexes sys-syslanguages +sys-sysobjects +sys-system_objects-for-13-x sys-system_sql_modules -sys-table_types sys-tables +sys-tables-dep +sys-table_types +sys-table_types-dep +sys-table_types_internal +SYSTEM_USER +sys-trigger_nestlevel sys-triggers sys-types +sys-types-dep +sys-userid-dep sys-views +sys-views-dep sys-xml_indexes sys-xml_schema_collections -sys_all_objects -sys-system_objects-for-13-x -fulltextserviceproperty -is_srvrolemember -msdb-dbo-fn_syspolicy_is_automation_enabled -objectpropertyex -sys-column-property -sys-datefirst -sys-lock_timeout -sys-max_connections -sys-objects -sys-original_login -sys-procedures -sys-schema-name -sys-suser_sid -identity_function -sys-suser_sname -sys-sysdatabases -sys-sysobjects -sys-trigger_nestlevel -routines_definition_before-14_7-or-15_2 -constraint_column_usage -column_domain_usage -sp_describe_first_result_set -schema_resolution_proc -datepart -SYSTEM_USER +table-variable +tdscollation +temp-tables +TestBigInt +TestBinary +TestBIT +TestChar +Test-Computed-Columns +TestDate +TestDatetime +TestDatetime2 +TestDecimal Test-Default-Columns -BABEL-1189 -BABEL-1243 -BABEL-1493 -BABEL-1963 -BABEL-2203 -BABEL-2208 -BABEL-2257 -BABEL-2535 -BABEL-2787-2 -BABEL-2787 -BABEL-2845 -BABEL-2884 -BABEL-2944 -BABEL-3116 -BABEL-3118 -BABEL-3249 -BABEL-3588 -BABEL-3369 -BABEL-3370 -BABEL-383 -BABEL-405 -BABEL-PROCID -babel_trigger -insteadoftriggers_with_transaction -insteadof_nested_trigger_inside_proc -insteadof_nested_trigger_with_dml -nested_trigger_inside_proc -nested_trigger_with_dml -triggers_with_transaction +TestErrorHelperFunctionsUpgrade +TestFloat +Test-Identity-before-14_7-or-15_2 +TestImage +TestInt +TestMoney +TestNotNull +TestNumeric +TestReal +TestSmallDatetime +TestSmallInt +TestSmallMoney Test-sp_addrole Test-sp_addrolemember Test-sp_droprole Test-sp_droprolemember Test-sp_helpdbfixedrole Test-sp_helpsrvrolemember -BABEL-404 -BABEL-493 -BABEL-621 -BABEL-775 -BABEL-1206 -BABEL-1251 -BABEL-1319 -BABEL-1444 -BABEL-1465 -BABEL-1466 -BABEL-1654 -BABEL-1715 -BABEL-2086 -BABEL-3314 -BABEL-TABLEOPTIONS -BABEL-2765 -BABEL-2917 -BABEL-2955 -BABEL-3646-before-14_6 -BABEL-3748-before-14_7 -temp-tables -table-variable -TestNotNull -Test-Identity-before-14_7-or-15_2 -Test-Computed-Columns -babel_char -BABEL-SQUARE -BABEL-728 -babel_function_string -BABEL-2701 -BABEL-1566 -babel_isnumeric -HAS_DBACCESS -BABEL-1475 -BABEL-1510 -BABEL-3213 -BABEL-RAND -BABEL-741 -BABEL-3360 Test-sp_helpuser +TestSQLVariant TestTableType -BABEL-CROSS-DB -BABEL-LOGIN -BABEL-USER -BABEL-ROLE -babelfish_sysdatabases -babelfish_namespace_ext -babelfish_authid_login_ext -babelfish_authid_user_ext -babelfish_inconsistent_metadata -babelfish_migration_mode -schema_resolution_func -BABEL-3147-before-14_5 -collation_tests_arabic -collation_tests_greek -collation_tests_mongolian -collation_tests_polish -collation_tests -BABEL-EXTENDEDPROPERTY -TestErrorHelperFunctionsUpgrade -BABEL-1249 -BABEL-1291 -BABEL-1994-CHAR -BABEL-1994-VARCHAR -BABEL-889 -babel_417 -babel_datatype_sqlvariant -babel_sqlvariant_cast_compare -tdscollation -sp_tablecollations -sys-assemblies -BABEL-LOGIN-USER-EXT -BABEL-1683 -schema_resolution_trigger -sys-sp_pkeys -sys-sp_statistics -BABEL-APPLOCK -BABEL-1438 -BABEL-SP_DATATYPE_INFO -BABEL-SPCOLUMNS -BABEL-SP_TABLES -BABEL-SP_SPECIAL_COLUMNS -BABEL-SP_TABLE_PRIVILIGES -BABEL-SP_STORED_PROCEDURES -BABEL-SP_SPROC_COLUMNS -BABEL-3000 -sys-foreign_key_columns-dep -sys-foreign_keys-dep -sys-indexes-dep -sys-computed_columns-dep -sys-key_constraints-dep -sys-schemas-dep -sys-sp_tables_view-dep -sys-sysforeignkeys-dep -sys-tables-dep -sys-types-dep -sys-views-dep -sys-check_constraints-dep -sys-index_columns-dep -sys-sp_databases-dep -sys-syscolumns-dep -sys-dm_exec_connections-dep -sys-dm_exec_sessions-dep -sys-table_types-dep -sys-sp_pkeys-dep -sys-sp_statistics-dep -sys-proc_param_helper-dep -sys-userid-dep -BABEL-SPCOLUMNS-dep -BABEL-SP_COLUMNS_MANAGED-dep -BABEL-SP_SPECIAL_COLUMNS-dep -BABEL-SP_SPECIAL_COLUMNS_100-dep -BABEL-SP_STORED_PROCEDURES-dep -BABEL-3000-dep -BABEL-3347-before-14_6 -BABEL-3556-before-14_6 -BABEL-3010-before-14_6 -BABEL_GRANT_CONNECT -BABEL-sp_helpdb -BABEL-2795 -BABEL-PG-SYSTEM-FUNCTIONS -BABEL-3655 -sys-table_types_internal -BABEL-CHECK-CONSTRAINT-before-14_6 -BABEL-3640 -sys-sysindexes -ISC-Tables -ISC-Columns -ISC-Table_Constraints -sys_server_principals_dep_for_13_x -sys_database_principals_dep_for_13_x -case_insensitive_collation -bbf_view_def-before-14_5 -sys-sql_modules_before-14_7-or-15_2 -sys-all_sql_modules_before-14_5 -BABEL_OBJECT_ID +TestText +TestTime +TestTinyInt +TestUDD +TestUniqueIdentifier +TestVarChar test_windows_login_before_15_2 -BABEL_OBJECT_NAME -BABEL_SCHEMATA -BABEL-3657 -BABEL-3938 -rowcount -BABEL-1625 -BABEL-3474 -datetime2fromparts +TestXML timefromparts -BABEL-3215 -BABEL-4078-before-14_8-or-15_3 +triggers_with_transaction diff --git a/test/JDBC/upgrade/13_9/schedule b/test/JDBC/upgrade/13_9/schedule index f12b7d8914..5aa34cb6fd 100644 --- a/test/JDBC/upgrade/13_9/schedule +++ b/test/JDBC/upgrade/13_9/schedule @@ -1,61 +1,195 @@ # Schedule File for JDBC Test Framework for local run # 1. Lines starting with '#' will be treated as comments -# 2. To run a postgres command: cmd#!#postgresql#!# +# 2. To run a postgres command: cmd#!#postgresql#!# # 3. To run a T-SQL command: cmd#!#sqlserver#!# -# 4. Keyword "all" is equivalent to running all test files in -# input folder -# 5. To add a test, add test name (without extension, -vu-prepare, -vu-verify and -vu-cleanup. For example if test file name is TestBigInt-vu-prepare.txt write TestBigInt) on a new line +# 4. Keyword "all" is equivalent to running all test files in input folder +# 5. To add a test, add test name (without extension, , and . For example if test file name is TestBigInt.txt write TestBigInt) on a new line # This should be the first test to check there are no duplicated object_ids BABEL-3613 -TestBigInt -TestBinary -TestBIT -TestChar -TestDate -TestDatetime -TestDatetime2 -TestDecimal -TestFloat -TestImage -TestInt -TestMoney -TestNumeric -TestReal -TestSmallDatetime -TestSmallInt -TestSmallMoney -TestSQLVariant -TestText -TestTime -TestTinyInt -TestUDD -TestUniqueIdentifier -TestVarChar -TestXML +AVG-Aggregate-common +AVG-Aggregate-Dep-before-15-2-or-14-7 +BABEL-1189 +BABEL-1206 +BABEL-1243 +BABEL-1249 +BABEL-1251 +BABEL-1291 +BABEL-1319 +BABEL-1438 +BABEL-1444 +BABEL-1465 +BABEL-1466 +BABEL-1475 +BABEL-1493 +BABEL-1510 +BABEL-1566 +BABEL-1625 +BABEL-1654 +BABEL-1683 +BABEL-1715 +BABEL-1963 +BABEL-1994-CHAR +BABEL-1994-VARCHAR +BABEL-2086 +BABEL-2203 +BABEL-2208 +BABEL-2257 +BABEL-2535 +BABEL-2701 +BABEL-2765 +BABEL-2787 +BABEL-2787-2 +BABEL-2795 +BABEL-2845 +BABEL-2884 +BABEL-2917 BABEL-2934 +BABEL-2944 +BABEL-2955 +BABEL-3000 +BABEL-3000-dep +BABEL-3010-before-14_6 +BABEL-3116 +BABEL-3118 BABEL-3121 +BABEL-3147-before-14_5 BABEL-3166 BABEL-3192 -BABEL-3221 BABEL-3204 +BABEL-3213 +BABEL-3215 +BABEL-3221 BABEL-3234 +BABEL-3249 +BABEL-3314 +BABEL-3347-before-14_6 +BABEL-3360 +BABEL-3369 +BABEL-3370 BABEL-3402 +BABEL-3474 +BABEL-3556-before-14_6 +BABEL-3588 +BABEL-3640 +BABEL-3655 +BABEL-3657 +BABEL-3748-before-14_7 +BABEL-383 +BABEL-3938 +BABEL-404 +BABEL-405 +BABEL-4078-before-14_8-or-15_3 +babel_417 +BABEL-493 +BABEL-621 +BABEL-728 +BABEL-741 +BABEL-775 +BABEL-889 +BABEL-APPLOCK +babel_char +BABEL-CHECK-CONSTRAINT-before-14_6 +BABEL-CROSS-DB +babel_datatype_sqlvariant +BABEL-EXTENDEDPROPERTY +babelfish_authid_login_ext +babelfish_authid_user_ext +babelfish_cast_floor +babelfish_inconsistent_metadata +babelfish_migration_mode +babelfish_namespace_ext +babelfish_sysdatabases +babel_function_string +BABEL_GRANT_CONNECT +babel_isnumeric +BABEL-LOGIN +BABEL-LOGIN-USER-EXT +BABEL_OBJECT_ID +BABEL_OBJECT_NAME +BABEL-PG-SYSTEM-FUNCTIONS +BABEL-PROCID +BABEL-RAND +BABEL-ROLE +BABEL_SCHEMATA +BABEL-SPCOLUMNS +BABEL-SPCOLUMNS-dep +BABEL-SP_COLUMNS_MANAGED-dep +BABEL-SP_DATATYPE_INFO +BABEL-SP_FKEYS +BABEL-SP_FKEYS-dep +BABEL-sp_helpdb +BABEL-SP_SPECIAL_COLUMNS +BABEL-SP_SPECIAL_COLUMNS_100-dep +BABEL-SP_SPECIAL_COLUMNS-dep +BABEL-SP_SPROC_COLUMNS +BABEL-SP_STORED_PROCEDURES +BABEL-SP_STORED_PROCEDURES-dep +BABEL-SP_TABLE_PRIVILIGES +BABEL-SP_TABLES +babel_sqlvariant_cast_compare +BABEL-SQUARE +BABEL-TABLEOPTIONS +babel_trigger +babel_try_parse +BABEL-USER +bbf_view_def-before-14_5 +case_insensitive_collation +collation_tests +collation_tests_arabic +collation_tests_greek +collation_tests_mongolian +collation_tests_polish +column_domain_usage +constraint_column_usage +datepart +datetime2fromparts +fulltextserviceproperty +HAS_DBACCESS +identity_function +insteadof_nested_trigger_inside_proc +insteadof_nested_trigger_with_dml +insteadoftriggers_with_transaction +ISC-Columns +ISC-Table_Constraints +ISC-Tables +is_srvrolemember +msdb-dbo-fn_syspolicy_is_automation_enabled msdb-dbo-syspolicy_system_health_state +nested_trigger_inside_proc +nested_trigger_with_dml +objectpropertyex +routines_definition_before-14_7-or-15_2 +rowcount +schema_resolution_func +schema_resolution_proc +schema_resolution_trigger +sp_describe_first_result_set +sp_tablecollations sys-all_columns +sys_all_objects sys-all_parameters +sys-all_sql_modules_before-14_5 +sys-assemblies sys-assembly_modules sys-change_tracking_databases sys-change_tracking_tables +sys-check_constraints-dep +sys-column-property sys-columns sys-computed_columns -sys-data_spaces +sys-computed_columns-dep sys-database_files sys-database_filestream_options +sys_database_principals_dep_for_13_x sys-database_recovery_status +sys-data_spaces +sys-datefirst sys-dm_exec_connections +sys-dm_exec_connections-dep sys-dm_exec_sessions +sys-dm_exec_sessions-dep sys-dm_hadr_cluster sys-dm_hadr_database_replica_states sys-dm_os_host_info @@ -63,253 +197,118 @@ sys-endpoints sys-extended_properties sys-filetable_system_defined_objects sys-foreign_key_columns +sys-foreign_key_columns-dep sys-foreign_keys +sys-foreign_keys-dep sys-fulltext_catalogs sys-fulltext_index_columns sys-fulltext_languages sys-fulltext_stoplists sys-identity_columns +sys-identity_columns-dep-for-13-x sys-index_columns +sys-index_columns-dep sys-indexes +sys-indexes-dep sys-key_constraints +sys-key_constraints-dep +sys-lock_timeout sys-master_files +sys-max_connections +sys-objects +sys-original_login +sys-procedures +sys-proc_param_helper-dep sys-registered_search_property_lists +sys-schema-name sys-schemas +sys-schemas-dep sys-selective_xml_index_paths sys-server_principals +sys_server_principals_dep_for_13_x sys-sid_binary +sys-spatial_indexes +sys-spatial_index_tessellations sys-sp_databases +sys-sp_databases-dep +sys-sp_pkeys +sys-sp_pkeys-dep +sys-sp_statistics +sys-sp_statistics-dep sys-sp_tables_view -sys-spatial_index_tessellations -sys-spatial_indexes +sys-sp_tables_view-dep +sys-sql_modules_before-14_7-or-15_2 sys-stats +sys-suser_sid +sys-suser_sname sys-synonyms sys-syscharsets sys-syscolumns +sys-syscolumns-dep +sys-sysdatabases sys-sysforeignkeys +sys-sysforeignkeys-dep +sys-sysindexes sys-syslanguages +sys-sysobjects +sys-system_objects-for-13-x sys-system_sql_modules -sys-table_types sys-tables +sys-tables-dep +sys-table_types +sys-table_types-dep +sys-table_types_internal +SYSTEM_USER +sys-trigger_nestlevel sys-triggers sys-types +sys-types-dep +sys-userid-dep sys-views +sys-views-dep sys-xml_indexes sys-xml_schema_collections -sys_all_objects -sys-system_objects-for-13-x -fulltextserviceproperty -is_srvrolemember -msdb-dbo-fn_syspolicy_is_automation_enabled -objectpropertyex -sys-column-property -sys-datefirst -sys-lock_timeout -sys-max_connections -sys-objects -sys-original_login -sys-procedures -sys-schema-name -sys-suser_sid -identity_function -sys-suser_sname -sys-sysdatabases -sys-sysobjects -sys-trigger_nestlevel -routines_definition_before-14_7-or-15_2 -constraint_column_usage -column_domain_usage -sp_describe_first_result_set -schema_resolution_proc -datepart -SYSTEM_USER +table-variable +tdscollation +temp-tables +TestBigInt +TestBinary +TestBIT +TestChar +Test-Computed-Columns +TestDate +TestDatetime +TestDatetime2 +TestDecimal Test-Default-Columns -BABEL-1189 -BABEL-1243 -BABEL-1493 -BABEL-1963 -BABEL-2203 -BABEL-2208 -BABEL-2257 -BABEL-2535 -BABEL-2787-2 -BABEL-2787 -BABEL-2845 -BABEL-2884 -BABEL-2944 -BABEL-3116 -BABEL-3118 -BABEL-3249 -BABEL-3588 -BABEL-3369 -BABEL-3370 -BABEL-383 -BABEL-405 -BABEL-PROCID -babel_trigger -insteadoftriggers_with_transaction -insteadof_nested_trigger_inside_proc -insteadof_nested_trigger_with_dml -nested_trigger_inside_proc -nested_trigger_with_dml -triggers_with_transaction +TestErrorHelperFunctionsUpgrade +TestFloat +Test-Identity-before-14_7-or-15_2 +TestImage +TestInt +TestMoney +TestNotNull +TestNumeric +TestReal +TestSmallDatetime +TestSmallInt +TestSmallMoney Test-sp_addrole Test-sp_addrolemember Test-sp_droprole Test-sp_droprolemember Test-sp_helpdbfixedrole Test-sp_helpsrvrolemember -BABEL-3748-before-14_7 -BABEL-404 -BABEL-493 -BABEL-621 -BABEL-775 -BABEL-1206 -BABEL-1251 -BABEL-1319 -BABEL-1444 -BABEL-1465 -BABEL-1466 -BABEL-1654 -BABEL-1715 -BABEL-2086 -BABEL-3314 -BABEL-TABLEOPTIONS -BABEL-2765 -BABEL-2917 -BABEL-2955 -temp-tables -table-variable -TestNotNull -Test-Identity-before-14_7-or-15_2 -Test-Computed-Columns -babel_char -BABEL-SQUARE -BABEL-728 -babel_function_string -BABEL-2701 -BABEL-1566 -babel_isnumeric -HAS_DBACCESS -BABEL-1475 -BABEL-1510 -BABEL-3213 -BABEL-RAND -BABEL-741 -BABEL-3360 Test-sp_helpuser +TestSQLVariant TestTableType -BABEL-CROSS-DB -BABEL-LOGIN -BABEL-USER -BABEL-ROLE -babelfish_sysdatabases -babelfish_namespace_ext -babelfish_authid_login_ext -babelfish_authid_user_ext -babelfish_inconsistent_metadata -babelfish_migration_mode -schema_resolution_func -BABEL-3147-before-14_5 -collation_tests_arabic -collation_tests_greek -collation_tests_mongolian -collation_tests_polish -collation_tests -BABEL-EXTENDEDPROPERTY -TestErrorHelperFunctionsUpgrade -BABEL-1249 -BABEL-1291 -BABEL-1994-CHAR -BABEL-1994-VARCHAR -BABEL-889 -babel_417 -babel_datatype_sqlvariant -babel_sqlvariant_cast_compare -tdscollation -sp_tablecollations -sys-assemblies -BABEL-LOGIN-USER-EXT -BABEL-1683 -schema_resolution_trigger -sys-sp_pkeys -sys-sp_statistics -BABEL-APPLOCK -BABEL-1438 -BABEL-SP_DATATYPE_INFO -BABEL-SPCOLUMNS -BABEL-SP_TABLES -BABEL-SP_SPECIAL_COLUMNS -BABEL-SP_TABLE_PRIVILIGES -BABEL-SP_STORED_PROCEDURES -BABEL-SP_SPROC_COLUMNS -BABEL-3000 -sys-foreign_key_columns-dep -sys-foreign_keys-dep -sys-identity_columns-dep-for-13-x -sys-indexes-dep -sys-key_constraints-dep -sys-schemas-dep -sys-sp_tables_view-dep -sys-sysforeignkeys-dep -sys-tables-dep -sys-types-dep -sys-views-dep -sys-check_constraints-dep -sys-computed_columns-dep -sys-index_columns-dep -sys-sp_databases-dep -sys-syscolumns-dep -sys-dm_exec_connections-dep -sys-dm_exec_sessions-dep -sys-table_types-dep -sys-sp_pkeys-dep -sys-sp_statistics-dep -sys-proc_param_helper-dep -sys-userid-dep -BABEL-SPCOLUMNS-dep -BABEL-SP_COLUMNS_MANAGED-dep -BABEL-SP_SPECIAL_COLUMNS-dep -BABEL-SP_SPECIAL_COLUMNS_100-dep -BABEL-SP_STORED_PROCEDURES-dep -BABEL-3000-dep -BABEL-3347-before-14_6 -BABEL-3556-before-14_6 -BABEL-3010-before-14_6 -BABEL_GRANT_CONNECT -BABEL-sp_helpdb -BABEL-2795 -BABEL-PG-SYSTEM-FUNCTIONS -BABEL-3655 -sys-table_types_internal -BABEL-CHECK-CONSTRAINT-before-14_6 -BABEL-3640 -sys_server_principals_dep_for_13_x -sys_database_principals_dep_for_13_x -babelfish_cast_floor -babel_try_parse -sys-sysindexes -ISC-Tables -ISC-Columns -ISC-Table_Constraints -case_insensitive_collation -AVG-Aggregate-common -AVG-Aggregate-Dep-before-15-2-or-14-7 -bbf_view_def-before-14_5 -sys-sql_modules_before-14_7-or-15_2 -sys-all_sql_modules_before-14_5 -BABEL_OBJECT_ID +TestText +TestTime +TestTinyInt +TestUDD +TestUniqueIdentifier +TestVarChar test_windows_login_before_15_2 -BABEL_SCHEMATA -BABEL-SP_FKEYS -BABEL-SP_FKEYS-dep -BABEL_OBJECT_NAME -BABEL-3657 -BABEL-3938 -rowcount -BABEL-1625 -BABEL-3474 -datetime2fromparts +TestXML timefromparts -BABEL-3215 -BABEL-4078-before-14_8-or-15_3 +triggers_with_transaction diff --git a/test/JDBC/upgrade/14_3/schedule b/test/JDBC/upgrade/14_3/schedule index c4ad2656ee..e7fe2f889e 100644 --- a/test/JDBC/upgrade/14_3/schedule +++ b/test/JDBC/upgrade/14_3/schedule @@ -1,66 +1,207 @@ # Schedule File for JDBC Test Framework for local run # 1. Lines starting with '#' will be treated as comments -# 2. To run a postgres command: cmd#!#postgresql#!# +# 2. To run a postgres command: cmd#!#postgresql#!# # 3. To run a T-SQL command: cmd#!#sqlserver#!# -# 4. Keyword "all" is equivalent to running all test files in -# input folder -# 5. To add a test, add test name (without extension, -vu-prepare, -vu-verify and -vu-cleanup. For example if test file name is TestBigInt-vu-prepare.txt write TestBigInt) on a new line +# 4. Keyword "all" is equivalent to running all test files in input folder +# 5. To add a test, add test name (without extension, , and . For example if test file name is TestBigInt.txt write TestBigInt) on a new line # This should be the first test to check there are no duplicated object_ids BABEL-3613 -babelfish_cast_floor -babel_try_parse -TestBigInt -TestBinary -TestBIT -TestChar -TestDate -TestDatetime -TestDatetime2 -TestDecimal -TestFloat -TestImage -TestInt -TestMoney -TestNumeric -TestReal -TestSmallDatetime -TestSmallInt -TestSmallMoney -TestSQLVariant -TestText -TestTime -TestTinyInt -TestUDD -TestUniqueIdentifier -TestVarChar -TestXML +AVG-Aggregate-common +AVG-Aggregate-Dep-before-15-2-or-14-7 +BABEL-1189 +BABEL-1206 +BABEL-1243 +BABEL-1249 +BABEL-1251 +BABEL-1291 +BABEL-1319 +BABEL-1438 +BABEL-1444 +BABEL-1465 +BABEL-1466 +BABEL-1475 +BABEL-1493 +BABEL-1510 +BABEL-1566 +BABEL-1625 +BABEL-1654 +BABEL-1683 +BABEL-1715 +BABEL-1756 +BABEL-1756-dep +BABEL-1963 +BABEL-1994-CHAR +BABEL-1994-VARCHAR +BABEL-2086 +BABEL-2203 +BABEL-2208 +BABEL-2257 +BABEL-2535 +BABEL-2701 +BABEL-2765 +BABEL-2787 +BABEL-2787-2 +BABEL-2795 +BABEL-2845 +BABEL-2884 +BABEL-2917 BABEL-2934 +BABEL-2944 +BABEL-2955 +BABEL-3000 +BABEL-3000-dep +BABEL-3010-before-14_6 +BABEL-3116 +BABEL-3118 BABEL-3121 +BABEL-3147-before-14_5 BABEL-3166 BABEL-3192 -BABEL-3221 BABEL-3204 +BABEL-3213 +BABEL-3215 +BABEL-3221 BABEL-3234 -BABEL-3402 +BABEL-3249 +BABEL-3314 +BABEL-3347-before-14_6 +BABEL-3360 BABEL-3369 BABEL-3370 -sys-server_principals +BABEL-3402 +BABEL-3474 +BABEL-3556-before-14_6 +BABEL-3588 +BABEL-3640 +BABEL-3646-before-14_6 +BABEL-3655 +BABEL-3657 +BABEL-3748-before-14_7 +BABEL-3801 +BABEL-3818 +BABEL-383 +BABEL-3938 +BABEL-404 +BABEL-405 +BABEL-4078-before-14_8-or-15_3 +babel_417 +BABEL-493 +BABEL-621 +BABEL-728 +BABEL-741 +BABEL-775 +BABEL-889 +BABEL-APPLOCK +babel_char +BABEL-CHECK-CONSTRAINT-before-14_6 +BABEL-CROSS-DB +babel_datatype_sqlvariant +BABEL-EXTENDEDPROPERTY +babelfish_authid_login_ext +babelfish_authid_user_ext +babelfish_cast_floor +babelfish_inconsistent_metadata +babelfish_migration_mode +babelfish_namespace_ext +babelfish_sysdatabases +babel_function_string +BABEL_GRANT_CONNECT +babel_isnumeric +BABEL-LOGIN +BABEL-LOGIN-USER-EXT +BABEL_OBJECT_ID +BABEL_OBJECT_NAME +BABEL-PG-SYSTEM-FUNCTIONS +BABEL-PROCID +BABEL-RAND +BABEL-ROLE +BABEL-ROLE-MEMBER +BABEL_SCHEMATA +BABEL-SPCOLUMNS +BABEL-SPCOLUMNS-dep +BABEL-SP_COLUMNS_MANAGED-dep +BABEL-SP_DATATYPE_INFO +BABEL-SP_FKEYS +BABEL-SP_FKEYS-dep +BABEL-sp_helpdb +BABEL-SP_SPECIAL_COLUMNS +BABEL-SP_SPECIAL_COLUMNS_100-dep +BABEL-SP_SPECIAL_COLUMNS-dep +BABEL-SP_SPROC_COLUMNS +BABEL-SP_SPROC_COLUMNS_100-dep +BABEL-SP_SPROC_COLUMNS-dep +BABEL-SP_STORED_PROCEDURES +BABEL-SP_STORED_PROCEDURES-dep +BABEL-SP_TABLE_PRIVILIGES +BABEL-SP_TABLES +babel_sqlvariant_cast_compare +BABEL-SQUARE +BABEL-TABLEOPTIONS +babel_trigger +babel_try_parse +BABEL-USER +bbf_view_def-before-14_5 +binary-index +case_insensitive_collation +collation_tests +collation_tests_arabic +collation_tests_greek +collation_tests_mongolian +collation_tests_polish +column_domain_usage +constraint_column_usage +datepart +datetime2fromparts +fulltextserviceproperty +HAS_DBACCESS +identity_function +insteadof_nested_trigger_inside_proc +insteadof_nested_trigger_with_dml +insteadoftriggers_with_transaction +ISC-Table_Constraints +ISC-Tables +is_srvrolemember +msdb-dbo-fn_syspolicy_is_automation_enabled msdb-dbo-syspolicy_system_health_state +nested_trigger_inside_proc +nested_trigger_with_dml +objectpropertyex +openjson +routines_definition_before-14_7-or-15_2 +rowcount +schema_resolution_func +schema_resolution_proc +schema_resolution_trigger +sp_describe_first_result_set +sp_tablecollations sys-all_columns +sys_all_objects +sys_all_objects-dep sys-all_parameters +sys-all_sql_modules_before-14_5 +sys-all_sql_modules-dep +sys-assemblies sys-assembly_modules sys-change_tracking_databases sys-change_tracking_tables +sys-check_constraints-dep +sys-column-property sys-columns +sys-columns-dep sys-computed_columns -sys-data_spaces +sys-computed_columns-dep sys-database_files sys-database_filestream_options +sys_database_principals_dep sys-database_recovery_status +sys-data_spaces +sys-datefirst sys-dm_exec_connections +sys-dm_exec_connections-dep sys-dm_exec_sessions +sys-dm_exec_sessions-dep sys-dm_hadr_cluster sys-dm_hadr_database_replica_states sys-dm_os_host_info @@ -68,264 +209,123 @@ sys-endpoints sys-extended_properties sys-filetable_system_defined_objects sys-foreign_key_columns +sys-foreign_key_columns-dep sys-foreign_keys +sys-foreign_keys-dep sys-fulltext_catalogs sys-fulltext_index_columns sys-fulltext_languages sys-fulltext_stoplists +sys-has_perms_by_name +sys-has_perms_by_name-dep sys-identity_columns +sys-identity_columns-dep-for-14-3 sys-index_columns +sys-index_columns-dep sys-indexes +sys-indexes-dep sys-key_constraints +sys-key_constraints-dep +sys-lock_timeout sys-master_files +sys-max_connections +sys-objects +sys-original_login +sys-procedures +sys-proc_param_helper-dep sys-registered_search_property_lists +sys-schema-name sys-schemas +sys-schemas-dep sys-selective_xml_index_paths +sys-server_principals +sys_server_principals_dep sys-sid_binary +sys-spatial_indexes +sys-spatial_index_tessellations sys-sp_databases +sys-sp_databases-dep +sys-sp_pkeys +sys-sp_pkeys-dep +sys-sp_statistics +sys-sp_statistics-dep sys-sp_tables_view -sys-spatial_index_tessellations -sys-spatial_indexes +sys-sp_tables_view-dep +sys-sql_modules_before-14_7-or-15_2 +sys-sql_modules-dep sys-stats +sys-suser_sid +sys-suser_sname sys-synonyms sys-syscharsets sys-syscolumns +sys-syscolumns-dep +sys-sysdatabases sys-sysforeignkeys +sys-sysforeignkeys-dep +sys-sysindexes sys-syslanguages +sys-sysobjects +sys-system_objects sys-system_sql_modules sys-system_sql_modules-dep -sys-table_types sys-tables +sys-tables-dep +sys-table_types +sys-table_types-dep +sys-table_types_internal +SYSTEM_USER +sys-trigger_nestlevel sys-triggers +sys-types-dep +sys-userid-dep sys-views +sys-views-dep sys-xml_indexes sys-xml_schema_collections -sys_all_objects -fulltextserviceproperty -is_srvrolemember -msdb-dbo-fn_syspolicy_is_automation_enabled -# Takes too long, tracking with BABEL-3675 -# objectproperty -objectpropertyex -sys-column-property -sys-datefirst -sys-lock_timeout -sys-max_connections -sys-objects -sys-original_login -sys-procedures -sys-schema-name -sys-suser_sid -sys-suser_sname -sys-sysdatabases -sys-sysobjects -sys-trigger_nestlevel -identity_function -routines_definition_before-14_7-or-15_2 -constraint_column_usage -column_domain_usage -sp_describe_first_result_set -schema_resolution_proc -datepart -SYSTEM_USER +table-variable +tdscollation +temp-tables +TestBigInt +TestBinary +TestBIT +TestChar +Test-Computed-Columns +TestDate +TestDatetime +TestDatetime2 +TestDecimal Test-Default-Columns -BABEL-1189 -BABEL-1243 -BABEL-1493 -BABEL-1963 -BABEL-2203 -BABEL-2208 -BABEL-2257 -BABEL-2535 -BABEL-2787-2 -BABEL-2787 -BABEL-2845 -BABEL-2884 -BABEL-2944 -BABEL-3116 -BABEL-3118 -BABEL-3249 -BABEL-3588 -BABEL-383 -BABEL-405 -BABEL-PROCID -babel_trigger -insteadoftriggers_with_transaction -insteadof_nested_trigger_inside_proc -insteadof_nested_trigger_with_dml -nested_trigger_inside_proc -nested_trigger_with_dml -triggers_with_transaction +TestErrorHelperFunctionsUpgrade +TestFloat +Test-Identity-before-14_7-or-15_2 +TestImage +TestInt +TestMoney +TestNotNull +TestNumeric +TestReal +TestSmallDatetime +TestSmallInt +TestSmallMoney Test-sp_addrole Test-sp_addrolemember Test-sp_droprole Test-sp_droprolemember Test-sp_helpdbfixedrole +Test-sp_helprole-dep +Test-sp_helprolemember-dep Test-sp_helpsrvrolemember -BABEL-404 -BABEL-493 -BABEL-621 -BABEL-775 -BABEL-1206 -BABEL-1251 -BABEL-1319 -BABEL-1444 -BABEL-1465 -BABEL-1466 -BABEL-1654 -BABEL-1715 -BABEL-2086 -BABEL-3314 -BABEL-TABLEOPTIONS -BABEL-2765 -BABEL-2917 -BABEL-2955 -BABEL-3646-before-14_6 -BABEL-3748-before-14_7 -temp-tables -table-variable -TestNotNull -Test-Identity-before-14_7-or-15_2 -Test-Computed-Columns -babel_char -BABEL-SQUARE -BABEL-728 -babel_function_string -BABEL-2701 -BABEL-1566 -babel_isnumeric -HAS_DBACCESS -BABEL-1475 -BABEL-1510 -BABEL-3213 -BABEL-RAND -BABEL-741 -BABEL-3360 -BABEL-ROLE-MEMBER Test-sp_helpuser +TestSQLVariant TestTableType -BABEL-CROSS-DB -BABEL-LOGIN -BABEL-USER -BABEL-ROLE -babelfish_sysdatabases -babelfish_namespace_ext -babelfish_authid_login_ext -babelfish_authid_user_ext -babelfish_inconsistent_metadata -babelfish_migration_mode -schema_resolution_func -BABEL-3147-before-14_5 -collation_tests_arabic -collation_tests_greek -collation_tests_mongolian -collation_tests_polish -collation_tests -BABEL-EXTENDEDPROPERTY -TestErrorHelperFunctionsUpgrade -BABEL-1249 -BABEL-1291 -BABEL-1994-CHAR -BABEL-1994-VARCHAR -BABEL-889 -babel_417 -babel_datatype_sqlvariant -babel_sqlvariant_cast_compare -tdscollation -sp_tablecollations -sys-assemblies -BABEL-LOGIN-USER-EXT -BABEL-1683 -schema_resolution_trigger -sys-sp_pkeys -sys-sp_statistics -BABEL-1756 -BABEL-APPLOCK -BABEL-1438 -BABEL-SP_TABLES -BABEL-SP_SPECIAL_COLUMNS -BABEL-SP_TABLE_PRIVILIGES -BABEL-SP_STORED_PROCEDURES -BABEL-SP_SPROC_COLUMNS -BABEL-3000 -sys_all_objects-dep -sys-columns-dep -sys-foreign_key_columns-dep -sys-foreign_keys-dep -sys-identity_columns-dep-for-14-3 -sys-indexes-dep -sys-key_constraints-dep -sys-schemas-dep -sys-sp_tables_view-dep -sys-sysforeignkeys-dep -sys-tables-dep -sys-types-dep -sys-views-dep -sys-check_constraints-dep -sys-computed_columns-dep -sys-index_columns-dep -sys-sp_databases-dep -sys-syscolumns-dep -sys-dm_exec_connections-dep -sys-dm_exec_sessions-dep -sys-table_types-dep -sys-all_sql_modules-dep -sys-sql_modules-dep -sys-sp_pkeys-dep -sys-sp_statistics-dep -sys-proc_param_helper-dep -sys-userid-dep -BABEL-1756-dep -BABEL-SP_COLUMNS_MANAGED-dep -BABEL-SP_SPECIAL_COLUMNS-dep -BABEL-SP_SPECIAL_COLUMNS_100-dep -BABEL-SP_STORED_PROCEDURES-dep -BABEL-SP_SPROC_COLUMNS-dep -BABEL-SP_SPROC_COLUMNS_100-dep -BABEL-3000-dep -Test-sp_helprole-dep -Test-sp_helprolemember-dep -BABEL-3347-before-14_6 -BABEL-3556-before-14_6 -BABEL-3010-before-14_6 -BABEL_GRANT_CONNECT -BABEL-sp_helpdb -BABEL-2795 -BABEL-PG-SYSTEM-FUNCTIONS -BABEL-3655 -sys-table_types_internal -BABEL-CHECK-CONSTRAINT-before-14_6 -BABEL-3640 -openjson -sys-sysindexes -sys-system_objects -ISC-Tables -ISC-Table_Constraints -sys_server_principals_dep -sys_database_principals_dep -BABEL-3801 -case_insensitive_collation -sys-has_perms_by_name -sys-has_perms_by_name-dep -AVG-Aggregate-common -AVG-Aggregate-Dep-before-15-2-or-14-7 -bbf_view_def-before-14_5 -sys-sql_modules_before-14_7-or-15_2 -sys-all_sql_modules_before-14_5 -BABEL_OBJECT_ID +TestText +TestTime +TestTinyInt +TestUDD +TestUniqueIdentifier +TestVarChar test_windows_login_before_15_2 -BABEL_SCHEMATA -BABEL-SP_FKEYS -BABEL-SP_FKEYS-dep -BABEL_OBJECT_NAME -BABEL-3657 -BABEL-3938 -binary-index -rowcount -BABEL-1625 -BABEL-3474 -BABEL-3818 -datetime2fromparts +TestXML timefromparts -BABEL-3215 -BABEL-4078-before-14_8-or-15_3 +triggers_with_transaction diff --git a/test/JDBC/upgrade/14_5/schedule b/test/JDBC/upgrade/14_5/schedule index 6236da993d..45cb0fb9fc 100644 --- a/test/JDBC/upgrade/14_5/schedule +++ b/test/JDBC/upgrade/14_5/schedule @@ -1,345 +1,345 @@ # Schedule File for JDBC Test Framework for local run # 1. Lines starting with '#' will be treated as comments -# 2. To run a postgres command: cmd#!#postgresql#!# +# 2. To run a postgres command: cmd#!#postgresql#!# # 3. To run a T-SQL command: cmd#!#sqlserver#!# -# 4. Keyword "all" is equivalent to running all test files in -# input folder -# 5. To add a test, add test name (without extension, -vu-prepare, -vu-verify and -vu-cleanup. For example if test file name is TestBigInt-vu-prepare.txt write TestBigInt) on a new line +# 4. Keyword "all" is equivalent to running all test files in input folder +# 5. To add a test, add test name (without extension, , and . For example if test file name is TestBigInt.txt write TestBigInt) on a new line # This should be the first test to check there are no duplicated object_ids BABEL-3613 -babelfish_cast_floor -babel_try_parse -TestBigInt -TestBinary -TestBIT -TestChar -TestDatetime2 -TestDatetime -TestDate -TestDecimal -TestFloat -TestImage -TestInt -TestMoney -TestNumeric -TestReal -TestSmallDatetime -TestSmallInt -TestSmallMoney -TestSQLVariant -TestText -TestTime -TestTinyInt -TestUDD -TestUniqueIdentifier -TestVarChar -TestXML -forxml -sys-assembly_types -sys-database_mirroring -sys-databases -sys-numbered_procedures -BABEL-3121 -sys-events -sys-suser_sid -sys-trigger_events -BABEL-3166 -BABEL-3192 -BABEL-3221 -BABEL-3204 -BABEL-3234 -BABEL-3402 -BABEL-3646-before-14_6 -BABEL-3748-before-14_7 -cast_numeric_types_to_datetime -routines_definition_before-14_7-or-15_2 -column_domain_usage -constraint_column_usage -sp_describe_first_result_set -sys-host_name -SYSTEM_USER -indexproperty -msdb-dbo-syspolicy_configuration -sys-all_views -datepart -sys-server_principals -fulltextserviceproperty -is_srvrolemember -msdb-dbo-fn_syspolicy_is_automation_enabled -# Takes too long, tracking with BABEL-3675 -# objectproperty -objectpropertyex -sys-column-property -sys-configurations -sys-datefirst -sys-lock_timeout -sys-max_connections -sys-original_login -sys-schema-name -sys-objects -sys-procedures -sys-sysdatabases -sys-sysobjects -sys-trigger_nestlevel -schema_resolution_proc -BABEL-404 -BABEL-493 -BABEL-621 -BABEL-775 +AVG-Aggregate-common +AVG-Aggregate-Dep-before-15-2-or-14-7 +BABEL-1189 BABEL-1206 +BABEL-1243 +BABEL-1249 BABEL-1251 +BABEL-1291 BABEL-1319 +BABEL-1438 BABEL-1444 BABEL-1465 BABEL-1466 +BABEL-1475 +BABEL-1510 +BABEL-1566 +BABEL-1625 BABEL-1654 +BABEL-1683 BABEL-1715 -BABEL-2086 -BABEL-3314 -BABEL-TABLEOPTIONS -BABEL-2765 -BABEL-2917 -BABEL-2955 -temp-tables -table-variable -TestNotNull -Test-Identity-before-14_7-or-15_2 -Test-Computed-Columns -BABEL-1189 -BABEL-1243 +BABEL-1756 +BABEL-1756-dep BABEL-1963 +BABEL-1994-CHAR +BABEL-1994-VARCHAR +BABEL-2086 BABEL-2203 BABEL-2208 BABEL-2257 BABEL-2535 -BABEL-2787-2 +BABEL-2701 +BABEL-2765 BABEL-2787 +BABEL-2787-2 +BABEL-2795 BABEL-2845 BABEL-2884 +BABEL-2917 BABEL-2944 +BABEL-2955 +BABEL-3000 +BABEL-3000-dep +BABEL-3010-before-14_6 BABEL-3116 BABEL-3118 +BABEL-3121 +BABEL-3147 +BABEL-3166 +BABEL-3192 +BABEL-3204 +BABEL-3213 +BABEL-3215 +BABEL-3221 +BABEL-3234 BABEL-3249 -BABEL-3588 +BABEL-3314 +BABEL-3347-before-14_6 +BABEL-3360 BABEL-3369 BABEL-3370 +BABEL-3402 +BABEL-3474 +BABEL-3556-before-14_6 +BABEL-3588 +BABEL-3640 +BABEL-3646-before-14_6 +BABEL-3655 +BABEL-3657 +BABEL-3748-before-14_7 +BABEL-3801 +BABEL-3818 BABEL-383 +BABEL-3938 +BABEL-404 BABEL-405 -BABEL-PROCID -babel_trigger -insteadoftriggers_with_transaction -insteadof_nested_trigger_inside_proc -insteadof_nested_trigger_with_dml -nested_trigger_inside_proc -nested_trigger_with_dml -triggers_with_transaction -Test-sp_addrole -Test-sp_addrolemember -Test-sp_droprole -Test-sp_droprolemember -Test-sp_helpdbfixedrole -Test-sp_helpsrvrolemember -Test-sp_helpuser -TestTableType +BABEL-4078-before-14_8-or-15_3 +babel_417 +BABEL-493 +BABEL-621 +BABEL-728 +BABEL-741 +BABEL-775 +BABEL-889 +BABEL-APPLOCK +babel_char +BABEL-CHECK-CONSTRAINT-before-14_6 BABEL-CROSS-DB -BABEL-LOGIN -BABEL-USER -BABEL-ROLE -babelfish_sysdatabases -babelfish_namespace_ext +babel_datatype_sqlvariant +babel_datetime +BABEL-EXTENDEDPROPERTY babelfish_authid_login_ext babelfish_authid_user_ext +babelfish_cast_floor babelfish_inconsistent_metadata babelfish_migration_mode -schema_resolution_func -BABEL-3147 -collation_tests_arabic -collation_tests_greek -collation_tests_mongolian -collation_tests_polish -collation_tests -babel_datetime -babel_char -BABEL-SQUARE -BABEL-728 +babelfish_namespace_ext +babelfish_sysdatabases babel_function_string -BABEL-2701 -BABEL-1566 -BABEL-3360 +BABEL_GRANT_CONNECT babel_isnumeric -HAS_DBACCESS -BABEL-1475 -BABEL-1510 -BABEL-3213 +BABEL-LOGIN +BABEL-LOGIN-USER-EXT +BABEL_OBJECT_ID +BABEL_OBJECT_NAME +BABEL-PG-SYSTEM-FUNCTIONS +BABEL-PROCID BABEL-RAND -BABEL-741 +BABEL-ROLE BABEL-ROLE-MEMBER -tdscollation -BABEL-EXTENDEDPROPERTY -sys-filegroups -sys-filetables -sys-fulltext_indexes -sys-hash_indexes -sys-plan_guides -sp_tablecollations -sys-assemblies -BABEL-LOGIN-USER-EXT -bitwise_not-operator -BABEL-1683 -sys-sp_pkeys -sys-sp_statistics -BABEL-1756 -BABEL-APPLOCK -BABEL-1438 -BABEL-SP_TABLES -BABEL-SP_SPECIAL_COLUMNS -BABEL-SP_TABLE_PRIVILIGES -BABEL-SP_STORED_PROCEDURES -BABEL-SP_SPROC_COLUMNS -BABEL-3000 -sys_all_objects-dep -sys-columns-dep -sys-databases-dep -sys-foreign_key_columns-dep -sys-foreign_keys-dep -sys-identity_columns-dep -sys-indexes-dep -sys-key_constraints-dep -sys-schemas-dep -sys-sp_tables_view-dep -sys-sysforeignkeys-dep -sys-tables-dep -sys-types-dep -sys-views-dep -sys-check_constraints-dep -sys-computed_columns-dep -sys-index_columns-dep -sys-sp_databases-dep -sys-syscolumns-dep -sys-dm_exec_connections-dep -sys-dm_exec_sessions-dep -sys-table_types-dep -sys-all_sql_modules-dep -sys-sql_modules-dep -sys-system_sql_modules -sys-system_sql_modules-dep -sys-sp_pkeys-dep -sys-sp_statistics-dep -sys-proc_param_helper-dep -BABEL-1756-dep +BABEL_SCHEMATA BABEL-SP_COLUMNS_MANAGED-dep -BABEL-SP_SPECIAL_COLUMNS-dep +BABEL-SP_FKEYS +BABEL-SP_FKEYS-dep +BABEL-sp_helpdb +BABEL-SP_SPECIAL_COLUMNS BABEL-SP_SPECIAL_COLUMNS_100-dep -BABEL-SP_STORED_PROCEDURES-dep -BABEL-SP_SPROC_COLUMNS-dep +BABEL-SP_SPECIAL_COLUMNS-dep +BABEL-SP_SPROC_COLUMNS BABEL-SP_SPROC_COLUMNS_100-dep -BABEL-3000-dep -Test-sp_helprole-dep -Test-sp_helprolemember-dep +BABEL-SP_SPROC_COLUMNS-dep +BABEL-SP_STORED_PROCEDURES +BABEL-SP_STORED_PROCEDURES-dep +BABEL-SP_TABLE_PRIVILIGES +BABEL-SP_TABLES +babel_sqlvariant_cast_compare +BABEL-SQUARE +BABEL-TABLEOPTIONS +babel_trigger +babel_try_parse +BABEL-USER +bbf_view_def-before-14_7-or-15_2 +binary-index +bitwise_not-operator +case_insensitive_collation +cast_numeric_types_to_datetime +collation_tests +collation_tests_arabic +collation_tests_greek +collation_tests_mongolian +collation_tests_polish +column_domain_usage +constraint_column_usage +datepart +datetime2fromparts +forxml +fulltextserviceproperty +HAS_DBACCESS +indexproperty +insteadof_nested_trigger_inside_proc +insteadof_nested_trigger_with_dml +insteadoftriggers_with_transaction +ISC-Table_Constraints +ISC-Tables +is_srvrolemember +msdb-dbo-fn_syspolicy_is_automation_enabled +msdb-dbo-syspolicy_configuration msdb-dbo-syspolicy_system_health_state +nested_trigger_inside_proc +nested_trigger_with_dml +objectpropertyex +openjson +routines_definition_before-14_7-or-15_2 +rowcount +schema_resolution_func +schema_resolution_proc +schema_resolution_trigger +sp_describe_first_result_set +sp_tablecollations sys-all_columns +sys_all_objects +sys_all_objects-dep sys-all_parameters +sys-all_sql_modules_before-14_7-or-15_2 +sys-all_sql_modules-dep +sys-all_views +sys-assemblies sys-assembly_modules +sys-assembly_types sys-change_tracking_databases sys-change_tracking_tables +sys-check_constraints-dep +sys-column-property sys-columns +sys-columns-dep sys-computed_columns -sys-data_spaces +sys-computed_columns-dep +sys-configurations sys-database_files sys-database_filestream_options +sys-database_mirroring +sys_database_principals_dep sys-database_recovery_status +sys-databases +sys-databases-dep +sys-data_spaces +sys-datefirst sys-dm_exec_connections +sys-dm_exec_connections-dep sys-dm_exec_sessions +sys-dm_exec_sessions-dep sys-dm_hadr_cluster sys-dm_hadr_database_replica_states sys-dm_os_host_info sys-endpoints +sys-events sys-extended_properties +sys-filegroups +sys-filetables sys-filetable_system_defined_objects sys-foreign_key_columns +sys-foreign_key_columns-dep sys-foreign_keys +sys-foreign_keys-dep sys-fulltext_catalogs sys-fulltext_index_columns +sys-fulltext_indexes sys-fulltext_languages sys-fulltext_stoplists +sys-hash_indexes +sys-has_perms_by_name +sys-has_perms_by_name-dep +sys-host_name sys-identity_columns +sys-identity_columns-dep sys-index_columns +sys-index_columns-dep sys-indexes +sys-indexes-dep sys-key_constraints +sys-key_constraints-dep +sys-lock_timeout sys-master_files +sys-max_connections +sys-numbered_procedures +sys-objects +sys-original_login +sys-plan_guides +sys-procedures +sys-proc_param_helper-dep sys-registered_search_property_lists +sys-schema-name sys-schemas +sys-schemas-dep sys-selective_xml_index_paths +sys-server_principals +sys_server_principals_dep sys-sid_binary +sys-spatial_indexes +sys-spatial_index_tessellations sys-sp_databases +sys-sp_databases-dep +sys-sp_pkeys +sys-sp_pkeys-dep +sys-sp_statistics +sys-sp_statistics-dep sys-sp_tables_view -sys-spatial_index_tessellations -sys-spatial_indexes +sys-sp_tables_view-dep +sys-sql_modules_before-14_7-or-15_2 +sys-sql_modules-dep sys-stats +sys-suser_sid +sys-suser_sname sys-synonyms sys-syscharsets sys-syscolumns +sys-syscolumns-dep +sys-sysdatabases sys-sysforeignkeys +sys-sysforeignkeys-dep +sys-sysindexes sys-syslanguages -sys-table_types +sys-sysobjects +sys-system_objects +sys-system_sql_modules +sys-system_sql_modules-dep sys-tables +sys-tables-dep +sys-table_types +sys-table_types-dep +sys-table_types_internal +SYSTEM_USER +sys-trigger_events +sys-trigger_nestlevel sys-triggers +sys-triggers-dep +sys-types-dep +sys-userid-dep sys-views +sys-views-dep sys-xml_indexes sys-xml_schema_collections -sys_all_objects -sys-userid-dep -BABEL-1249 -BABEL-1291 -BABEL-1994-CHAR -BABEL-1994-VARCHAR -BABEL-889 -babel_417 -babel_datatype_sqlvariant -babel_sqlvariant_cast_compare -BABEL-3347-before-14_6 -BABEL-3556-before-14_6 -BABEL-3010-before-14_6 -BABEL_GRANT_CONNECT -BABEL-sp_helpdb -BABEL-2795 -BABEL-PG-SYSTEM-FUNCTIONS -BABEL-3655 -sys-table_types_internal -BABEL-CHECK-CONSTRAINT-before-14_6 -BABEL-3640 -openjson -sys-sysindexes -sys-system_objects -ISC-Tables -ISC-Table_Constraints -sys_server_principals_dep -sys_database_principals_dep -BABEL-3801 -case_insensitive_collation -sys-has_perms_by_name -sys-has_perms_by_name-dep -AVG-Aggregate-common -AVG-Aggregate-Dep-before-15-2-or-14-7 -bbf_view_def-before-14_7-or-15_2 -sys-all_sql_modules_before-14_7-or-15_2 -sys-sql_modules_before-14_7-or-15_2 -BABEL_OBJECT_ID +table-variable +tdscollation +temp-tables +TestBigInt +TestBinary +TestBIT +TestChar +Test-Computed-Columns +TestDate +TestDatetime +TestDatetime2 +TestDecimal +TestFloat +Test-Identity-before-14_7-or-15_2 +TestImage +TestInt +TestMoney +TestNotNull +TestNumeric +TestReal +TestSmallDatetime +TestSmallInt +TestSmallMoney +Test-sp_addrole +Test-sp_addrolemember +Test-sp_droprole +Test-sp_droprolemember +Test-sp_helpdbfixedrole +Test-sp_helprole-dep +Test-sp_helprolemember-dep +Test-sp_helpsrvrolemember +Test-sp_helpuser +TestSQLVariant +TestTableType +TestText +TestTime +TestTinyInt +TestUDD +TestUniqueIdentifier +TestVarChar test_windows_login_before_15_2 -BABEL_SCHEMATA -BABEL-SP_FKEYS -BABEL-SP_FKEYS-dep -BABEL_OBJECT_NAME -BABEL-3657 -BABEL-3938 -binary-index -rowcount -BABEL-1625 -BABEL-3818 -BABEL-3474 -datetime2fromparts +TestXML timefromparts -BABEL-3215 -BABEL-4078-before-14_8-or-15_3 +triggers_with_transaction diff --git a/test/JDBC/upgrade/14_6/schedule b/test/JDBC/upgrade/14_6/schedule index cf45192a70..d09cdadca3 100644 --- a/test/JDBC/upgrade/14_6/schedule +++ b/test/JDBC/upgrade/14_6/schedule @@ -1,372 +1,379 @@ # Schedule File for JDBC Test Framework for local run # 1. Lines starting with '#' will be treated as comments -# 2. To run a postgres command: cmd#!#postgresql#!# +# 2. To run a postgres command: cmd#!#postgresql#!# # 3. To run a T-SQL command: cmd#!#sqlserver#!# -# 4. Keyword "all" is equivalent to running all test files in -# input folder -# 5. To add a test, add test name (without extension, -vu-prepare, -vu-verify and -vu-cleanup. For example if test file name is TestBigInt-vu-prepare.txt write TestBigInt) on a new line +# 4. Keyword "all" is equivalent to running all test files in input folder +# 5. To add a test, add test name (without extension, , and . For example if test file name is TestBigInt.txt write TestBigInt) on a new line # This should be the first test to check there are no duplicated object_ids BABEL-3613 -TestBigInt -TestBinary -TestBIT -TestChar -TestDatetime2 -TestDatetime -TestDatetime-numeric-representation -TestDate -TestDecimal -TestFloat -TestImage -TestInt -TestMoney -TestNumeric -TestReal -TestSmallDatetime -TestSmallInt -TestSmallMoney -TestSQLVariant -TestText -TestTime -TestTinyInt -TestUDD -TestUniqueIdentifier -TestVarChar -TestXML -sys-assembly_types -sys-database_mirroring -sys-databases -sys-numbered_procedures -BABEL-3121 -sys-events -sys-suser_sid -sys-trigger_events -BABEL-328 -BABEL-3166 -BABEL-3192 -BABEL-3221 -BABEL-3204 -BABEL-3234 -BABEL-3402 -cast_numeric_types_to_datetime -cast_numeric_types_to_smalldatetime -routines_definition_before-14_7-or-15_2 -column_domain_usage -constraint_column_usage -sp_describe_first_result_set -sys-host_name -SYSTEM_USER -indexproperty -sys-all_parameters -msdb-dbo-syspolicy_configuration -sys-all_views -datepart -sys-server_principals -fulltextserviceproperty -is_srvrolemember -msdb-dbo-fn_syspolicy_is_automation_enabled -# Takes too long, tracking with BABEL-3675 -# objectproperty -objectpropertyex -sys-column-property -sys-configurations -sys-datefirst -sys-lock_timeout -sys-max_connections -sys-original_login -sys-schema-name -sys-objects -sys-procedures -sys-sysdatabases -sys-sysobjects -sys-trigger_nestlevel -schema_resolution_proc -BABEL-404 -BABEL-493 -BABEL-621 -BABEL-775 +AVG-Aggregate-common +AVG-Aggregate-Dep-before-15-2-or-14-7 +BABEL-1062 +BABEL-1189 BABEL-1206 +BABEL-1243 +BABEL-1249 BABEL-1251 +BABEL-1291 BABEL-1319 +BABEL-1438 BABEL-1444 BABEL-1465 BABEL-1466 +BABEL-1475 +BABEL-1493 +BABEL-1510 +BABEL-1566 +BABEL-1625 BABEL-1654 +BABEL-1683 BABEL-1715 -BABEL-2086 -BABEL-3314 -BABEL-TABLEOPTIONS -BABEL-2765 -BABEL-2819 -BABEL-2917 -BABEL-2955 -BABEL-3358 -temp-tables -table-variable -TestNotNull -Test-Identity-before-14_7-or-15_2 -Test-Computed-Columns -BABEL-1189 -BABEL-1062 -BABEL-1243 -BABEL-1493 +BABEL-1953 BABEL-1963 +BABEL-1994-CHAR +BABEL-1994-VARCHAR +BABEL-2086 BABEL-2203 BABEL-2208 BABEL-2257 BABEL-2449 BABEL-2535 -BABEL-2787-2 +BABEL-2765 BABEL-2787 +BABEL-2787-2 +BABEL-2795 BABEL-2805 BABEL-2812 +BABEL-2819 BABEL-2845 BABEL-2884 +BABEL-2917 BABEL-2944 +BABEL-2955 +BABEL-3000 +BABEL-3000-dep +BABEL-3010 BABEL-3116 BABEL-3117 BABEL-3118 +BABEL-3121 +BABEL-3144 +BABEL-3147 +BABEL-3166 +BABEL-3192 +BABEL-3204 +BABEL-3213 +BABEL-3215 +BABEL-3221 +BABEL-3234 BABEL-3249 +BABEL-3268 +BABEL-328 +BABEL-3314 +BABEL-3347 +BABEL-3358 +BABEL-3360 +BABEL-3369 +BABEL-3370 +BABEL-3380 +BABEL-3402 +BABEL-3474 BABEL-3486 +BABEL-3513 +BABEL-3556 +BABEL-3588 BABEL-3614 +BABEL-3640 BABEL-3646 +BABEL-3655 +BABEL-3657 BABEL-3748-before-14_7 +BABEL-3801 +BABEL-3818 BABEL-383 +BABEL-3938 +BABEL-404 BABEL-405 +BABEL-4078-before-14_8-or-15_3 +babel_417 +BABEL-493 +BABEL-621 +BABEL-728 +BABEL-741 +BABEL-775 +BABEL-889 BABEL-937 -forjson -forjson-datatypes -forxml -BABEL-PROCID -babel_trigger -insteadoftriggers_with_transaction -insteadof_nested_trigger_inside_proc -insteadof_nested_trigger_with_dml -nested_trigger_inside_proc -nested_trigger_with_dml -triggers_with_transaction -Test-sp_addrole -Test-sp_addrolemember -Test-sp_droprole -Test-sp_droprolemember -Test-sp_helpdbfixedrole -Test-sp_helpsrvrolemember -Test-sp_helpuser -TestTableType +BABEL-APPLOCK +babel_char +BABEL-CHECK-CONSTRAINT BABEL-CROSS-DB -BABEL-LOGIN -BABEL-USER -BABEL-ROLE -babelfish_sysdatabases -babelfish_namespace_ext +babel_datatype_sqlvariant +babel_datetime +BABEL-EXTENDEDPROPERTY babelfish_authid_login_ext babelfish_authid_user_ext +babelfish_cast_floor babelfish_inconsistent_metadata +babelfish_integrity_checker babelfish_migration_mode -schema_resolution_func -BABEL-3147 -collation_tests_arabic -collation_tests_greek -collation_tests_mongolian -collation_tests_polish -collation_tests -babel_datetime -babel_char -BABEL-SQUARE -BABEL-728 +babelfish_namespace_ext +babelfish_sysdatabases babel_function_string -BABEL-1566 -BABEL-3360 -BABEL-3380 +BABEL_GRANT_CONNECT babel_isnumeric -HAS_DBACCESS -BABEL-1475 -BABEL-1510 -BABEL-3213 -BABEL-3010 -BABEL-3369 -BABEL-3370 -BABEL-RAND -BABEL-741 -BABEL-ROLE-MEMBER -tdscollation -BABEL-EXTENDEDPROPERTY -sys-filegroups -sys-filetables -sys-fulltext_indexes -sys-hash_indexes -sys-plan_guides -sp_tablecollations -sys-assemblies +BABEL-LOGIN BABEL-LOGIN-USER-EXT -bitwise_not-operator -BABEL-1683 -BABEL-1953 -schema_resolution_trigger -sys_all_objects-dep -sys-columns-dep -sys-databases-dep -sys-foreign_key_columns-dep -sys-foreign_keys-dep -sys-identity_columns-dep -sys-indexes-dep -sys-key_constraints-dep -sys-schemas-dep -sys-sp_tables_view-dep -sys-sysforeignkeys-dep -sys-tables-dep -sys-types-dep -sys-views-dep -sys-check_constraints-dep -sys-computed_columns-dep -sys-default_constraints-dep -sys-index_columns-dep -sys-sp_databases-dep -sys-syscolumns-dep -sys-dm_exec_connections-dep -sys-dm_exec_sessions-dep -sys-table_types-dep -sys-all_sql_modules-dep -sys-sql_modules-dep -sys-system_sql_modules-dep -sys-triggers-dep -sys-sp_pkeys -sys-sp_statistics -sys-userid-dep -BABEL-APPLOCK -BABEL-1438 -BABEL-SP_DATATYPE_INFO +BABEL_OBJECT_ID +BABEL_OBJECT_NAME +BABEL-PG-SYSTEM-FUNCTIONS +BABEL-PROCID +BABEL-RAND +BABEL-ROLE +BABEL-ROLE-MEMBER +BABEL_SCHEMATA BABEL-SPCOLUMNS -BABEL-SP_TABLES -BABEL-SP_SPECIAL_COLUMNS -BABEL-SP_TABLE_PRIVILIGES -BABEL-SP_FKEYS -BABEL-SP_STORED_PROCEDURES -BABEL-SP_SPROC_COLUMNS -BABEL-3000 -sys-sp_pkeys-dep -sys-sp_statistics-dep BABEL-SPCOLUMNS-dep -BABEL-SP_SPECIAL_COLUMNS-dep +BABEL-SP_COLUMNS_MANAGED-dep +BABEL-SP_DATATYPE_INFO +BABEL-SP_FKEYS BABEL-SP_FKEYS-dep -BABEL-SP_STORED_PROCEDURES-dep +BABEL-sp_helpdb +BABEL-SP_SPECIAL_COLUMNS +BABEL-SP_SPECIAL_COLUMNS_100-dep +BABEL-SP_SPECIAL_COLUMNS-dep +BABEL-SP_SPROC_COLUMNS +BABEL-SP_SPROC_COLUMNS_100-dep BABEL-SP_SPROC_COLUMNS-dep -BABEL-3000-dep +BABEL-SP_STORED_PROCEDURES +BABEL-SP_STORED_PROCEDURES-dep +BABEL-SP_TABLE_PRIVILIGES +BABEL-SP_TABLES +babel_sqlvariant_cast_compare +BABEL-SQUARE +BABEL-TABLEOPTIONS +babel_trigger +babel_try_parse +BABEL-USER +bbf_view_def-before-14_7-or-15_2 +binary-index +bitwise_not-operator +case_insensitive_collation +cast_numeric_types_to_datetime +cast_numeric_types_to_smalldatetime +collation_tests +collation_tests_arabic +collation_tests_greek +collation_tests_mongolian +collation_tests_polish +column_domain_usage +constraint_column_usage +dateadd_internal_df +datediff_internal_date-before-14_7-or-15_2 +datepart +datetime2fromparts +forjson +forjson-datatypes format +forxml +fulltextserviceproperty +get_tds_id +HAS_DBACCESS +identity_function +indexproperty +insteadof_nested_trigger_inside_proc +insteadof_nested_trigger_with_dml +insteadoftriggers_with_transaction +ISC-Table_Constraints +ISC-Tables +ISC-Views +is_srvrolemember +msdb-dbo-fn_syspolicy_is_automation_enabled +msdb-dbo-syspolicy_configuration msdb-dbo-syspolicy_system_health_state +nested_trigger_inside_proc +nested_trigger_with_dml +objectpropertyex +openjson +routines_definition_before-14_7-or-15_2 +rowcount +schema_resolution_func +schema_resolution_proc +schema_resolution_trigger +sp_describe_first_result_set +sp_tablecollations sys-all_columns +sys_all_objects +sys_all_objects-dep +sys-all_parameters +sys-all_parameters-dep +sys-all_sql_modules-dep +sys-all_views +sys-assemblies sys-assembly_modules +sys-assembly_types +sys_babelfish_configurations_view sys-change_tracking_databases sys-change_tracking_tables sys-check_constraints +sys-check_constraints-dep +sys-column-property sys-columns +sys-columns-dep sys-computed_columns -sys-data_spaces +sys-computed_columns-dep +sys-configurations sys-database_files sys-database_filestream_options +sys-database_mirroring +sys_database_principals_dep sys-database_recovery_status +sys-databases +sys-databases-dep +sys-data_spaces +sys-datefirst sys-default_constraints +sys-default_constraints-dep sys-dm_exec_connections +sys-dm_exec_connections-dep sys-dm_exec_sessions +sys-dm_exec_sessions-dep sys-dm_hadr_cluster sys-dm_hadr_database_replica_states sys-dm_os_host_info sys-endpoints +sys-events sys-extended_properties +sys-filegroups +sys-filetables sys-filetable_system_defined_objects sys-foreign_key_columns +sys-foreign_key_columns-dep sys-foreign_keys +sys-foreign_keys-dep sys-fulltext_catalogs sys-fulltext_index_columns +sys-fulltext_indexes sys-fulltext_languages sys-fulltext_stoplists +sys-hash_indexes +sys-has_perms_by_name +sys-has_perms_by_name-dep +sys-host_name sys-identity_columns +sys-identity_columns-dep sys-index_columns +sys-index_columns-dep sys-indexes +sys-indexes-dep sys-key_constraints +sys-key_constraints-dep +sys-lock_timeout sys-master_files +sys-max_connections +sys-numbered_procedures +sys-objects +sys-original_login sys-partitions +sys-plan_guides +sys-procedures +sys-proc_param_helper-dep sys-registered_search_property_lists +sys-schema-name sys-schemas +sys-schemas-dep sys-selective_xml_index_paths +sys-server_principals +sys_server_principals_dep sys-sid_binary +sys-spatial_indexes +sys-spatial_index_tessellations sys-sp_databases +sys-sp_databases-dep +sys-sp_pkeys +sys-sp_pkeys-dep +sys-sp_statistics +sys-sp_statistics-dep sys-sp_tables_view -sys-spatial_index_tessellations -sys-spatial_indexes +sys-sp_tables_view-dep +sys-sql_modules-dep sys-stats +sys-suser_sid +sys-suser_sname sys-synonyms sys-syscharsets sys-syscolumns +sys-syscolumns-dep +sys-sysdatabases sys-sysforeignkeys +sys-sysforeignkeys-dep +sys-sysindexes sys-syslanguages +sys-sysobjects +sys-system_objects sys-system_sql_modules -sys-table_types +sys-system_sql_modules-dep sys-tables +sys-tables-dep +sys-table_types +sys-table_types-dep +sys-table_types_internal +sys-table_types_internal-dep +SYSTEM_USER +sys-trigger_events +sys-trigger_nestlevel sys-triggers +sys-triggers-dep sys-types +sys-types-dep +sys-userid-dep sys-views +sys-views-dep sys-xml_indexes sys-xml_schema_collections -sys_all_objects -sys_babelfish_configurations_view -BABEL-1249 -BABEL-1291 -BABEL-1994-CHAR -BABEL-1994-VARCHAR -BABEL-889 -babel_417 -babel_datatype_sqlvariant -babel_sqlvariant_cast_compare -BABEL-3347 -BABEL-3144 -sys-all_parameters-dep -BABEL-3556 -BABEL-3588 -BABEL-3268 -BABEL-3513 -BABEL_GRANT_CONNECT -BABEL-sp_helpdb -BABEL-2795 -babelfish_integrity_checker -get_tds_id -BABEL-PG-SYSTEM-FUNCTIONS -BABEL-3655 -sys-table_types_internal -sys-table_types_internal-dep -BABEL-CHECK-CONSTRAINT -BABEL-3640 -openjson -sys-sysindexes -sys-system_objects -ISC-Tables -ISC-Table_Constraints -ISC-Views -sys_server_principals_dep -sys_database_principals_dep -BABEL-3801 -case_insensitive_collation -sys-has_perms_by_name -sys-has_perms_by_name-dep -AVG-Aggregate-common -AVG-Aggregate-Dep-before-15-2-or-14-7 -bbf_view_def-before-14_7-or-15_2 -BABEL_OBJECT_ID +table-variable +tdscollation +temp-tables +TestBigInt +TestBinary +TestBIT +TestChar +Test-Computed-Columns +TestDate +TestDatetime +TestDatetime2 +TestDatetime-numeric-representation +TestDecimal +TestFloat +Test-Identity-before-14_7-or-15_2 +TestImage +TestInt +TestMoney +TestNotNull +TestNumeric +TestReal +TestSmallDatetime +TestSmallInt +TestSmallMoney +Test-sp_addrole +Test-sp_addrolemember +Test-sp_droprole +Test-sp_droprolemember +Test-sp_helpdbfixedrole +Test-sp_helprole-dep +Test-sp_helprolemember-dep +Test-sp_helpsrvrolemember +Test-sp_helpuser +TestSQLVariant +TestTableType +TestText +TestTime +TestTinyInt +TestUDD +TestUniqueIdentifier +TestVarChar test_windows_login_before_15_2 -datediff_internal_date-before-14_7-or-15_2 -BABEL_OBJECT_NAME -BABEL_SCHEMATA -BABEL-3657 -BABEL-3938 -binary-index -rowcount -BABEL-1625 -BABEL-3474 -BABEL-3818 -dateadd_internal_df -datetime2fromparts +TestXML timefromparts -BABEL-3215 -BABEL-4078-before-14_8-or-15_3 +triggers_with_transaction diff --git a/test/JDBC/upgrade/14_7/schedule b/test/JDBC/upgrade/14_7/schedule index 0751725d3a..3ca5f6bde3 100644 --- a/test/JDBC/upgrade/14_7/schedule +++ b/test/JDBC/upgrade/14_7/schedule @@ -1,405 +1,401 @@ # Schedule File for JDBC Test Framework for local run # 1. Lines starting with '#' will be treated as comments -# 2. To run a postgres command: cmd#!#postgresql#!# +# 2. To run a postgres command: cmd#!#postgresql#!# # 3. To run a T-SQL command: cmd#!#sqlserver#!# -# 4. Keyword "all" is equivalent to running all test files in -# input folder -# 5. To add a test, add test name (without extension, -vu-prepare, -vu-verify and -vu-cleanup. For example if test file name is TestBigInt-vu-prepare.txt write TestBigInt) on a new line +# 4. Keyword "all" is equivalent to running all test files in input folder +# 5. To add a test, add test name (without extension, , and . For example if test file name is TestBigInt.txt write TestBigInt) on a new line # This should be the first test to check there are no duplicated object_ids BABEL-3613 -babelfish_cast_floor -babel_try_parse -TestBigInt -TestBinary -TestBIT -TestChar -TestDatetime2 -TestDatetime -TestDatetime-numeric-representation -TestDate -TestDecimal -TestFloat -TestImage -TestInt -TestMoney -TestNumeric -TestReal -TestSmallDatetime -TestSmallInt -TestSmallMoney -TestSQLVariant -TestText -TestTime -TestTinyInt -TestUDD -TestUniqueIdentifier -TestVarChar -TestXML -sys-assembly_types -sys-database_mirroring -sys-databases -sys-numbered_procedures -BABEL-3121 -sys-events -sys-suser_sid -sys-trigger_events -BABEL-328 -BABEL-3166 -BABEL-3192 -BABEL-3221 -BABEL-3204 -BABEL-3234 -BABEL-3402 -cast_numeric_types_to_datetime -cast_numeric_types_to_smalldatetime -routines_definition -column_domain_usage -constraint_column_usage -sp_describe_first_result_set -sys-host_name -SYSTEM_USER -indexproperty -sys-all_parameters -msdb-dbo-syspolicy_configuration -sys-all_views -datepart -sys-server_principals -fulltextserviceproperty -is_srvrolemember -msdb-dbo-fn_syspolicy_is_automation_enabled -# Takes too long, tracking with BABEL-3675 -# objectproperty -objectpropertyex -sys-column-property -sys-configurations -sys-datefirst -sys-lock_timeout -sys-max_connections -sys-original_login -sys-schema-name -sys-objects -sys-procedures -sys-sysdatabases -sys-sysobjects -sys-trigger_nestlevel -schema_resolution_proc -BABEL-404 -BABEL-493 -BABEL-621 -BABEL-775 +app_name +atn2 +AVG-Aggregate-common +AVG-Aggregate-Dep +BABEL-1062 +BABEL-1189 BABEL-1206 +BABEL-1243 +BABEL-1249 BABEL-1251 +BABEL-1291 BABEL-1319 +BABEL-1438 BABEL-1444 BABEL-1465 BABEL-1466 +BABEL-1475 +BABEL-1493 +BABEL-1510 +BABEL-1566 +BABEL-1625 BABEL-1654 +BABEL-1683 BABEL-1715 -BABEL-2086 -BABEL-3314 -BABEL-TABLEOPTIONS -BABEL-2765 -BABEL-2819 -BABEL-2917 -BABEL-2955 -BABEL-3358 -BABEL-3747 -BABEL-3781 -BABEL-3802 -BABEL-3914 -temp-tables -table-variable -TestNotNull -Test-Identity -Test-Computed-Columns -BABEL-1189 -BABEL-1062 -BABEL-1243 -BABEL-1493 +BABEL-1953 BABEL-1963 +BABEL-1994-CHAR +BABEL-1994-VARCHAR +BABEL-2086 BABEL-2203 BABEL-2208 BABEL-2257 BABEL-2449 BABEL-2535 -BABEL-2787-2 +BABEL-2765 BABEL-2787 +BABEL-2787-2 +BABEL-2795 BABEL-2805 BABEL-2812 +BABEL-2819 BABEL-2845 BABEL-2884 +BABEL-2917 BABEL-2944 +BABEL-2955 +BABEL-3000 +BABEL-3000-dep +BABEL-3010 BABEL-3116 BABEL-3117 BABEL-3118 +BABEL-3121 +BABEL-3144 +BABEL-3147 +BABEL-3166 +BABEL-3192 +BABEL-3204 +BABEL-3213 +BABEL-3215 +BABEL-3221 +BABEL-3234 BABEL-3249 +BABEL-3268 +BABEL-328 +BABEL-3314 +BABEL-3347 +BABEL-3358 +BABEL-3360 +BABEL-3369 +BABEL-3370 +BABEL-3380 +BABEL-3402 +BABEL-3474 BABEL-3486 +BABEL-3513 +BABEL-3556 +BABEL-3588 BABEL-3614 +BABEL-3640 BABEL-3646 +BABEL-3655 +BABEL-3657 +BABEL-3702 +BABEL-3747 +BABEL-3748 +BABEL-3781 +BABEL-3802 +BABEL-3818 BABEL-383 +BABEL-3914 +BABEL-3938 +BABEL-404 BABEL-405 +BABEL-4078-before-14_8-or-15_3 +BABEL-4098 +babel_417 +BABEL-493 +BABEL-621 +BABEL-728 +BABEL-733 +BABEL-741 +BABEL-745 +BABEL-775 +BABEL-889 BABEL-937 -forjson -forjson-subquery -forjson-datatypes -forxml -forxml-subquery -BABEL-PROCID -babel_trigger -insteadoftriggers_with_transaction -insteadof_nested_trigger_inside_proc -insteadof_nested_trigger_with_dml -nested_trigger_inside_proc -nested_trigger_with_dml -triggers_with_transaction -Test-sp_addrole -Test-sp_addrolemember -Test-sp_droprole -Test-sp_droprolemember -Test-sp_helpdbfixedrole -Test-sp_helpsrvrolemember -Test-sp_set_session_context -Test-sp_helpuser -TestTableType +BABEL-APPLOCK +babel_char +BABEL-CHECK-CONSTRAINT +babel_context_info BABEL-CROSS-DB -BABEL-LOGIN -BABEL-USER -BABEL-ROLE -babelfish_sysdatabases -babelfish_namespace_ext +babel_datatype_sqlvariant +babel_datetime +BABEL-EXECUTE_AS_CALLER +BABEL-EXTENDEDPROPERTY babelfish_authid_login_ext babelfish_authid_user_ext +babelfish_cast_floor babelfish_inconsistent_metadata +babelfish_integrity_checker babelfish_migration_mode -schema_resolution_func -BABEL-3147 -collation_tests_arabic -collation_tests_greek -collation_tests_mongolian -collation_tests_polish -collation_tests -babel_datetime -babel_char -BABEL-SQUARE -BABEL-728 +babelfish_namespace_ext +babelfish_sysdatabases babel_function_string -BABEL-1566 -BABEL-3360 -BABEL-3380 +BABEL_GRANT_CONNECT babel_isnumeric -HAS_DBACCESS -BABEL-1475 -BABEL-1510 -BABEL-3213 -BABEL-3010 -BABEL-3369 -BABEL-3370 +BABEL-LOGIN +BABEL-LOGIN-USER-EXT +BABEL-NEXT-VALUE-FOR +BABEL_OBJECT_DEFINITION +BABEL_OBJECT_ID +BABEL_OBJECT_NAME +BABEL-PG-SYSTEM-FUNCTIONS +BABEL-PROCID BABEL-RAND -BABEL-741 +BABEL-ROLE BABEL-ROLE-MEMBER -tdscollation -BABEL-EXTENDEDPROPERTY -BABEL-EXECUTE_AS_CALLER -sys-filegroups -sys-filetables -sys-fulltext_indexes -sys-hash_indexes -sys-plan_guides -sp_tablecollations -sys-assemblies -BABEL-LOGIN-USER-EXT -bitwise_not-operator -BABEL-1683 -BABEL-1953 -schema_resolution_trigger -sys_all_objects-dep -sys-columns-dep -sys-databases-dep -sys-foreign_key_columns-dep -sys-foreign_keys-dep -sys-identity_columns-dep -sys-indexes-dep -sys-key_constraints-dep -sys-schemas-dep -sys-sp_tables_view-dep -sys-sysforeignkeys-dep -sys-tables-dep -sys-types-dep -sys-views-dep -sys-check_constraints-dep -sys-computed_columns-dep -sys-default_constraints-dep -sys-index_columns-dep -sys-sp_databases-dep -sys-syscolumns-dep -sys-dm_exec_connections-dep -sys-dm_exec_sessions-dep -sys-table_types-dep -sys-all_sql_modules-dep -sys-sql_modules-dep -sys-system_sql_modules-dep -sys-triggers-dep -sys-proc_param_helper-dep -sys-sp_pkeys -sys-sp_statistics -BABEL-APPLOCK -BABEL-1438 -BABEL-SP_DATATYPE_INFO +BABEL_SCHEMATA BABEL-SPCOLUMNS -BABEL-SP_TABLES -BABEL-SP_SPECIAL_COLUMNS -BABEL-SP_TABLE_PRIVILIGES -BABEL-SP_FKEYS -BABEL-SP_STORED_PROCEDURES -BABEL-SP_SPROC_COLUMNS -BABEL-3000 -sys-sp_pkeys-dep -sys-sp_statistics-dep BABEL-SPCOLUMNS-dep BABEL-SP_COLUMNS_MANAGED-dep -BABEL-SP_SPECIAL_COLUMNS-dep -BABEL-SP_SPECIAL_COLUMNS_100-dep +BABEL-SP_DATATYPE_INFO +BABEL-SP_FKEYS BABEL-SP_FKEYS-dep -BABEL-SP_STORED_PROCEDURES-dep -BABEL-SP_SPROC_COLUMNS-dep +BABEL-sp_helpdb +BABEL-SP_SPECIAL_COLUMNS +BABEL-SP_SPECIAL_COLUMNS_100-dep +BABEL-SP_SPECIAL_COLUMNS-dep +BABEL-SP_SPROC_COLUMNS BABEL-SP_SPROC_COLUMNS_100-dep -BABEL-3000-dep -Test-sp_helprole-dep -Test-sp_helprolemember-dep +BABEL-SP_SPROC_COLUMNS-dep +BABEL-SP_STORED_PROCEDURES +BABEL-SP_STORED_PROCEDURES-dep +BABEL-SP_TABLE_PRIVILIGES +BABEL-SP_TABLES +babel_sqlvariant_cast_compare +BABEL-SQUARE +BABEL-TABLEOPTIONS +babel_trigger +babel_try_parse +BABEL-USER +bbf_view_def +binary-index +bitwise_not-operator +case_insensitive_collation +cast_numeric_types_to_datetime +cast_numeric_types_to_smalldatetime +collation_tests +collation_tests_arabic +collation_tests_greek +collation_tests_mongolian +collation_tests_polish +column_domain_usage +constraint_column_usage +dateadd_internal_df +datediff_big +datediff_internal_date +datepart +datetime2fromparts +forjson +forjson-datatypes +forjson-subquery format +forxml +forxml-subquery +fulltextserviceproperty +get_tds_id +HAS_DBACCESS +indexproperty +insteadof_nested_trigger_inside_proc +insteadof_nested_trigger_with_dml +insteadoftriggers_with_transaction +ISC-Columns +ISC-Table_Constraints +ISC-Tables +is_srvrolemember +msdb-dbo-fn_syspolicy_is_automation_enabled +msdb-dbo-syspolicy_configuration msdb-dbo-syspolicy_system_health_state +nested_trigger_inside_proc +nested_trigger_with_dml +objectpropertyex +openjson +routines_definition +rowcount +schema_resolution_func +schema_resolution_proc +schema_resolution_trigger +sp_describe_first_result_set +sp_tablecollations +str sys-all_columns sys-all_columns-dep +sys_all_objects +sys_all_objects-dep +sys-all_parameters +sys-all_parameters-dep +sys-all_sql_modules +sys-all_sql_modules-dep +sys-all_views +sys-assemblies sys-assembly_modules +sys-assembly_types +sys_babelfish_configurations_view sys-change_tracking_databases sys-change_tracking_tables sys-check_constraints +sys-check_constraints-dep +sys-column-property sys-columns +sys-columns-dep sys-computed_columns -sys-data_spaces +sys-computed_columns-dep +sys-configurations sys-database_files sys-database_filestream_options +sys-database_mirroring +sys_database_principals_dep sys-database_recovery_status +sys-databases +sys-databases-dep +sys-data_spaces +sys-datefirst sys-default_constraints +sys-default_constraints-dep sys-dm_exec_connections +sys-dm_exec_connections-dep sys-dm_exec_sessions +sys-dm_exec_sessions-dep sys-dm_hadr_cluster sys-dm_hadr_database_replica_states sys-dm_os_host_info sys-endpoints +sys-events sys-extended_properties +sys-filegroups +sys-filetables sys-filetable_system_defined_objects sys-foreign_key_columns +sys-foreign_key_columns-dep sys-foreign_keys +sys-foreign_keys-dep sys-fulltext_catalogs sys-fulltext_index_columns +sys-fulltext_indexes sys-fulltext_languages sys-fulltext_stoplists +sys-hash_indexes +sys-has_perms_by_name +sys-has_perms_by_name-dep +sys-host_name sys-identity_columns +sys-identity_columns-dep sys-index_columns +sys-index_columns-dep sys-indexes +sys-indexes-dep sys-key_constraints +sys-key_constraints-dep +sys-lock_timeout sys-master_files +sys-max_connections +sys-numbered_procedures +sys-objects +sys-original_login sys-partitions sys-partitions-dep +sys-plan_guides +sys-procedures +sys-proc_param_helper-dep sys-registered_search_property_lists +sys-schema-name sys-schemas +sys-schemas-dep sys-selective_xml_index_paths +sys-server_principals +sys_server_principals_dep sys-sid_binary +sys-spatial_indexes +sys-spatial_index_tessellations sys-sp_databases +sys-sp_databases-dep +sys-sp_pkeys +sys-sp_pkeys-dep +sys-sp_statistics +sys-sp_statistics-dep sys-sp_tables_view -sys-spatial_index_tessellations -sys-spatial_indexes +sys-sp_tables_view-dep +sys-sql_modules +sys-sql_modules-dep sys-stats +sys-suser_sid sys-synonyms sys-syscharsets sys-syscolumns +sys-syscolumns-dep +sys-sysdatabases sys-sysforeignkeys +sys-sysforeignkeys-dep +sys-sysindexes sys-syslanguages +sys-sysobjects +sys-system_objects sys-system_sql_modules -sys-table_types +sys-system_sql_modules-dep sys-tables +sys-tables-dep +sys-table_types +sys-table_types-dep +sys-table_types_internal +sys-table_types_internal-dep +SYSTEM_USER +sys-trigger_events +sys-trigger_nestlevel sys-triggers +sys-triggers-dep sys-types +sys-types-dep +sys-userid-dep sys-views +sys-views-dep sys-xml_indexes sys-xml_schema_collections -sys_all_objects -sys_babelfish_configurations_view -sys-userid-dep -BABEL-1249 -BABEL-1291 -BABEL-1994-CHAR -BABEL-1994-VARCHAR -BABEL-889 -babel_417 -babel_datatype_sqlvariant -babel_sqlvariant_cast_compare -BABEL-3347 -BABEL-3144 -sys-all_parameters-dep -BABEL-3556 -BABEL-3588 -BABEL-3268 -BABEL-3513 -BABEL_GRANT_CONNECT -BABEL-sp_helpdb -BABEL-2795 -babelfish_integrity_checker -get_tds_id -BABEL-PG-SYSTEM-FUNCTIONS -BABEL-3655 -sys-table_types_internal -sys-table_types_internal-dep -BABEL-CHECK-CONSTRAINT -BABEL-3640 -BABEL-3748 -openjson -BABEL-3702 -sys-sysindexes -sys-system_objects -ISC-Tables -ISC-Columns -#ISC-Check-Constraints -ISC-Table_Constraints -sys_server_principals_dep -sys_database_principals_dep -atn2 -datediff_big -app_name -str -case_insensitive_collation -sys-has_perms_by_name -sys-has_perms_by_name-dep -AVG-Aggregate-common -AVG-Aggregate-Dep -bbf_view_def -sys-all_sql_modules -sys-sql_modules -BABEL_OBJECT_ID -test_windows_login_before_15_2 -BABEL_OBJECT_DEFINITION -BABEL_SCHEMATA -datediff_internal_date -BABEL_OBJECT_NAME +table-variable +tdscollation +temp-tables +TestBigInt +TestBinary +TestBIT +TestChar +Test-Computed-Columns +TestDate +TestDatetime +TestDatetime2 +TestDatetime-numeric-representation +TestDecimal +TestFloat +Test-Identity +TestImage +TestInt +TestMoney +TestNotNull +TestNumeric +TestReal +TestSmallDatetime +TestSmallInt +TestSmallMoney +Test-sp_addrole +Test-sp_addrolemember +Test-sp_droprole +Test-sp_droprolemember +Test-sp_helpdbfixedrole +Test-sp_helprole-dep +Test-sp_helprolemember-dep +Test-sp_helpsrvrolemember +Test-sp_helpuser Test-sp_rename Test-sp_rename-dep -BABEL-3657 -BABEL-733 -BABEL-3938 -babel_context_info -binary-index -BABEL-745 -rowcount -BABEL-1625 -BABEL-3474 -BABEL-3818 -dateadd_internal_df -datetime2fromparts +Test-sp_set_session_context +TestSQLVariant +TestTableType +TestText +TestTime +TestTinyInt +TestUDD +TestUniqueIdentifier +TestVarChar +test_windows_login_before_15_2 +TestXML timefromparts -BABEL-3215 -BABEL-NEXT-VALUE-FOR -BABEL-4098 -BABEL-4078-before-14_8-or-15_3 +triggers_with_transaction diff --git a/test/JDBC/upgrade/14_8/schedule b/test/JDBC/upgrade/14_8/schedule index 0a998a9620..b00fb9484b 100644 --- a/test/JDBC/upgrade/14_8/schedule +++ b/test/JDBC/upgrade/14_8/schedule @@ -1,404 +1,400 @@ # Schedule File for JDBC Test Framework for local run # 1. Lines starting with '#' will be treated as comments -# 2. To run a postgres command: cmd#!#postgresql#!# +# 2. To run a postgres command: cmd#!#postgresql#!# # 3. To run a T-SQL command: cmd#!#sqlserver#!# -# 4. Keyword "all" is equivalent to running all test files in -# input folder -# 5. To add a test, add test name (without extension, -vu-prepare, -vu-verify and -vu-cleanup. For example if test file name is TestBigInt-vu-prepare.txt write TestBigInt) on a new line +# 4. Keyword "all" is equivalent to running all test files in input folder +# 5. To add a test, add test name (without extension, , and . For example if test file name is TestBigInt.txt write TestBigInt) on a new line # This should be the first test to check there are no duplicated object_ids BABEL-3613 -babelfish_cast_floor -babel_try_parse -TestBigInt -TestBinary -TestBIT -TestChar -TestDatetime2 -TestDatetime -TestDatetime-numeric-representation -TestDate -TestDecimal -TestFloat -TestImage -TestInt -TestMoney -TestNumeric -TestReal -TestSmallDatetime -TestSmallInt -TestSmallMoney -TestSQLVariant -TestText -TestTime -TestTinyInt -TestUDD -TestUniqueIdentifier -TestVarChar -TestXML -sys-assembly_types -sys-database_mirroring -sys-databases -sys-numbered_procedures -BABEL-3121 -sys-events -sys-suser_sid -sys-trigger_events -BABEL-328 -BABEL-3166 -BABEL-3192 -BABEL-3221 -BABEL-3204 -BABEL-3234 -BABEL-3402 -cast_numeric_types_to_datetime -cast_numeric_types_to_smalldatetime -routines_definition -column_domain_usage -constraint_column_usage -sp_describe_first_result_set -sys-host_name -SYSTEM_USER -indexproperty -sys-all_parameters -msdb-dbo-syspolicy_configuration -sys-all_views -datepart -sys-server_principals -fulltextserviceproperty -is_srvrolemember -msdb-dbo-fn_syspolicy_is_automation_enabled -# Takes too long, tracking with BABEL-3675 -# objectproperty -objectpropertyex -sys-column-property -sys-configurations -sys-datefirst -sys-lock_timeout -sys-max_connections -sys-original_login -sys-schema-name -sys-objects -sys-procedures -sys-sysdatabases -sys-sysobjects -sys-trigger_nestlevel -schema_resolution_proc -BABEL-404 -BABEL-493 -BABEL-621 -BABEL-775 +app_name +atn2 +AVG-Aggregate-common +AVG-Aggregate-Dep +BABEL-1062 +BABEL-1189 BABEL-1206 +BABEL-1243 +BABEL-1249 BABEL-1251 +BABEL-1291 BABEL-1319 +BABEL-1438 BABEL-1444 BABEL-1465 BABEL-1466 +BABEL-1475 +BABEL-1493 +BABEL-1510 +BABEL-1566 +BABEL-1625 BABEL-1654 +BABEL-1683 BABEL-1715 -BABEL-2086 -BABEL-3314 -BABEL-TABLEOPTIONS -BABEL-2765 -BABEL-2819 -BABEL-2917 -BABEL-2955 -BABEL-3358 -BABEL-3747 -BABEL-3781 -BABEL-3802 -BABEL-3914 -temp-tables -table-variable -TestNotNull -Test-Identity -Test-Computed-Columns -BABEL-1189 -BABEL-1062 -BABEL-1243 -BABEL-1493 +BABEL-1953 BABEL-1963 +BABEL-1994-CHAR +BABEL-1994-VARCHAR +BABEL-2086 BABEL-2203 BABEL-2208 BABEL-2257 BABEL-2449 BABEL-2535 -BABEL-2787-2 +BABEL-2765 BABEL-2787 +BABEL-2787-2 +BABEL-2795 BABEL-2805 BABEL-2812 +BABEL-2819 BABEL-2845 BABEL-2884 +BABEL-2917 BABEL-2944 +BABEL-2955 +BABEL-3000 +BABEL-3000-dep +BABEL-3010 BABEL-3116 BABEL-3117 BABEL-3118 +BABEL-3121 +BABEL-3144 +BABEL-3147 +BABEL-3166 +BABEL-3192 +BABEL-3204 +BABEL-3213 +BABEL-3215 +BABEL-3221 +BABEL-3234 BABEL-3249 +BABEL-3268 +BABEL-328 +BABEL-3314 +BABEL-3347 +BABEL-3358 +BABEL-3360 +BABEL-3369 +BABEL-3370 +BABEL-3380 +BABEL-3402 +BABEL-3474 BABEL-3486 +BABEL-3513 +BABEL-3556 +BABEL-3588 BABEL-3614 +BABEL-3640 BABEL-3646 +BABEL-3655 +BABEL-3657 +BABEL-3702 +BABEL-3747 +BABEL-3748 +BABEL-3781 +BABEL-3802 +BABEL-3818 BABEL-383 +BABEL-3914 +BABEL-3938 +BABEL-404 BABEL-405 +BABEL-4078 +BABEL-4098 +babel_417 +BABEL-493 +BABEL-621 +BABEL-728 +BABEL-733 +BABEL-741 +BABEL-775 +BABEL-889 BABEL-937 -forjson -forjson-subquery -forjson-datatypes -forxml -forxml-subquery -BABEL-PROCID -babel_trigger -insteadoftriggers_with_transaction -insteadof_nested_trigger_inside_proc -insteadof_nested_trigger_with_dml -nested_trigger_inside_proc -nested_trigger_with_dml -triggers_with_transaction -Test-sp_addrole -Test-sp_addrolemember -Test-sp_droprole -Test-sp_droprolemember -Test-sp_helpdbfixedrole -Test-sp_helpsrvrolemember -Test-sp_set_session_context -Test-sp_helpuser -TestTableType +BABEL-APPLOCK +babel_char +BABEL-CHECK-CONSTRAINT BABEL-CROSS-DB -BABEL-LOGIN -BABEL-USER -BABEL-ROLE -babelfish_sysdatabases -babelfish_namespace_ext +babel_datatype_sqlvariant +babel_datetime +BABEL-EXECUTE_AS_CALLER +BABEL-EXTENDEDPROPERTY babelfish_authid_login_ext babelfish_authid_user_ext +babelfish_cast_floor babelfish_inconsistent_metadata +babelfish_integrity_checker babelfish_migration_mode -schema_resolution_func -BABEL-3147 -collation_tests_arabic -collation_tests_greek -collation_tests_mongolian -collation_tests_polish -collation_tests -babel_datetime -babel_char -BABEL-SQUARE -BABEL-728 +babelfish_namespace_ext +babelfish_sysdatabases babel_function_string -BABEL-1566 -BABEL-3360 -BABEL-3380 +BABEL_GRANT_CONNECT babel_isnumeric -HAS_DBACCESS -BABEL-1475 -BABEL-1510 -BABEL-3213 -BABEL-3010 -BABEL-3369 -BABEL-3370 +BABEL-LOGIN +BABEL-LOGIN-USER-EXT +BABEL-NEXT-VALUE-FOR +BABEL_OBJECT_DEFINITION +BABEL_OBJECT_ID +BABEL_OBJECT_NAME +BABEL-PG-SYSTEM-FUNCTIONS +BABEL-PROCID BABEL-RAND -BABEL-741 +BABEL-ROLE BABEL-ROLE-MEMBER -tdscollation -BABEL-EXTENDEDPROPERTY -BABEL-EXECUTE_AS_CALLER -sys-filegroups -sys-filetables -sys-fulltext_indexes -sys-hash_indexes -sys-plan_guides -sp_tablecollations -sys-assemblies -BABEL-LOGIN-USER-EXT -bitwise_not-operator -BABEL-1683 -BABEL-1953 -schema_resolution_trigger -sys_all_objects-dep -sys-columns-dep -sys-databases-dep -sys-foreign_key_columns-dep -sys-foreign_keys-dep -sys-identity_columns-dep -sys-indexes-dep -sys-key_constraints-dep -sys-schemas-dep -sys-sp_tables_view-dep -sys-sysforeignkeys-dep -sys-tables-dep -sys-types-dep -sys-views-dep -sys-check_constraints-dep -sys-computed_columns-dep -sys-default_constraints-dep -sys-index_columns-dep -sys-sp_databases-dep -sys-syscolumns-dep -sys-dm_exec_connections-dep -sys-dm_exec_sessions-dep -sys-table_types-dep -sys-all_sql_modules-dep -sys-sql_modules-dep -sys-system_sql_modules-dep -sys-triggers-dep -sys-proc_param_helper-dep -sys-sp_pkeys -sys-sp_statistics -sys-userid-dep -BABEL-APPLOCK -BABEL-1438 -BABEL-SP_DATATYPE_INFO +BABEL_SCHEMATA BABEL-SPCOLUMNS -BABEL-SP_TABLES -BABEL-SP_SPECIAL_COLUMNS -BABEL-SP_TABLE_PRIVILIGES -BABEL-SP_FKEYS -BABEL-SP_STORED_PROCEDURES -BABEL-SP_SPROC_COLUMNS -BABEL-3000 -sys-sp_pkeys-dep -sys-sp_statistics-dep BABEL-SPCOLUMNS-dep BABEL-SP_COLUMNS_MANAGED-dep -BABEL-SP_SPECIAL_COLUMNS-dep -BABEL-SP_SPECIAL_COLUMNS_100-dep +BABEL-SP_DATATYPE_INFO +BABEL-SP_FKEYS BABEL-SP_FKEYS-dep -BABEL-SP_STORED_PROCEDURES-dep -BABEL-SP_SPROC_COLUMNS-dep +BABEL-sp_helpdb +BABEL-SP_SPECIAL_COLUMNS +BABEL-SP_SPECIAL_COLUMNS_100-dep +BABEL-SP_SPECIAL_COLUMNS-dep +BABEL-SP_SPROC_COLUMNS BABEL-SP_SPROC_COLUMNS_100-dep -BABEL-3000-dep -Test-sp_helprole-dep -Test-sp_helprolemember-dep +BABEL-SP_SPROC_COLUMNS-dep +BABEL-SP_STORED_PROCEDURES +BABEL-SP_STORED_PROCEDURES-dep +BABEL-SP_TABLE_PRIVILIGES +BABEL-SP_TABLES +babel_sqlvariant_cast_compare +BABEL-SQUARE +BABEL-TABLEOPTIONS +babel_trigger +babel_try_parse +BABEL-USER +bbf_view_def +binary-index +bitwise_not-operator +case_insensitive_collation +cast_numeric_types_to_datetime +cast_numeric_types_to_smalldatetime +collation_tests +collation_tests_arabic +collation_tests_greek +collation_tests_mongolian +collation_tests_polish +column_domain_usage +constraint_column_usage +dateadd_internal_df +datediff_big +datediff_internal_date +datepart +datetime2fromparts +forjson +forjson-datatypes +forjson-subquery format +forxml +forxml-subquery +fulltextserviceproperty +get_tds_id +HAS_DBACCESS +indexproperty +insteadof_nested_trigger_inside_proc +insteadof_nested_trigger_with_dml +insteadoftriggers_with_transaction +ISC-Columns +ISC-Table_Constraints +ISC-Tables +is_srvrolemember +msdb-dbo-fn_syspolicy_is_automation_enabled +msdb-dbo-syspolicy_configuration msdb-dbo-syspolicy_system_health_state +nested_trigger_inside_proc +nested_trigger_with_dml +objectpropertyex +openjson +orderby-before-15_3 +routines_definition +rowcount +schema_resolution_func +schema_resolution_proc +schema_resolution_trigger +sp_describe_first_result_set +sp_tablecollations +str sys-all_columns sys-all_columns-dep +sys_all_objects +sys_all_objects-dep +sys-all_parameters +sys-all_parameters-dep +sys-all_sql_modules +sys-all_sql_modules-dep +sys-all_views +sys-assemblies sys-assembly_modules +sys-assembly_types +sys_babelfish_configurations_view sys-change_tracking_databases sys-change_tracking_tables sys-check_constraints +sys-check_constraints-dep +sys-column-property sys-columns +sys-columns-dep sys-computed_columns -sys-data_spaces +sys-computed_columns-dep +sys-configurations sys-database_files sys-database_filestream_options +sys-database_mirroring +sys_database_principals_dep sys-database_recovery_status +sys-databases +sys-databases-dep +sys-data_spaces +sys-datefirst sys-default_constraints +sys-default_constraints-dep sys-dm_exec_connections +sys-dm_exec_connections-dep sys-dm_exec_sessions +sys-dm_exec_sessions-dep sys-dm_hadr_cluster sys-dm_hadr_database_replica_states sys-dm_os_host_info sys-endpoints +sys-events sys-extended_properties +sys-filegroups +sys-filetables sys-filetable_system_defined_objects sys-foreign_key_columns +sys-foreign_key_columns-dep sys-foreign_keys +sys-foreign_keys-dep sys-fulltext_catalogs sys-fulltext_index_columns +sys-fulltext_indexes sys-fulltext_languages sys-fulltext_stoplists +sys-hash_indexes +sys-has_perms_by_name +sys-has_perms_by_name-dep +sys-host_name sys-identity_columns +sys-identity_columns-dep sys-index_columns +sys-index_columns-dep sys-indexes +sys-indexes-dep sys-key_constraints +sys-key_constraints-dep +sys-lock_timeout sys-master_files +sys-max_connections +sys-numbered_procedures +sys-objects +sys-original_login sys-partitions sys-partitions-dep +sys-plan_guides +sys-procedures +sys-proc_param_helper-dep sys-registered_search_property_lists +sys-schema-name sys-schemas +sys-schemas-dep sys-selective_xml_index_paths +sys-server_principals +sys_server_principals_dep sys-sid_binary +sys-spatial_indexes +sys-spatial_index_tessellations sys-sp_databases +sys-sp_databases-dep +sys-sp_pkeys +sys-sp_pkeys-dep +sys-sp_statistics +sys-sp_statistics-dep sys-sp_tables_view -sys-spatial_index_tessellations -sys-spatial_indexes +sys-sp_tables_view-dep +sys-sql_modules +sys-sql_modules-dep sys-stats +sys-suser_sid sys-synonyms sys-syscharsets sys-syscolumns +sys-syscolumns-dep +sys-sysdatabases sys-sysforeignkeys +sys-sysforeignkeys-dep +sys-sysindexes sys-syslanguages +sys-sysobjects +sys-system_objects sys-system_sql_modules -sys-table_types +sys-system_sql_modules-dep sys-tables +sys-tables-dep +sys-table_types +sys-table_types-dep +sys-table_types_internal +sys-table_types_internal-dep +SYSTEM_USER +sys-trigger_events +sys-trigger_nestlevel sys-triggers +sys-triggers-dep sys-types +sys-types-dep +sys-userid-dep sys-views +sys-views-dep sys-xml_indexes sys-xml_schema_collections -sys_all_objects -sys_babelfish_configurations_view -BABEL-1249 -BABEL-1291 -BABEL-1994-CHAR -BABEL-1994-VARCHAR -BABEL-889 -babel_417 -babel_datatype_sqlvariant -babel_sqlvariant_cast_compare -BABEL-3347 -BABEL-3144 -sys-all_parameters-dep -BABEL-3556 -BABEL-3588 -BABEL-3268 -BABEL-3513 -BABEL_GRANT_CONNECT -BABEL-sp_helpdb -BABEL-2795 -babelfish_integrity_checker -get_tds_id -BABEL-PG-SYSTEM-FUNCTIONS -BABEL-3655 -sys-table_types_internal -sys-table_types_internal-dep -BABEL-CHECK-CONSTRAINT -BABEL-3640 -BABEL-3748 -openjson -BABEL-3702 -sys-sysindexes -sys-system_objects -ISC-Tables -ISC-Columns -#ISC-Check-Constraints -ISC-Table_Constraints -sys_server_principals_dep -sys_database_principals_dep -atn2 -datediff_big -app_name -str -case_insensitive_collation -sys-has_perms_by_name -sys-has_perms_by_name-dep -AVG-Aggregate-common -AVG-Aggregate-Dep -bbf_view_def -sys-all_sql_modules -sys-sql_modules -BABEL_OBJECT_ID -test_windows_login_before_15_2 -BABEL_OBJECT_DEFINITION -BABEL_SCHEMATA -datediff_internal_date -BABEL_OBJECT_NAME +table-variable +tdscollation +temp-tables +TestBigInt +TestBinary +TestBIT +TestChar +Test-Computed-Columns +TestDate +TestDatetime +TestDatetime2 +TestDatetime-numeric-representation +TestDecimal +TestFloat +Test-Identity +TestImage +TestInt +TestMoney +TestNotNull +TestNumeric +TestReal +TestSmallDatetime +TestSmallInt +TestSmallMoney +Test-sp_addrole +Test-sp_addrolemember +Test-sp_droprole +Test-sp_droprolemember +Test-sp_helpdbfixedrole +Test-sp_helprole-dep +Test-sp_helprolemember-dep +Test-sp_helpsrvrolemember +Test-sp_helpuser Test-sp_rename Test-sp_rename-dep -BABEL-3657 -BABEL-733 -BABEL-3938 -binary-index -BABEL-3818 -rowcount -BABEL-1625 -BABEL-3474 -dateadd_internal_df -datetime2fromparts +Test-sp_set_session_context +TestSQLVariant +TestTableType +TestText +TestTime +TestTinyInt +TestUDD +TestUniqueIdentifier +TestVarChar +test_windows_login_before_15_2 +TestXML timefromparts -orderby-before-15_3 -BABEL-3215 -BABEL-NEXT-VALUE-FOR -BABEL-4098 -BABEL-4078 +triggers_with_transaction diff --git a/test/JDBC/upgrade/15_1/schedule b/test/JDBC/upgrade/15_1/schedule index 98bb8f8298..e31e64d534 100644 --- a/test/JDBC/upgrade/15_1/schedule +++ b/test/JDBC/upgrade/15_1/schedule @@ -1,382 +1,380 @@ # Schedule File for JDBC Test Framework for local run # 1. Lines starting with '#' will be treated as comments -# 2. To run a postgres command: cmd#!#postgresql#!# +# 2. To run a postgres command: cmd#!#postgresql#!# # 3. To run a T-SQL command: cmd#!#sqlserver#!# -# 4. Keyword "all" is equivalent to running all test files in -# input folder -# 5. To add a test, add test name (without extension, -vu-prepare, -vu-verify and -vu-cleanup. For example if test file name is TestBigInt-vu-prepare.txt write TestBigInt) on a new line +# 4. Keyword "all" is equivalent to running all test files in input folder +# 5. To add a test, add test name (without extension, , and . For example if test file name is TestBigInt.txt write TestBigInt) on a new line # This should be the first test to check there are no duplicated object_ids BABEL-3613 -babelfish_cast_floor -babel_try_parse -TestBigInt -TestBinary -TestBIT -TestChar -TestDatetime2 -TestDatetime -TestDatetime-numeric-representation -TestDate -TestDecimal -TestFloat -TestImage -TestInt -TestMoney -TestNumeric -TestReal -TestSmallDatetime -TestSmallInt -TestSmallMoney -TestSQLVariant -TestText -TestTime -TestTinyInt -TestUDD -TestUniqueIdentifier -TestVarChar -TestXML -sys-assembly_types -sys-database_mirroring -sys-databases -sys-numbered_procedures -BABEL-3121 -sys-events -sys-suser_sid -sys-trigger_events -BABEL-328 -BABEL-3166 -BABEL-3192 -BABEL-3221 -BABEL-3204 -BABEL-3234 -BABEL-3402 -cast_numeric_types_to_datetime -cast_numeric_types_to_smalldatetime -routines_definition_before-14_7-or-15_2 -column_domain_usage -constraint_column_usage -sp_describe_first_result_set -sys-host_name -SYSTEM_USER -indexproperty -sys-all_parameters -msdb-dbo-syspolicy_configuration -sys-all_views -datepart -sys-server_principals -fulltextserviceproperty -is_srvrolemember -msdb-dbo-fn_syspolicy_is_automation_enabled -# Takes too long, tracking with BABEL-3675 -# objectproperty -objectpropertyex -sys-column-property -sys-configurations -sys-datefirst -sys-lock_timeout -sys-max_connections -sys-original_login -sys-schema-name -sys-objects -sys-procedures -sys-sysdatabases -sys-sysobjects -sys-trigger_nestlevel -schema_resolution_proc -BABEL-404 -BABEL-493 -BABEL-621 -BABEL-775 +AVG-Aggregate-common +AVG-Aggregate-Dep-before-15-2-or-14-7 +BABEL-1062 +BABEL-1189 BABEL-1206 +BABEL-1243 +BABEL-1249 BABEL-1251 +BABEL-1291 BABEL-1319 +BABEL-1438 BABEL-1444 BABEL-1465 BABEL-1466 +BABEL-1475 +BABEL-1493 +BABEL-1510 +BABEL-1566 +BABEL-1625 BABEL-1654 +BABEL-1683 BABEL-1715 -BABEL-2086 -BABEL-3314 -BABEL-TABLEOPTIONS -BABEL-2765 -BABEL-2819 -BABEL-2917 -BABEL-2955 -BABEL-3358 -temp-tables -table-variable -TestNotNull -Test-Identity-before-14_7-or-15_2 -Test-Computed-Columns -BABEL-1189 -BABEL-1062 -BABEL-1243 -BABEL-1493 +BABEL-1953 BABEL-1963 +BABEL-1994-CHAR +BABEL-1994-VARCHAR +BABEL-2086 BABEL-2203 BABEL-2208 BABEL-2257 BABEL-2449 BABEL-2535 -BABEL-2787-2 +BABEL-2765 BABEL-2787 +BABEL-2787-2 +BABEL-2795 BABEL-2805 BABEL-2812 +BABEL-2819 BABEL-2845 BABEL-2884 +BABEL-2917 BABEL-2944 +BABEL-2955 +BABEL-3000 +BABEL-3000-dep +BABEL-3010 BABEL-3116 BABEL-3117 BABEL-3118 +BABEL-3121 +BABEL-3144 +BABEL-3147 +BABEL-3166 +BABEL-3192 +BABEL-3204 +BABEL-3213 +BABEL-3215 +BABEL-3221 +BABEL-3234 BABEL-3249 +BABEL-3268 +BABEL-328 +BABEL-3314 +BABEL-3347 +BABEL-3358 +BABEL-3360 +BABEL-3369 +BABEL-3370 +BABEL-3380 +BABEL-3402 +BABEL-3474 BABEL-3486 +BABEL-3513 +BABEL-3556 +BABEL-3588 BABEL-3614 +BABEL-3640 BABEL-3646 +BABEL-3655 +BABEL-3657 +BABEL-3748-before-14_7 +BABEL-3801 +BABEL-3818 BABEL-383 +BABEL-3938 +BABEL-404 BABEL-405 +BABEL-4078-before-14_8-or-15_3 +babel_417 +BABEL-493 +BABEL-621 +BABEL-728 +BABEL-741 +BABEL-775 +BABEL-889 BABEL-937 -forjson -forjson-datatypes -forxml -BABEL-PROCID -babel_trigger -insteadoftriggers_with_transaction -insteadof_nested_trigger_inside_proc -insteadof_nested_trigger_with_dml -nested_trigger_inside_proc -nested_trigger_with_dml -triggers_with_transaction -Test-sp_addrole -Test-sp_addrolemember -Test-sp_droprole -Test-sp_droprolemember -Test-sp_helpdbfixedrole -Test-sp_helpsrvrolemember -Test-sp_helpuser -TestTableType +BABEL-APPLOCK +babel_char +BABEL-CHECK-CONSTRAINT BABEL-CROSS-DB -BABEL-LOGIN -BABEL-USER -BABEL-ROLE -babelfish_sysdatabases -babelfish_namespace_ext +babel_datatype_sqlvariant +babel_datetime +BABEL-EXTENDEDPROPERTY babelfish_authid_login_ext babelfish_authid_user_ext +babelfish_cast_floor babelfish_inconsistent_metadata +babelfish_integrity_checker babelfish_migration_mode -schema_resolution_func -BABEL-3147 -collation_tests_arabic -collation_tests_greek -collation_tests_mongolian -collation_tests_polish -collation_tests -babel_datetime -babel_char -BABEL-SQUARE -BABEL-728 +babelfish_namespace_ext +babelfish_sysdatabases babel_function_string -BABEL-1566 -BABEL-3360 -BABEL-3380 +BABEL_GRANT_CONNECT babel_isnumeric -HAS_DBACCESS -BABEL-1475 -BABEL-1510 -BABEL-3213 -BABEL-3010 -BABEL-3369 -BABEL-3370 -BABEL-RAND -BABEL-741 -BABEL-ROLE-MEMBER -tdscollation -BABEL-EXTENDEDPROPERTY -sys-filegroups -sys-filetables -sys-fulltext_indexes -sys-hash_indexes -sys-plan_guides -sp_tablecollations -sys-assemblies -sys-userid-dep +BABEL-LOGIN BABEL-LOGIN-USER-EXT -bitwise_not-operator -BABEL-1683 -BABEL-1953 -schema_resolution_trigger -sys_all_objects-dep -sys-columns-dep -sys-databases-dep -sys-foreign_key_columns-dep -sys-foreign_keys-dep -sys-identity_columns-dep -sys-indexes-dep -sys-key_constraints-dep -sys-schemas-dep -sys-sp_tables_view-dep -sys-sysforeignkeys-dep -sys-tables-dep -sys-types-dep -sys-views-dep -sys-check_constraints-dep -sys-computed_columns-dep -sys-default_constraints-dep -sys-index_columns-dep -sys-sp_databases-dep -sys-syscolumns-dep -sys-dm_exec_connections-dep -sys-dm_exec_sessions-dep -sys-table_types-dep -sys-all_sql_modules-dep -sys-sql_modules-dep -sys-system_sql_modules-dep -sys-triggers-dep -sys-proc_param_helper-dep -sys-sp_pkeys -sys-sp_statistics -BABEL-APPLOCK -BABEL-1438 -BABEL-SP_DATATYPE_INFO -BABEL-SPCOLUMNS -BABEL-SP_TABLES -BABEL-SP_SPECIAL_COLUMNS -BABEL-SP_TABLE_PRIVILIGES -BABEL-SP_FKEYS -BABEL-SP_STORED_PROCEDURES -BABEL-SP_SPROC_COLUMNS -BABEL-3000 -sys-sp_pkeys-dep -sys-sp_statistics-dep +BABEL_OBJECT_ID +BABEL_OBJECT_NAME +BABEL-PG-SYSTEM-FUNCTIONS +BABEL-PROCID +BABEL-RAND +BABEL-ROLE +BABEL-ROLE-MEMBER +BABEL_SCHEMATA +BABEL-SPCOLUMNS BABEL-SPCOLUMNS-dep BABEL-SP_COLUMNS_MANAGED-dep -BABEL-SP_SPECIAL_COLUMNS-dep -BABEL-SP_SPECIAL_COLUMNS_100-dep +BABEL-SP_DATATYPE_INFO +BABEL-SP_FKEYS BABEL-SP_FKEYS-dep -BABEL-SP_STORED_PROCEDURES-dep -BABEL-SP_SPROC_COLUMNS-dep +BABEL-sp_helpdb +BABEL-SP_SPECIAL_COLUMNS +BABEL-SP_SPECIAL_COLUMNS_100-dep +BABEL-SP_SPECIAL_COLUMNS-dep +BABEL-SP_SPROC_COLUMNS BABEL-SP_SPROC_COLUMNS_100-dep -BABEL-3000-dep -Test-sp_helprole-dep -Test-sp_helprolemember-dep +BABEL-SP_SPROC_COLUMNS-dep +BABEL-SP_STORED_PROCEDURES +BABEL-SP_STORED_PROCEDURES-dep +BABEL-SP_TABLE_PRIVILIGES +BABEL-SP_TABLES +babel_sqlvariant_cast_compare +BABEL-SQUARE +BABEL-TABLEOPTIONS +babel_trigger +babel_try_parse +BABEL-USER +bbf_view_def-before-14_7-or-15_2 +binary-index +bitwise_not-operator +cast_numeric_types_to_datetime +cast_numeric_types_to_smalldatetime +collation_tests +collation_tests_arabic +collation_tests_greek +collation_tests_mongolian +collation_tests_polish +column_domain_usage +constraint_column_usage +dateadd_internal_df +datediff_internal_date-before-14_7-or-15_2 +datepart +datetime2fromparts +forjson +forjson-datatypes format +forxml +fulltextserviceproperty +get_tds_id +HAS_DBACCESS +indexproperty +insteadof_nested_trigger_inside_proc +insteadof_nested_trigger_with_dml +insteadoftriggers_with_transaction +ISC-Columns +ISC-Table_Constraints +ISC-Tables +is_srvrolemember +msdb-dbo-fn_syspolicy_is_automation_enabled +msdb-dbo-syspolicy_configuration msdb-dbo-syspolicy_system_health_state +nested_trigger_inside_proc +nested_trigger_with_dml +objectpropertyex +openjson +orderby-before-15_3 +routines_definition_before-14_7-or-15_2 +rowcount +schema_resolution_func +schema_resolution_proc +schema_resolution_trigger +sp_describe_first_result_set +sp_tablecollations sys-all_columns +sys_all_objects +sys_all_objects-dep +sys-all_parameters +sys-all_parameters-dep +sys-all_sql_modules_before-14_7-or-15_2 +sys-all_sql_modules-dep +sys-all_views +sys-assemblies sys-assembly_modules +sys-assembly_types +sys_babelfish_configurations_view sys-change_tracking_databases sys-change_tracking_tables sys-check_constraints +sys-check_constraints-dep +sys-column-property sys-columns +sys-columns-dep sys-computed_columns -sys-data_spaces +sys-computed_columns-dep +sys-configurations sys-database_files sys-database_filestream_options +sys-database_mirroring +sys_database_principals_dep sys-database_recovery_status +sys-databases +sys-databases-dep +sys-data_spaces +sys-datefirst sys-default_constraints +sys-default_constraints-dep sys-dm_exec_connections +sys-dm_exec_connections-dep sys-dm_exec_sessions +sys-dm_exec_sessions-dep sys-dm_hadr_cluster sys-dm_hadr_database_replica_states sys-dm_os_host_info sys-endpoints +sys-events sys-extended_properties +sys-filegroups +sys-filetables sys-filetable_system_defined_objects sys-foreign_key_columns +sys-foreign_key_columns-dep sys-foreign_keys +sys-foreign_keys-dep sys-fulltext_catalogs sys-fulltext_index_columns +sys-fulltext_indexes sys-fulltext_languages sys-fulltext_stoplists +sys-hash_indexes +sys-has_perms_by_name +sys-has_perms_by_name-dep +sys-host_name sys-identity_columns +sys-identity_columns-dep sys-index_columns +sys-index_columns-dep sys-indexes +sys-indexes-dep sys-key_constraints +sys-key_constraints-dep +sys-lock_timeout sys-master_files +sys-max_connections +sys-numbered_procedures +sys-objects +sys-original_login sys-partitions +sys-plan_guides +sys-procedures +sys-proc_param_helper-dep sys-registered_search_property_lists +sys-schema-name sys-schemas +sys-schemas-dep sys-selective_xml_index_paths +sys-server_principals +sys_server_principals_dep sys-sid_binary +sys-spatial_indexes +sys-spatial_index_tessellations sys-sp_databases +sys-sp_databases-dep +sys-sp_pkeys +sys-sp_pkeys-dep +sys-sp_statistics +sys-sp_statistics-dep sys-sp_tables_view -sys-spatial_index_tessellations -sys-spatial_indexes +sys-sp_tables_view-dep +sys-sql_modules_before-14_7-or-15_2 +sys-sql_modules-dep sys-stats +sys-suser_sid sys-synonyms sys-syscharsets sys-syscolumns +sys-syscolumns-dep +sys-sysdatabases sys-sysforeignkeys +sys-sysforeignkeys-dep +sys-sysindexes sys-syslanguages +sys-sysobjects +sys-system_objects sys-system_sql_modules -sys-table_types +sys-system_sql_modules-dep sys-tables +sys-tables-dep +sys-table_types +sys-table_types-dep +sys-table_types_internal +sys-table_types_internal-dep +SYSTEM_USER +sys-trigger_events +sys-trigger_nestlevel sys-triggers +sys-triggers-dep sys-types +sys-types-dep +sys-userid-dep sys-views +sys-views-dep sys-xml_indexes sys-xml_schema_collections -sys_all_objects -sys_babelfish_configurations_view -BABEL-1249 -BABEL-1291 -BABEL-1994-CHAR -BABEL-1994-VARCHAR -BABEL-889 -babel_417 -babel_datatype_sqlvariant -babel_sqlvariant_cast_compare -BABEL-3347 -BABEL-3144 -sys-all_parameters-dep -BABEL-3556 -BABEL-3588 -BABEL-3268 -BABEL-3513 -BABEL_GRANT_CONNECT -BABEL-sp_helpdb -BABEL-2795 -BABEL-3748-before-14_7 -babelfish_integrity_checker -get_tds_id -BABEL-PG-SYSTEM-FUNCTIONS -BABEL-3655 -sys-table_types_internal -sys-table_types_internal-dep -BABEL-CHECK-CONSTRAINT -BABEL-3640 -sys-sysindexes -sys-system_objects -ISC-Tables -ISC-Columns -#ISC-Check-Constraints -ISC-Table_Constraints -sys_server_principals_dep -sys_database_principals_dep +table-variable +tdscollation +temp-tables +TestBigInt +TestBinary +TestBIT +TestChar +Test-Computed-Columns +TestDate +TestDatetime +TestDatetime2 +TestDatetime-numeric-representation +TestDecimal +TestFloat +Test-Identity-before-14_7-or-15_2 +TestImage +TestInt +TestMoney +TestNotNull +TestNumeric +TestReal +TestSmallDatetime +TestSmallInt +TestSmallMoney +Test-sp_addrole +Test-sp_addrolemember +Test-sp_droprole +Test-sp_droprolemember +Test-sp_helpdbfixedrole +Test-sp_helprole-dep +Test-sp_helprolemember-dep +Test-sp_helpsrvrolemember +Test-sp_helpuser +TestSQLVariant +TestTableType +TestText +TestTime +TestTinyInt +TestUDD +TestUniqueIdentifier +TestVarChar TestVariableDataLength -BABEL-3801 -AVG-Aggregate-common -AVG-Aggregate-Dep-before-15-2-or-14-7 -bbf_view_def-before-14_7-or-15_2 -sys-all_sql_modules_before-14_7-or-15_2 -sys-sql_modules_before-14_7-or-15_2 -BABEL_OBJECT_ID test_windows_login_before_15_2 -openjson -BABEL_SCHEMATA -datediff_internal_date-before-14_7-or-15_2 -BABEL_OBJECT_NAME -BABEL-3657 -BABEL-3938 -binary-index -rowcount -BABEL-1625 -BABEL-3474 -BABEL-3818 -dateadd_internal_df -datetime2fromparts +TestXML timefromparts -orderby-before-15_3 -BABEL-3215 -BABEL-4078-before-14_8-or-15_3 +triggers_with_transaction diff --git a/test/JDBC/upgrade/15_2/schedule b/test/JDBC/upgrade/15_2/schedule index a9f5a37e73..74340a9caf 100644 --- a/test/JDBC/upgrade/15_2/schedule +++ b/test/JDBC/upgrade/15_2/schedule @@ -1,421 +1,407 @@ # Schedule File for JDBC Test Framework for local run # 1. Lines starting with '#' will be treated as comments -# 2. To run a postgres command: cmd#!#postgresql#!# +# 2. To run a postgres command: cmd#!#postgresql#!# # 3. To run a T-SQL command: cmd#!#sqlserver#!# -# 4. Keyword "all" is equivalent to running all test files in -# input folder -# 5. To add a test, add test name (without extension, -vu-prepare, -vu-verify and -vu-cleanup. For example if test file name is TestBigInt-vu-prepare.txt write TestBigInt) on a new line +# 4. Keyword "all" is equivalent to running all test files in input folder +# 5. To add a test, add test name (without extension, , and . For example if test file name is TestBigInt.txt write TestBigInt) on a new line # This should be the first test to check there are no duplicated object_ids BABEL-3613 -babelfish_cast_floor -babel_try_parse -TestBigInt -TestBinary -TestBIT -TestChar -TestDatetime2 -TestDatetime -TestDatetime-numeric-representation -TestDate -TestDecimal -TestFloat -TestImage -TestInt -TestMoney -TestNumeric -TestReal -TestSmallDatetime -TestSmallInt -TestSmallMoney -TestSQLVariant -TestText -TestTime -TestTinyInt -TestUDD -TestUniqueIdentifier -TestVarChar -TestXML -sys-assembly_types -sys-database_mirroring -sys-databases -sys-numbered_procedures -BABEL-3121 -sys-events -sys-suser_sid -sys-trigger_events -BABEL-328 -BABEL-3166 -BABEL-3192 -BABEL-3221 -BABEL-3204 -BABEL-3234 -BABEL-3402 -cast_numeric_types_to_datetime -cast_numeric_types_to_smalldatetime -routines_definition -column_domain_usage -constraint_column_usage -sp_describe_first_result_set -sys-host_name -SYSTEM_USER -indexproperty -sys-all_parameters -msdb-dbo-syspolicy_configuration -sys-all_views -datepart -sys-server_principals -fulltextserviceproperty -is_srvrolemember -msdb-dbo-fn_syspolicy_is_automation_enabled -# Takes too long, tracking with BABEL-3675 -# objectproperty -objectpropertyex -sys-column-property -sys-configurations -sys-datefirst -sys-lock_timeout -sys-max_connections -sys-original_login -sys-schema-name -sys-objects -sys-procedures -sys-sysdatabases -sys-sysobjects -sys-trigger_nestlevel -schema_resolution_proc -BABEL-404 -BABEL-493 -BABEL-621 -BABEL-775 +app_name +atn2 +AVG-Aggregate-common +AVG-Aggregate-Dep +BABEL-1062 +BABEL-1189 BABEL-1206 +BABEL-1243 +BABEL-1249 BABEL-1251 +BABEL-1291 BABEL-1319 +BABEL-1438 BABEL-1444 BABEL-1465 BABEL-1466 +BABEL-1475 +BABEL-1493 +BABEL-1510 +BABEL-1566 +BABEL-1625 BABEL-1654 +BABEL-1683 BABEL-1715 -BABEL-2086 -BABEL-3314 -BABEL-TABLEOPTIONS -BABEL-2765 -BABEL-2819 -BABEL-2917 -BABEL-2955 -BABEL-3358 -BABEL-3747 -BABEL-3781 -temp-tables -table-variable -TestNotNull -Test-Identity -Test-Computed-Columns -BABEL-1189 -BABEL-1062 -BABEL-1243 -BABEL-1493 +BABEL-1953 BABEL-1963 +BABEL-1994-CHAR +BABEL-1994-VARCHAR +BABEL-2086 BABEL-2203 BABEL-2208 BABEL-2257 BABEL-2449 BABEL-2535 -BABEL-2787-2 +BABEL-2765 BABEL-2787 +BABEL-2787-2 +BABEL-2795 BABEL-2805 BABEL-2812 +BABEL-2819 BABEL-2845 BABEL-2884 +BABEL-2917 BABEL-2944 +BABEL-2955 +BABEL-3000 +BABEL-3000-dep +BABEL-3010 BABEL-3116 BABEL-3117 BABEL-3118 +BABEL-3121 +BABEL-3144 +BABEL-3147 +BABEL-3166 +BABEL-3192 +BABEL-3204 +BABEL-3213 +BABEL-3215 +BABEL-3221 +BABEL-3234 BABEL-3249 +BABEL-3268 +BABEL-328 +BABEL-3314 +BABEL-3347 +BABEL-3358 +BABEL-3360 +BABEL-3369 +BABEL-3370 +BABEL-3380 +BABEL-3402 +BABEL-3474 BABEL-3486 +BABEL-3513 +BABEL-3556 +BABEL-3588 BABEL-3614 +BABEL-3640 BABEL-3646 +BABEL-3655 +BABEL-3657 +BABEL-3702 +BABEL-3747 +BABEL-3748 +BABEL-3781 +BABEL-3801 +BABEL-3802 +BABEL-3818 BABEL-383 +BABEL-3914 +BABEL-3938 +BABEL-404 BABEL-405 +BABEL-4078-before-14_8-or-15_3 +BABEL-4098 +babel_417 +BABEL-493 +BABEL-621 +BABEL-728 +BABEL-733 +BABEL-741 +BABEL-775 +BABEL-889 BABEL-937 -forjson -forjson-subquery -forjson-datatypes -forxml -forxml-subquery -BABEL-PROCID -babel_trigger -insteadoftriggers_with_transaction -insteadof_nested_trigger_inside_proc -insteadof_nested_trigger_with_dml -nested_trigger_inside_proc -nested_trigger_with_dml -triggers_with_transaction -Test-sp_addrole -Test-sp_addrolemember -Test-sp_droprole -Test-sp_droprolemember -Test-sp_helpdbfixedrole -Test-sp_helpsrvrolemember -Test-sp_helpuser -Test-sp_set_session_context -Test-sp_set_session_context-dep -TestTableType +BABEL-APPLOCK +babel_char +BABEL-CHECK-CONSTRAINT BABEL-CROSS-DB -BABEL-LOGIN -BABEL-USER -BABEL-ROLE -babelfish_sysdatabases -babelfish_namespace_ext +babel_datatype_sqlvariant +babel_datetime +BABEL-EXECUTE_AS_CALLER +BABEL-EXTENDEDPROPERTY babelfish_authid_login_ext babelfish_authid_user_ext +babelfish_cast_floor babelfish_inconsistent_metadata +babelfish_integrity_checker babelfish_migration_mode -schema_resolution_func -BABEL-3147 -collation_tests_arabic -collation_tests_greek -collation_tests_mongolian -collation_tests_polish -collation_tests -babel_datetime -babel_char -BABEL-SQUARE -BABEL-728 +babelfish_namespace_ext +babelfish_sysdatabases babel_function_string -BABEL-1566 -BABEL-3360 -BABEL-3380 +BABEL_GRANT_CONNECT babel_isnumeric -HAS_DBACCESS -BABEL-1475 -BABEL-1510 -BABEL-3213 -BABEL-3010 -BABEL-3369 -BABEL-3370 +BABEL-LOGIN +BABEL-LOGIN-USER-EXT +BABEL-NEXT-VALUE-FOR +BABEL_OBJECT_DEFINITION +BABEL_OBJECT_ID +BABEL_OBJECT_NAME +BABEL-PG-SYSTEM-FUNCTIONS +BABEL-PROCID BABEL-RAND -BABEL-741 +BABEL-ROLE BABEL-ROLE-MEMBER -tdscollation -BABEL-EXTENDEDPROPERTY -BABEL-EXECUTE_AS_CALLER -sys-filegroups -sys-filetables -sys-fulltext_indexes -sys-hash_indexes -sys-plan_guides -sp_tablecollations -sys-assemblies -sys-userid-dep -BABEL-LOGIN-USER-EXT -bitwise_not-operator -BABEL-1683 -BABEL-1953 -schema_resolution_trigger -sys_all_objects-dep -sys-columns-dep -sys-databases-dep -sys-foreign_key_columns-dep -sys-foreign_keys-dep -sys-identity_columns-dep -sys-indexes-dep -sys-key_constraints-dep -sys-schemas-dep -sys-sp_tables_view-dep -sys-sysforeignkeys-dep -sys-tables-dep -sys-types-dep -sys-views-dep -sys-check_constraints-dep -sys-computed_columns-dep -sys-default_constraints-dep -sys-index_columns-dep -sys-sp_databases-dep -sys-syscolumns-dep -sys-dm_exec_connections-dep -sys-dm_exec_sessions-dep -sys-table_types-dep -sys-all_sql_modules-dep -sys-sql_modules-dep -sys-system_sql_modules-dep -sys-triggers-dep -sys-proc_param_helper-dep -sys-sp_pkeys -sys-sp_statistics -BABEL-APPLOCK -BABEL-1438 -BABEL-SP_DATATYPE_INFO +BABEL_SCHEMATA BABEL-SPCOLUMNS -BABEL-SP_TABLES -BABEL-SP_SPECIAL_COLUMNS -BABEL-SP_TABLE_PRIVILIGES -BABEL-SP_FKEYS -BABEL-SP_STORED_PROCEDURES -BABEL-SP_SPROC_COLUMNS -BABEL-3000 -sys-sp_pkeys-dep -sys-sp_statistics-dep BABEL-SPCOLUMNS-dep BABEL-SP_COLUMNS_MANAGED-dep -BABEL-SP_SPECIAL_COLUMNS-dep -BABEL-SP_SPECIAL_COLUMNS_100-dep +BABEL-SP_DATATYPE_INFO +BABEL-SP_FKEYS BABEL-SP_FKEYS-dep -BABEL-SP_STORED_PROCEDURES-dep -BABEL-SP_SPROC_COLUMNS-dep +BABEL-sp_helpdb +BABEL-SP_SPECIAL_COLUMNS +BABEL-SP_SPECIAL_COLUMNS_100-dep +BABEL-SP_SPECIAL_COLUMNS-dep +BABEL-SP_SPROC_COLUMNS BABEL-SP_SPROC_COLUMNS_100-dep -BABEL-3000-dep -Test-sp_helprole-dep -Test-sp_helprolemember-dep +BABEL-SP_SPROC_COLUMNS-dep +BABEL-SP_STORED_PROCEDURES +BABEL-SP_STORED_PROCEDURES-dep +BABEL-SP_TABLE_PRIVILIGES +BABEL-SP_TABLES +babel_sqlvariant_cast_compare +BABEL-SQUARE +BABEL-TABLEOPTIONS +babel_trigger +babel_try_parse +BABEL-USER +bbf_view_def +binary-index +bitwise_not-operator +case_insensitive_collation +cast_numeric_types_to_datetime +cast_numeric_types_to_smalldatetime +collation_tests +collation_tests_arabic +collation_tests_greek +collation_tests_mongolian +collation_tests_polish +column_domain_usage +constraint_column_usage +dateadd_internal_df +datediff_big +datediff_internal_date +datepart +datetime2fromparts +forjson +forjson-datatypes +forjson-subquery format +forxml +forxml-subquery +fulltextserviceproperty +get_tds_id +HAS_DBACCESS +indexproperty +insteadof_nested_trigger_inside_proc +insteadof_nested_trigger_with_dml +insteadoftriggers_with_transaction +ISC-Columns +isc-schemata-dep +ISC-sequences +ISC-Table_Constraints +ISC-Tables +ISC-Views +is_srvrolemember +jira-BABEL-3504-upgrade +msdb-dbo-fn_syspolicy_is_automation_enabled +msdb-dbo-syspolicy_configuration msdb-dbo-syspolicy_system_health_state +nested_trigger_inside_proc +nested_trigger_with_dml +objectpropertyex +openjson +orderby-before-15_3 +routines_definition +rowcount +schema_resolution_func +schema_resolution_proc +schema_resolution_trigger +sp_describe_first_result_set +sp_tablecollations +str sys-all_columns sys-all_columns-dep +sys_all_objects +sys_all_objects-dep +sys-all_parameters +sys-all_parameters-dep sys-all_sql_modules +sys-all_sql_modules-dep +sys-all_views +sys-assemblies sys-assembly_modules +sys-assembly_types +sys_babelfish_configurations_view sys-change_tracking_databases sys-change_tracking_tables sys-check_constraints +sys-check_constraints-dep +sys-column-property sys-columns +sys-columns-dep sys-computed_columns -sys-data_spaces +sys-computed_columns-dep +sys-configurations sys-database_files sys-database_filestream_options +sys-database_mirroring +sys_database_principals_dep sys-database_recovery_status +sys-databases +sys-databases-dep +sys-data_spaces +sys-datefirst sys-default_constraints +sys-default_constraints-dep sys-dm_exec_connections +sys-dm_exec_connections-dep sys-dm_exec_sessions +sys-dm_exec_sessions-dep sys-dm_hadr_cluster sys-dm_hadr_database_replica_states sys-dm_os_host_info sys-endpoints +sys-events sys-extended_properties +sys-filegroups +sys-filetables sys-filetable_system_defined_objects sys-foreign_key_columns +sys-foreign_key_columns-dep sys-foreign_keys +sys-foreign_keys-dep sys-fulltext_catalogs sys-fulltext_index_columns +sys-fulltext_indexes sys-fulltext_languages sys-fulltext_stoplists +sys-hash_indexes +sys-has_perms_by_name +sys-has_perms_by_name-dep +sys-host_name sys-identity_columns +sys-identity_columns-dep sys-index_columns +sys-index_columns-dep sys-indexes +sys-indexes-dep sys-key_constraints +sys-key_constraints-dep +sys-lock_timeout sys-master_files +sys-max_connections +sys-numbered_procedures +sys-objects +sys-original_login sys-partitions sys-partitions-dep +sys-plan_guides +sys-procedures +sys-proc_param_helper-dep sys-registered_search_property_lists +sys-schema-name sys-schemas +sys-schemas-dep sys-selective_xml_index_paths +sys-server_principals +sys_server_principals_dep sys-sid_binary +sys-spatial_indexes +sys-spatial_index_tessellations sys-sp_databases +sys-sp_databases-dep +sys-sp_pkeys +sys-sp_pkeys-dep +sys-sp_statistics +sys-sp_statistics-dep sys-sp_tables_view -sys-spatial_index_tessellations -sys-spatial_indexes +sys-sp_tables_view-dep +sys-sql_modules +sys-sql_modules-dep sys-stats +sys-suser_sid sys-synonyms sys-syscharsets sys-syscolumns +sys-syscolumns-dep +sys-sysdatabases sys-sysforeignkeys +sys-sysforeignkeys-dep +sys-sysindexes sys-syslanguages +sys-sysobjects +sys-system_objects sys-system_sql_modules -sys-sql_modules -sys-table_types +sys-system_sql_modules-dep +sys-systypes sys-tables +sys-tables-dep +sys-table_types +sys-table_types-dep +sys-table_types_internal +sys-table_types_internal-dep +SYSTEM_USER +sys-trigger_events +sys-trigger_nestlevel sys-triggers +sys-triggers-dep sys-types +sys-types-dep +sys-userid-dep sys-views +sys-views-dep sys-xml_indexes sys-xml_schema_collections -sys_all_objects -sys_babelfish_configurations_view -BABEL-1249 -BABEL-1291 -BABEL-1994-CHAR -BABEL-1994-VARCHAR -BABEL-889 -babel_417 -babel_datatype_sqlvariant -babel_sqlvariant_cast_compare -BABEL-3347 -BABEL-3144 -sys-all_parameters-dep -BABEL-3556 -BABEL-3588 -BABEL-3268 -BABEL-3513 -BABEL_GRANT_CONNECT -BABEL-sp_helpdb -BABEL-2795 -babelfish_integrity_checker -get_tds_id -BABEL-PG-SYSTEM-FUNCTIONS -BABEL-3655 -sys-table_types_internal -sys-table_types_internal-dep -BABEL-CHECK-CONSTRAINT -BABEL-3640 -sys-sysindexes -sys-system_objects -ISC-Views -ISC-Tables -ISC-Columns -#ISC-Check-Constraints -ISC-Table_Constraints -sys_server_principals_dep -sys_database_principals_dep -TestVariableDataLength -BABEL-3801 -datediff_big -app_name -atn2 -str -case_insensitive_collation -BABEL-3215 -# linked_servers -ISC-sequences -jira-BABEL-3504-upgrade -# test_windows_login -sys-has_perms_by_name -sys-has_perms_by_name-dep -BABEL_SCHEMATA -isc-schemata-dep -AVG-Aggregate-common -AVG-Aggregate-Dep -bbf_view_def -BABEL_OBJECT_ID -BABEL-3802 -datediff_internal_date -BABEL_OBJECT_NAME -# Test_user_from_win_login -BABEL-3914 -# Babel_domain_mapping_test -# BABEL-3828 -# BABEL-3844 -BABEL-3748 -#test_windows_alter_login -sys-systypes -openjson -BABEL-3702 -BABEL_OBJECT_DEFINITION -BABEL-3818 +table-variable +tdscollation +temp-tables +TestBigInt +TestBinary +TestBIT +TestChar +Test-Computed-Columns +TestDate +TestDatetime +TestDatetime2 +TestDatetime-numeric-representation +TestDecimal +TestFloat +Test-Identity +TestImage +TestInt +TestMoney +TestNotNull +TestNumeric +TestReal +TestSmallDatetime +TestSmallInt +TestSmallMoney +Test-sp_addrole +Test-sp_addrolemember +Test-sp_droprole +Test-sp_droprolemember +Test-sp_helpdbfixedrole +Test-sp_helprole-dep +Test-sp_helprolemember-dep +Test-sp_helpsrvrolemember +Test-sp_helpuser Test-sp_rename Test-sp_rename-dep -# openquery_upgrd -BABEL-3657 -# test_windows_alter_user -BABEL-733 -BABEL-3938 -BABEL-NEXT-VALUE-FOR -BABEL-4098 -binary-index -rowcount -# test_windows_sp_helpuser -BABEL-1625 -BABEL-3474 -dateadd_internal_df -datetime2fromparts +Test-sp_set_session_context +Test-sp_set_session_context-dep +TestSQLVariant +TestTableType +TestText +TestTime +TestTinyInt +TestUDD +TestUniqueIdentifier +TestVarChar +TestVariableDataLength +TestXML timefromparts -orderby-before-15_3 -BABEL-4078-before-14_8-or-15_3 +triggers_with_transaction diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index 6830f8371f..aa1fa2e5b9 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -1,431 +1,429 @@ # Schedule File for JDBC Test Framework for local run # 1. Lines starting with '#' will be treated as comments -# 2. To run a postgres command: cmd#!#postgresql#!# +# 2. To run a postgres command: cmd#!#postgresql#!# # 3. To run a T-SQL command: cmd#!#sqlserver#!# -# 4. Keyword "all" is equivalent to running all test files in -# input folder -# 5. To add a test, add test name (without extension, -vu-prepare, -vu-verify and -vu-cleanup. For example if test file name is TestBigInt-vu-prepare.txt write TestBigInt) on a new line +# 4. Keyword "all" is equivalent to running all test files in input folder +# 5. To add a test, add test name (without extension, , and . For example if test file name is TestBigInt.txt write TestBigInt) on a new line # This should be the first test to check there are no duplicated object_ids BABEL-3613 -babelfish_cast_floor -babel_try_parse -TestBigInt -TestBinary -TestBIT -TestChar -TestDatetime2 -TestDatetime -TestDatetime-numeric-representation -TestDatetime-numeric-dateaddfunction -TestDate -TestDecimal -TestFloat -TestImage -TestInt -TestMoney -TestNumeric -TestReal -TestRowVersion -TestSmallDatetime -TestSmallInt -TestSmallMoney -TestSQLVariant -TestText -TestTime -TestTinyInt -TestUDD -TestUniqueIdentifier -TestVarChar -TestXML -sys-assembly_types -sys-database_mirroring -sys-databases -sys-numbered_procedures -BABEL-3121 -sys-events -sys-suser_sid -sys-trigger_events -BABEL-328 -BABEL-3166 -BABEL-3192 -BABEL-3221 -BABEL-3204 -BABEL-3234 -BABEL-3402 -cast_numeric_types_to_datetime -cast_numeric_types_to_smalldatetime -routines_definition -column_domain_usage -constraint_column_usage -sp_describe_first_result_set -sys-host_name -SYSTEM_USER -indexproperty -sys-all_parameters -msdb-dbo-syspolicy_configuration -sys-all_views -datepart -sys-server_principals -fulltextserviceproperty -is_srvrolemember -msdb-dbo-fn_syspolicy_is_automation_enabled -# Takes too long, tracking with BABEL-3675 -# objectproperty -objectpropertyex -sys-column-property -sys-configurations -sys-datefirst -sys-lock_timeout -sys-max_connections -sys-original_login -sys-schema-name -sys-objects -sys-procedures -sys-sysdatabases -sys-sysobjects -sys-trigger_nestlevel -schema_resolution_proc -BABEL-404 -BABEL-493 -BABEL-621 -BABEL-775 +app_name +atn2 +AVG-Aggregate-common +AVG-Aggregate-Dep +BABEL-1062 +BABEL-1189 BABEL-1206 +BABEL-1243 +BABEL-1249 BABEL-1251 +BABEL-1291 BABEL-1319 +BABEL-1438 BABEL-1444 BABEL-1465 BABEL-1466 +BABEL-1475 +BABEL-1493 +BABEL-1510 +BABEL-1566 +BABEL-1625 BABEL-1654 +BABEL-1683 BABEL-1715 -BABEL-2086 -BABEL-3314 -BABEL-TABLEOPTIONS -BABEL-2765 -BABEL-2819 -BABEL-2917 -BABEL-2955 -BABEL-3358 -BABEL-3747 -BABEL-3781 -temp-tables -table-variable -TestNotNull -Test-Identity -Test-Computed-Columns -BABEL-1189 -BABEL-1062 -BABEL-1243 -BABEL-1493 +BABEL-1953 BABEL-1963 +BABEL-1994-CHAR +BABEL-1994-VARCHAR +BABEL-2086 BABEL-2203 BABEL-2208 BABEL-2257 BABEL-2449 BABEL-2535 -BABEL-2787-2 +BABEL-2765 BABEL-2787 +BABEL-2787-2 +BABEL-2795 BABEL-2805 BABEL-2812 +BABEL-2819 BABEL-2845 +BABEL-2877 BABEL-2884 +BABEL-2917 BABEL-2944 +BABEL-2955 +BABEL-3000 +BABEL-3000-dep +BABEL-3010 BABEL-3116 BABEL-3117 BABEL-3118 +BABEL-3121 +BABEL-3144 +BABEL-3147 +BABEL-3166 +BABEL-3192 +BABEL-3204 +BABEL-3213 +BABEL-3215 +BABEL-3221 +BABEL-3234 BABEL-3249 +BABEL-3268 +BABEL-328 +BABEL-3314 +BABEL-3347 +BABEL-3358 +BABEL-3360 +BABEL-3369 +BABEL-3370 +BABEL-3380 +BABEL-3402 +BABEL-3474 +BABEL-3478 BABEL-3486 +BABEL-3513 +BABEL-3556 +BABEL-3588 BABEL-3614 +BABEL-3640 BABEL-3646 +BABEL-3655 +BABEL-3657 +BABEL-3696 +BABEL-3697 +BABEL-3702 +BABEL-3747 +BABEL-3748 +BABEL-3781 +BABEL-3801 +BABEL-3802 +BABEL-3818 +BABEL-3828 BABEL-383 +BABEL-3844 +BABEL-3914 +BABEL-3938 +BABEL-404 BABEL-405 +BABEL-4078 +BABEL-4098 +babel_417 +BABEL-493 +BABEL-621 +BABEL-728 +BABEL-733 +BABEL-741 +BABEL-745 +BABEL-775 +BABEL-889 BABEL-937 -forjson -forjson-subquery -forjson-datatypes -forxml -forxml-subquery -BABEL-PROCID -babel_trigger -insteadoftriggers_with_transaction -insteadof_nested_trigger_inside_proc -insteadof_nested_trigger_with_dml -nested_trigger_inside_proc -nested_trigger_with_dml -triggers_with_transaction -Test-sp_addrole -Test-sp_addrolemember -Test-sp_droprole -Test-sp_droprolemember -Test-sp_helpdbfixedrole -Test-sp_helpsrvrolemember -Test-sp_helpuser -Test-sp_set_session_context -Test-sp_set_session_context-dep -TestTableType +BABEL-APPLOCK +babel_char +BABEL-CHECK-CONSTRAINT +babel_context_info BABEL-CROSS-DB -BABEL-LOGIN -BABEL-USER -BABEL-ROLE -babelfish_sysdatabases -babelfish_namespace_ext +babel_datatype_sqlvariant +babel_datetime +Babel_domain_mapping_test +BABEL-EXECUTE_AS_CALLER +BABEL-EXTENDEDPROPERTY babelfish_authid_login_ext babelfish_authid_user_ext +babelfish_cast_floor babelfish_inconsistent_metadata +babelfish_integrity_checker babelfish_migration_mode -schema_resolution_func -BABEL-3147 -collation_tests_arabic -collation_tests_greek -collation_tests_mongolian -collation_tests_polish -collation_tests -babel_datetime -babel_char -BABEL-SQUARE -BABEL-728 +babelfish_namespace_ext +babelfish_sysdatabases babel_function_string -BABEL-1566 -BABEL-3360 -BABEL-3380 +BABEL_GRANT_CONNECT babel_isnumeric -HAS_DBACCESS -BABEL-1475 -BABEL-1510 -BABEL-3213 -BABEL-3010 -BABEL-3369 -BABEL-3370 +BABEL-LOGIN +BABEL-LOGIN-USER-EXT +BABEL-NEXT-VALUE-FOR +BABEL_OBJECT_DEFINITION +BABEL_OBJECT_ID +BABEL_OBJECT_NAME +BABEL-PG-SYSTEM-FUNCTIONS +BABEL-PROCID BABEL-RAND -BABEL-741 +BABEL-ROLE BABEL-ROLE-MEMBER -tdscollation -BABEL-EXTENDEDPROPERTY -BABEL-EXECUTE_AS_CALLER -sys-filegroups -sys-filetables -sys-fulltext_indexes -sys-hash_indexes -sys-plan_guides -sp_tablecollations -sys-assemblies -BABEL-LOGIN-USER-EXT -bitwise_not-operator -BABEL-1683 -BABEL-1953 -schema_resolution_trigger -sys_all_objects-dep -sys-columns-dep -sys-databases-dep -sys-foreign_key_columns-dep -sys-foreign_keys-dep -sys-identity_columns-dep -sys-indexes-dep -sys-key_constraints-dep -sys-schemas-dep -sys-sp_tables_view-dep -sys-sysforeignkeys-dep -sys-tables-dep -sys-types-dep -sys-views-dep -sys-check_constraints-dep -sys-computed_columns-dep -sys-default_constraints-dep -sys-index_columns-dep -sys-sp_databases-dep -sys-syscolumns-dep -sys-dm_exec_connections-dep -sys-dm_exec_sessions-dep -sys-table_types-dep -sys-all_sql_modules-dep -sys-sql_modules-dep -sys-system_sql_modules-dep -sys-triggers-dep -sys-proc_param_helper-dep -BABEL-2877 -sys-sp_pkeys -sys-sp_statistics -BABEL-APPLOCK -BABEL-1438 -BABEL-SP_DATATYPE_INFO +BABEL_SCHEMATA BABEL-SPCOLUMNS -BABEL-SP_TABLES -BABEL-SP_SPECIAL_COLUMNS -BABEL-SP_TABLE_PRIVILIGES -BABEL-SP_FKEYS -BABEL-SP_STORED_PROCEDURES -BABEL-SP_SPROC_COLUMNS -BABEL-3000 -sys-sp_pkeys-dep -sys-sp_statistics-dep BABEL-SPCOLUMNS-dep BABEL-SP_COLUMNS_MANAGED-dep -BABEL-SP_SPECIAL_COLUMNS-dep -BABEL-SP_SPECIAL_COLUMNS_100-dep +BABEL-SP_DATATYPE_INFO +BABEL-SP_FKEYS BABEL-SP_FKEYS-dep -BABEL-SP_STORED_PROCEDURES-dep -BABEL-SP_SPROC_COLUMNS-dep +BABEL-sp_helpdb +BABEL-SP_SPECIAL_COLUMNS +BABEL-SP_SPECIAL_COLUMNS_100-dep +BABEL-SP_SPECIAL_COLUMNS-dep +BABEL-SP_SPROC_COLUMNS BABEL-SP_SPROC_COLUMNS_100-dep -BABEL-3000-dep -Test-sp_helprole-dep -Test-sp_helprolemember-dep +BABEL-SP_SPROC_COLUMNS-dep +BABEL-SP_STORED_PROCEDURES +BABEL-SP_STORED_PROCEDURES-dep +BABEL-SP_TABLE_PRIVILIGES +BABEL-SP_TABLES +babel_sqlvariant_cast_compare +BABEL-SQUARE +BABEL-TABLEOPTIONS +babel_trigger +babel_try_parse +BABEL-USER +bbf_view_def +binary-index +bitwise_not-operator +case_insensitive_collation +cast_numeric_types_to_datetime +cast_numeric_types_to_smalldatetime +collation_tests +collation_tests_arabic +collation_tests_greek +collation_tests_mongolian +collation_tests_polish +column_domain_usage +constraint_column_usage +dateadd_internal_df +datediff_big +datediff_internal_date +datepart +datetime2fromparts-after-15-2 +forjson +forjson-datatypes +forjson-subquery format +forxml +forxml-subquery +fulltextserviceproperty +get_tds_id +HAS_DBACCESS +identity_function +indexproperty +insteadof_nested_trigger_inside_proc +insteadof_nested_trigger_with_dml +insteadoftriggers_with_transaction +ISC-Columns +isc-schemata-dep +ISC-sequences +ISC-Table_Constraints +ISC-Tables +ISC-Views +is_srvrolemember +jira-BABEL-3504-upgrade +linked_servers +msdb-dbo-fn_syspolicy_is_automation_enabled +msdb-dbo-syspolicy_configuration msdb-dbo-syspolicy_system_health_state +nested_trigger_inside_proc +nested_trigger_with_dml +objectpropertyex +openjson +openquery_upgrd +orderby +routines_definition +rowcount +schema_resolution_func +schema_resolution_proc +schema_resolution_trigger +sp_describe_first_result_set +sp_tablecollations +str sys-all_columns sys-all_columns-dep +sys_all_objects +sys_all_objects-dep +sys-all_parameters +sys-all_parameters-dep sys-all_sql_modules +sys-all_sql_modules-dep +sys-all_views +sys-assemblies sys-assembly_modules +sys-assembly_types +sys_babelfish_configurations_view sys-change_tracking_databases sys-change_tracking_tables sys-check_constraints +sys-check_constraints-dep +sys-column-property sys-columns +sys-columns-dep sys-computed_columns -sys-data_spaces +sys-computed_columns-dep +sys-configurations sys-database_files sys-database_filestream_options +sys-database_mirroring +sys_database_principals_dep sys-database_recovery_status +sys-databases +sys-databases-dep +sys-data_spaces +sys-datefirst sys-default_constraints +sys-default_constraints-dep sys-dm_exec_connections +sys-dm_exec_connections-dep sys-dm_exec_sessions +sys-dm_exec_sessions-dep sys-dm_hadr_cluster sys-dm_hadr_database_replica_states sys-dm_os_host_info sys-endpoints +sys-events sys-extended_properties +sys-filegroups +sys-filetables sys-filetable_system_defined_objects sys-foreign_key_columns +sys-foreign_key_columns-dep sys-foreign_keys +sys-foreign_keys-dep sys-fulltext_catalogs sys-fulltext_index_columns +sys-fulltext_indexes sys-fulltext_languages sys-fulltext_stoplists +sys-hash_indexes +sys-has_perms_by_name +sys-has_perms_by_name-dep +sys-host_name sys-identity_columns +sys-identity_columns-dep sys-index_columns +sys-index_columns-dep sys-indexes +sys-indexes-dep sys-key_constraints +sys-key_constraints-dep +sys-lock_timeout sys-master_files +sys-max_connections +sys-numbered_procedures +sys-objects +sys-original_login sys-partitions sys-partitions-dep +sys-plan_guides +sys-procedures +sys-proc_param_helper-dep sys-registered_search_property_lists +sys-schema-name sys-schemas +sys-schemas-dep sys-selective_xml_index_paths +sys-server_principals +sys_server_principals_dep sys-sid_binary +sys-spatial_indexes +sys-spatial_index_tessellations sys-sp_databases +sys-sp_databases-dep +sys-sp_pkeys +sys-sp_pkeys-dep +sys-sp_statistics +sys-sp_statistics-dep sys-sp_tables_view -sys-spatial_index_tessellations -sys-spatial_indexes +sys-sp_tables_view-dep +sys-sql_modules +sys-sql_modules-dep sys-stats +sys-suser_sid +sys-suser_sname sys-synonyms sys-syscharsets sys-syscolumns +sys-syscolumns-dep +sys-sysdatabases sys-sysforeignkeys +sys-sysforeignkeys-dep +sys-sysindexes sys-syslanguages +sys-sysobjects +sys-system_objects sys-system_sql_modules -sys-sql_modules -sys-table_types +sys-system_sql_modules-dep +sys-systypes +sys_sysusers_dep sys-tables +sys-tables-dep +sys-table_types +sys-table_types-dep +sys-table_types_internal +sys-table_types_internal-dep +SYSTEM_USER +sys-trigger_events +sys-trigger_nestlevel sys-triggers +sys-triggers-dep sys-types +sys-types-dep +sys-userid sys-views +sys-views-dep sys-xml_indexes sys-xml_schema_collections -sys_all_objects -sys_babelfish_configurations_view -BABEL-1249 -BABEL-1291 -BABEL-1994-CHAR -BABEL-1994-VARCHAR -BABEL-889 -babel_417 -babel_datatype_sqlvariant -babel_sqlvariant_cast_compare -BABEL-3347 -BABEL-3144 -sys-all_parameters-dep -BABEL-3556 -BABEL-3588 -BABEL-3268 -BABEL-3513 -BABEL_GRANT_CONNECT -BABEL-sp_helpdb -BABEL-2795 -babelfish_integrity_checker -get_tds_id -BABEL-PG-SYSTEM-FUNCTIONS -BABEL-3655 -sys-table_types_internal -sys-table_types_internal-dep -BABEL-CHECK-CONSTRAINT -BABEL-3640 -sys-sysindexes -sys-system_objects -ISC-Views -ISC-Tables -ISC-Columns -#ISC-Check-Constraints -ISC-Table_Constraints -sys_server_principals_dep -sys_database_principals_dep -TestVariableDataLength -BABEL-3801 -datediff_big -app_name -atn2 -str -case_insensitive_collation -linked_servers -ISC-sequences -jira-BABEL-3504-upgrade -test_windows_login -sys-has_perms_by_name -sys-has_perms_by_name-dep -BABEL_SCHEMATA -isc-schemata-dep -AVG-Aggregate-common -AVG-Aggregate-Dep -bbf_view_def -BABEL_OBJECT_ID -BABEL-3802 -datediff_internal_date -BABEL_OBJECT_NAME -Test_user_from_win_login -BABEL-3914 -Babel_domain_mapping_test -BABEL-3828 -BABEL-3844 -BABEL-3748 -test_windows_alter_login -sys-systypes -openjson -BABEL-3702 -BABEL-3696 -BABEL-3697 +table-variable +tdscollation +temp-tables +TestBigInt +TestBinary +TestBIT +TestChar +Test-Computed-Columns +TestDate +TestDatetime +TestDatetime2 +TestDatetime-numeric-dateaddfunction +TestDatetime-numeric-representation +TestDecimal +TestFloat +Test-Identity +TestImage +TestInt +TestMoney +TestNotNull +TestNumeric +TestReal +TestRowVersion +TestSmallDatetime +TestSmallInt +TestSmallMoney +Test-sp_addrole +Test-sp_addrolemember Test-sp_babelfish_volatility -BABEL_OBJECT_DEFINITION +Test-sp_droprole +Test-sp_droprolemember +Test-sp_helpdbfixedrole +Test-sp_helprole-dep +Test-sp_helprolemember-dep +Test-sp_helpsrvrolemember +Test-sp_helpuser Test-sp_rename Test-sp_rename-dep -openquery_upgrd -BABEL-3657 +Test-sp_set_session_context +Test-sp_set_session_context-dep +TestSQLVariant +TestTableType +TestText +TestTime +TestTinyInt +TestUDD +TestUniqueIdentifier +Test_user_from_win_login +TestVarChar +TestVariableDataLength +test_windows_alter_login test_windows_alter_user -BABEL-733 -BABEL-745 -BABEL-3938 -sys-userid -BABEL-NEXT-VALUE-FOR -BABEL-4098 -babel_context_info -binary-index +test_windows_login test_windows_sp_helpuser -BABEL-3478 -rowcount -BABEL-1625 -BABEL-3474 -BABEL-3818 -dateadd_internal_df -datetime2fromparts-after-15-2 +TestXML timefromparts -orderby -sys_sysusers_dep -BABEL-3215 -BABEL-4078 +triggers_with_transaction diff --git a/test/JDBC/upgrade/master/schedule b/test/JDBC/upgrade/master/schedule index c7dbf8097c..a5e5ac061c 100644 --- a/test/JDBC/upgrade/master/schedule +++ b/test/JDBC/upgrade/master/schedule @@ -1,417 +1,305 @@ # Schedule File for JDBC Test Framework for local run # 1. Lines starting with '#' will be treated as comments -# 2. To run a postgres command: cmd#!#postgresql#!# +# 2. To run a postgres command: cmd#!#postgresql#!# # 3. To run a T-SQL command: cmd#!#sqlserver#!# -# 4. Keyword "all" is equivalent to running all test files in -# input folder -# 5. To add a test, add test name (without extension, -vu-prepare, -vu-verify and -vu-cleanup. For example if test file name is TestBigInt-vu-prepare.txt write TestBigInt) on a new line +# 4. Keyword "all" is equivalent to running all test files in input folder +# 5. To add a test, add test name (without extension, , and . For example if test file name is TestBigInt.txt write TestBigInt) on a new line # This should be the first test to check there are no duplicated object_ids BABEL-3613 -babelfish_cast_floor -babel_try_parse -TestBigInt -TestBinary -TestBIT -TestChar -TestDatetime2 -TestDatetime -TestDate -TestDecimal -TestFloat -TestImage -TestInt -TestMoney -TestNumeric -TestReal -TestRowVersion -TestSmallDatetime -TestSmallInt -TestSmallMoney -# TestSQLVariant -TestText -TestTime -TestTinyInt -TestUDD -TestUniqueIdentifier -TestVarChar -TestXML -sys-assembly_types -sys-database_mirroring -# sys-databases -sys-numbered_procedures -BABEL-3121 -# sys-events -sys-suser_sid -# sys-trigger_events -BABEL-328 -# BABEL-3166 -# BABEL-3192 -# BABEL-3221 -# BABEL-3204 -# BABEL-3234 -BABEL-3402 -cast_numeric_types_to_datetime -cast_numeric_types_to_smalldatetime -# routines_definition -# column_domain_usage -# constraint_column_usage -sp_describe_first_result_set -sys-host_name -# SYSTEM_USER -indexproperty -sys-all_parameters -msdb-dbo-syspolicy_configuration -sys-all_views -datepart -sys-server_principals -fulltextserviceproperty -is_srvrolemember -msdb-dbo-fn_syspolicy_is_automation_enabled -# Takes too long, tracking with BABEL-3675 -# objectproperty -objectpropertyex -sys-column-property -sys-configurations -sys-datefirst -sys-lock_timeout -sys-max_connections -sys-original_login -sys-schema-name -# sys-objects -# sys-procedures -# sys-sysdatabases -sys-sysobjects -sys-trigger_nestlevel -# schema_resolution_proc -BABEL-404 -BABEL-493 -BABEL-621 -BABEL-775 +app_name +atn2 +AVG-Aggregate-common +AVG-Aggregate-Dep +BABEL-1062 +BABEL-1189 BABEL-1206 +BABEL-1243 +BABEL-1249 BABEL-1251 +BABEL-1291 BABEL-1319 +BABEL-1438 BABEL-1444 BABEL-1465 BABEL-1466 +BABEL-1475 +BABEL-1493 +BABEL-1510 +BABEL-1566 +BABEL-1625 BABEL-1654 +BABEL-1683 BABEL-1715 -BABEL-2086 -BABEL-3314 -BABEL-TABLEOPTIONS -BABEL-2765 -BABEL-2819 -BABEL-2917 -BABEL-2955 -BABEL-3358 -BABEL-3747 -BABEL-3781 -temp-tables -# table-variable -# TestNotNull -Test-Identity -Test-Computed-Columns -BABEL-1189 -BABEL-1062 -BABEL-1243 -BABEL-1493 +BABEL-1953 BABEL-1963 +BABEL-1994-CHAR +BABEL-1994-VARCHAR +BABEL-2086 BABEL-2203 BABEL-2208 BABEL-2257 BABEL-2449 BABEL-2535 -BABEL-2787-2 +BABEL-2765 BABEL-2787 +BABEL-2787-2 +BABEL-2795 BABEL-2805 BABEL-2812 +BABEL-2819 BABEL-2845 +BABEL-2877 BABEL-2884 +BABEL-2917 BABEL-2944 +BABEL-2955 +BABEL-3000-dep +BABEL-3010 BABEL-3116 -# BABEL-3117 BABEL-3118 +BABEL-3121 +BABEL-3144 +BABEL-3147 +BABEL-3213 BABEL-3249 +BABEL-3268 +BABEL-328 +BABEL-3314 +BABEL-3347 +BABEL-3358 +BABEL-3360 +BABEL-3369 +BABEL-3370 +BABEL-3380 +BABEL-3402 +BABEL-3474 BABEL-3486 +BABEL-3556 +BABEL-3588 BABEL-3614 BABEL-3646 +BABEL-3657 +BABEL-3696 +BABEL-3702 +BABEL-3747 +BABEL-3748 +BABEL-3781 +BABEL-3801 +BABEL-3802 BABEL-383 +BABEL-3914 +BABEL-3938 +BABEL-404 BABEL-405 +babel_417 +BABEL-493 +BABEL-621 +BABEL-728 +BABEL-741 +BABEL-775 +BABEL-889 BABEL-937 -forjson -forjson-subquery -forjson-datatypes -forxml -forxml-subquery -BABEL-PROCID -babel_trigger -insteadoftriggers_with_transaction -insteadof_nested_trigger_inside_proc -insteadof_nested_trigger_with_dml -nested_trigger_inside_proc -nested_trigger_with_dml -triggers_with_transaction -Test-sp_addrole -Test-sp_addrolemember -Test-sp_droprole -Test-sp_droprolemember -Test-sp_helpdbfixedrole -# Test-sp_helpsrvrolemember -# Test-sp_helpuser -Test-sp_set_session_context -Test-sp_set_session_context-dep -TestTableType -# BABEL-CROSS-DB -# BABEL-LOGIN -# BABEL-USER -# BABEL-ROLE -# babelfish_sysdatabases -babelfish_namespace_ext -# babelfish_authid_login_ext -# babelfish_authid_user_ext +BABEL-APPLOCK +babel_char +BABEL-CHECK-CONSTRAINT +babel_datetime +BABEL-EXECUTE_AS_CALLER +BABEL-EXTENDEDPROPERTY +babelfish_cast_floor babelfish_inconsistent_metadata +babelfish_integrity_checker babelfish_migration_mode -# schema_resolution_func -BABEL-3147 -collation_tests_arabic -collation_tests_greek -collation_tests_mongolian -collation_tests_polish -collation_tests -babel_datetime -babel_char -BABEL-SQUARE -BABEL-728 +babelfish_namespace_ext babel_function_string -BABEL-1566 -BABEL-3360 -BABEL-3380 babel_isnumeric -# HAS_DBACCESS -BABEL-1475 -BABEL-1510 -BABEL-3213 -BABEL-3010 -BABEL-3369 -BABEL-3370 +BABEL-NEXT-VALUE-FOR +BABEL-PG-SYSTEM-FUNCTIONS +BABEL-PROCID BABEL-RAND -BABEL-741 -# BABEL-ROLE-MEMBER -tdscollation -BABEL-EXTENDEDPROPERTY -BABEL-EXECUTE_AS_CALLER -sys-filegroups -sys-filetables -sys-fulltext_indexes -sys-hash_indexes -sys-plan_guides -sp_tablecollations -sys-assemblies -# BABEL-LOGIN-USER-EXT -bitwise_not-operator -BABEL-1683 -BABEL-1953 -schema_resolution_trigger -sys_all_objects-dep -sys-columns-dep -# sys-databases-dep -# sys-foreign_key_columns-dep -# sys-foreign_keys-dep -# sys-identity_columns-dep -sys-indexes-dep -# sys-key_constraints-dep -sys-schemas-dep -# sys-sp_tables_view-dep -sys-sysforeignkeys-dep -# sys-tables-dep -# sys-types-dep -sys-views-dep -sys-check_constraints-dep -sys-computed_columns-dep -sys-default_constraints-dep -sys-index_columns-dep -# sys-sp_databases-dep -sys-syscolumns-dep -# sys-dm_exec_connections-dep -# sys-dm_exec_sessions-dep -sys-table_types-dep -sys-all_sql_modules-dep -sys-sql_modules-dep -# sys-system_sql_modules-dep -sys-triggers-dep -sys-proc_param_helper-dep -BABEL-2877 -# sys-sp_pkeys -# sys-sp_statistics -BABEL-APPLOCK -BABEL-1438 -BABEL-SP_DATATYPE_INFO -# BABEL-SPCOLUMNS -# BABEL-SP_TABLES -# BABEL-SP_SPECIAL_COLUMNS -# BABEL-SP_TABLE_PRIVILIGES -# BABEL-SP_FKEYS -# BABEL-SP_STORED_PROCEDURES -# BABEL-SP_SPROC_COLUMNS -# BABEL-3000 -sys-sp_pkeys-dep -sys-sp_statistics-dep BABEL-SPCOLUMNS-dep BABEL-SP_COLUMNS_MANAGED-dep -BABEL-SP_SPECIAL_COLUMNS-dep -BABEL-SP_SPECIAL_COLUMNS_100-dep +BABEL-SP_DATATYPE_INFO BABEL-SP_FKEYS-dep -BABEL-SP_STORED_PROCEDURES-dep -BABEL-SP_SPROC_COLUMNS-dep +BABEL-SP_SPECIAL_COLUMNS_100-dep +BABEL-SP_SPECIAL_COLUMNS-dep BABEL-SP_SPROC_COLUMNS_100-dep -BABEL-3000-dep -Test-sp_helprole-dep -Test-sp_helprolemember-dep +BABEL-SP_SPROC_COLUMNS-dep +BABEL-SP_STORED_PROCEDURES-dep +babel_sqlvariant_cast_compare +BABEL-SQUARE +BABEL-TABLEOPTIONS +babel_trigger +babel_try_parse +bbf_view_def +binary-index +bitwise_not-operator +cast_numeric_types_to_datetime +cast_numeric_types_to_smalldatetime +collation_tests +collation_tests_arabic +collation_tests_greek +collation_tests_mongolian +collation_tests_polish +dateadd_internal_df +datediff_big +datediff_internal_date +datepart +datetime2fromparts-after-15-2 +forjson +forjson-datatypes +forjson-subquery format +forxml +forxml-subquery +fulltextserviceproperty +get_tds_id +indexproperty +insteadof_nested_trigger_inside_proc +insteadof_nested_trigger_with_dml +insteadoftriggers_with_transaction +isc-schemata-dep +ISC-Tables +is_srvrolemember +msdb-dbo-fn_syspolicy_is_automation_enabled +msdb-dbo-syspolicy_configuration msdb-dbo-syspolicy_system_health_state +nested_trigger_inside_proc +nested_trigger_with_dml +objectpropertyex +openjson +schema_resolution_trigger +sp_describe_first_result_set +sp_tablecollations +str sys-all_columns sys-all_columns-dep -# sys-all_sql_modules +sys_all_objects +sys_all_objects-dep +sys-all_parameters +sys-all_parameters-dep +sys-all_sql_modules-dep +sys-all_views +sys-assemblies sys-assembly_modules +sys-assembly_types +sys_babelfish_configurations_view sys-change_tracking_databases sys-change_tracking_tables sys-check_constraints +sys-check_constraints-dep +sys-column-property sys-columns +sys-columns-dep sys-computed_columns -sys-data_spaces +sys-computed_columns-dep +sys-configurations sys-database_files sys-database_filestream_options +sys-database_mirroring sys-database_recovery_status +sys-data_spaces +sys-datefirst sys-default_constraints -# sys-dm_exec_connections -# sys-dm_exec_sessions +sys-default_constraints-dep sys-dm_hadr_cluster sys-dm_hadr_database_replica_states sys-dm_os_host_info sys-endpoints sys-extended_properties +sys-filegroups +sys-filetables sys-filetable_system_defined_objects -# sys-foreign_key_columns -# sys-foreign_keys sys-fulltext_catalogs sys-fulltext_index_columns +sys-fulltext_indexes sys-fulltext_languages sys-fulltext_stoplists -# sys-identity_columns -# sys-index_columns -# sys-indexes -# sys-key_constraints +sys-hash_indexes +sys-has_perms_by_name-dep +sys-host_name +sys-index_columns-dep +sys-indexes-dep +sys-lock_timeout sys-master_files +sys-max_connections +sys-numbered_procedures +sys-original_login sys-partitions sys-partitions-dep +sys-plan_guides +sys-proc_param_helper-dep sys-registered_search_property_lists +sys-schema-name sys-schemas +sys-schemas-dep sys-selective_xml_index_paths +sys-server_principals sys-sid_binary -# sys-sp_databases -# sys-sp_tables_view -sys-spatial_index_tessellations sys-spatial_indexes +sys-spatial_index_tessellations +sys-sp_pkeys-dep +sys-sp_statistics-dep +sys-sql_modules-dep sys-stats +sys-suser_sid sys-synonyms sys-syscharsets -# sys-syscolumns -# sys-sysforeignkeys +sys-syscolumns-dep +sys-sysforeignkeys-dep sys-syslanguages -# sys-system_sql_modules -# sys-sql_modules +sys-sysobjects +sys-system_objects sys-table_types -# sys-tables -# sys-triggers -# sys-types -# sys-views +sys-table_types-dep +sys-table_types_internal-dep +sys-trigger_nestlevel +sys-triggers-dep +sys-views-dep sys-xml_indexes sys-xml_schema_collections -sys_all_objects -sys_babelfish_configurations_view -BABEL-1249 -BABEL-1291 -BABEL-1994-CHAR -BABEL-1994-VARCHAR -BABEL-889 -babel_417 -# babel_datatype_sqlvariant -babel_sqlvariant_cast_compare -BABEL-3347 -BABEL-3144 -sys-all_parameters-dep -BABEL-3556 -BABEL-3588 -BABEL-3268 -# BABEL-3513 -# BABEL_GRANT_CONNECT -# BABEL-sp_helpdb -BABEL-2795 -babelfish_integrity_checker -get_tds_id -BABEL-PG-SYSTEM-FUNCTIONS -# BABEL-3655 -# sys-table_types_internal -sys-table_types_internal-dep -BABEL-CHECK-CONSTRAINT -# BABEL-3640 -# sys-sysindexes -sys-system_objects -# ISC-Views -ISC-Tables -# ISC-Columns -#ISC-Check-Constraints -# ISC-Table_Constraints -# sys_server_principals_dep -# sys_database_principals_dep -TestVariableDataLength -BABEL-3801 -datediff_big -app_name -atn2 -str -# case_insensitive_collation -# linked_servers -# ISC-sequences -# jira-BABEL-3504-upgrade -# test_windows_login -# sys-has_perms_by_name -sys-has_perms_by_name-dep -# BABEL_SCHEMATA -isc-schemata-dep -AVG-Aggregate-common -AVG-Aggregate-Dep -bbf_view_def -# BABEL_OBJECT_ID -BABEL-3802 -datediff_internal_date -# BABEL_OBJECT_NAME -# Test_user_from_win_login -BABEL-3914 -# Babel_domain_mapping_test -# BABEL-3828 -# BABEL-3844 -BABEL-3748 -# test_windows_alter_login -# sys-systypes -openjson -BABEL-3702 -BABEL-3696 -# Test-sp_babelfish_volatility -# BABEL_OBJECT_DEFINITION +tdscollation +temp-tables +TestBigInt +TestBinary +TestBIT +TestChar +Test-Computed-Columns +TestDate +TestDatetime +TestDatetime2 +TestDecimal +TestFloat +Test-Identity +TestImage +TestInt +TestMoney +TestNumeric +TestReal +TestRowVersion +TestSmallDatetime +TestSmallInt +TestSmallMoney +Test-sp_addrole +Test-sp_addrolemember +Test-sp_droprole +Test-sp_droprolemember +Test-sp_helpdbfixedrole +Test-sp_helprole-dep +Test-sp_helprolemember-dep Test-sp_rename Test-sp_rename-dep -# openquery_upgrd -BABEL-3657 -# test_windows_alter_user -# BABEL-733 -BABEL-3938 -BABEL-NEXT-VALUE-FOR -binary-index -# test_windows_sp_helpuser -BABEL-1625 -BABEL-3474 -dateadd_internal_df -datetime2fromparts-after-15-2 +Test-sp_set_session_context +Test-sp_set_session_context-dep +TestTableType +TestText +TestTime +TestTinyInt +TestUDD +TestUniqueIdentifier +TestVarChar +TestVariableDataLength +TestXML timefromparts +triggers_with_transaction diff --git a/test/python/expected/upgrade_validation/expected_dependency.out b/test/python/expected/upgrade_validation/expected_dependency.out index 1bdf6b9f7b..30d06c1603 100644 --- a/test/python/expected/upgrade_validation/expected_dependency.out +++ b/test/python/expected/upgrade_validation/expected_dependency.out @@ -128,8 +128,6 @@ Function sys.babelfish_get_identity_param(text,text) Function sys.babelfish_get_int_part(double precision) Function sys.babelfish_get_jobs() Function sys.babelfish_get_lang_metadata_json(text) -Function sys.babelfish_get_last_identity() -Function sys.babelfish_get_last_identity_numeric() Function sys.babelfish_get_login_default_db(text) Function sys.babelfish_get_microsecs_from_fractsecs(text,numeric) Function sys.babelfish_get_monthnum_by_name(text,jsonb) @@ -531,7 +529,6 @@ Function sys.rowversionsysvarchar(sys.rowversion) Function sys.rowversionvarbinary(sys.rowversion,integer,boolean) Function sys.rowversionvarchar(sys.rowversion) Function sys.schema_name() -Function sys.scope_identity() Function sys.servername() Function sys.serverproperty(text) Function sys.servicename() @@ -611,11 +608,9 @@ Function sys.stuff(text,integer,integer,text) Function sys.suser_id() Function sys.suser_id_internal(text) Function sys.suser_name() -Function sys.suser_name(oid) Function sys.suser_name_internal(oid) Function sys.suser_sid() Function sys.suser_sname() -Function sys.suser_sname(sys.varbinary) Function sys.sysdatetime() Function sys.sysdatetimeoffset() Function sys.system_user() From e90ac5b950f0201922437f2162fa6286047d1a51 Mon Sep 17 00:00:00 2001 From: Walt Boettge Date: Fri, 21 Apr 2023 17:05:29 -0700 Subject: [PATCH 070/363] Update / Delete / Insert with TOP (#1430) * Fix TOP in UPDATE/DELETE Previously, update and delete statements were handled by query re-writing to account for differences in pg and t-sql. Due to a variety of issues with this approach, a more comprehensive solution was done (see Support and re-design UPDATE/DELETE). However, this work did not support the TOP clause in UPDATE/DELETE. This change continues this work to now support TOP in in UPDAET/DELETE. Task: BABEL-3725 and BABEL-3909 Signed-off-by: Walt Boettge * Support INSERT TOP T-SQL allows a TOP clause to be used with INSERT statements to limit the number of items added to a table. This change will add support for this feature. Note this is separate from INSERT ... SELECT TOP, which allows a user to specify an ORDER BY clause in the SELECT statement. INSERT TOP does not allow any ordering, so the resulting inserted columns are random. Task: BABEL-1139 Signed-off-by: Walt Boettge --- .../src/backend_parser/gram-tsql-epilogue.y.c | 3 +- .../src/backend_parser/gram-tsql-prologue.y.h | 2 +- .../src/backend_parser/gram-tsql-rule.y | 152 ++- contrib/babelfishpg_tsql/src/hooks.c | 51 +- test/JDBC/expected/BABEL-3725-vu-prepare.out | 14 + test/JDBC/expected/BABEL-3725-vu-verify.out | 12 + test/JDBC/expected/babel_top_in_dml.out | 904 +++++++++++++++++- test/JDBC/input/dml/BABEL-3725-vu-prepare.sql | 12 + test/JDBC/input/dml/BABEL-3725-vu-verify.sql | 8 + test/JDBC/input/dml/babel_top_in_dml.sql | 619 +++++++++++- test/JDBC/upgrade/13_4/schedule | 1 + test/JDBC/upgrade/13_5/schedule | 1 + test/JDBC/upgrade/13_6/schedule | 1 + test/JDBC/upgrade/13_7/schedule | 1 + test/JDBC/upgrade/13_8/schedule | 1 + test/JDBC/upgrade/13_9/schedule | 1 + test/JDBC/upgrade/14_3/schedule | 1 + test/JDBC/upgrade/14_5/schedule | 1 + test/JDBC/upgrade/14_6/schedule | 1 + test/JDBC/upgrade/14_7/schedule | 1 + test/JDBC/upgrade/14_8/schedule | 1 + test/JDBC/upgrade/15_1/schedule | 1 + test/JDBC/upgrade/15_2/schedule | 1 + test/JDBC/upgrade/latest/schedule | 1 + 24 files changed, 1692 insertions(+), 99 deletions(-) create mode 100644 test/JDBC/expected/BABEL-3725-vu-prepare.out create mode 100644 test/JDBC/expected/BABEL-3725-vu-verify.out create mode 100644 test/JDBC/input/dml/BABEL-3725-vu-prepare.sql create mode 100644 test/JDBC/input/dml/BABEL-3725-vu-verify.sql diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c index 8601c53449..4c69507f27 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-epilogue.y.c @@ -966,7 +966,7 @@ tsql_update_delete_stmt_from_clause_alias(RangeVar *relation, List *from_clause) } static Node * -tsql_insert_output_into_cte_transformation(WithClause *opt_with_clause, RangeVar *insert_target, +tsql_insert_output_into_cte_transformation(WithClause *opt_with_clause, Node *opt_top_clause, RangeVar *insert_target, List *insert_column_list, List *tsql_output_clause, RangeVar *output_target, List *tsql_output_into_target_columns, InsertStmt *tsql_output_insert_rest, int select_location) { @@ -992,6 +992,7 @@ tsql_insert_output_into_cte_transformation(WithClause *opt_with_clause, RangeVar /* PreparableStmt inside CTE */ i->cols = insert_column_list; i->selectStmt = tsql_output_insert_rest->selectStmt; + i->limitCount = opt_top_clause; i->relation = insert_target; i->onConflictClause = NULL; i->returningList = get_transformed_output_list(tsql_output_clause); diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-prologue.y.h b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-prologue.y.h index baf85cb493..a667a3e345 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-prologue.y.h +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-prologue.y.h @@ -68,7 +68,7 @@ static Node *tsql_update_delete_stmt_with_join(Node *n, List *from_clause, Node static Node *tsql_update_delete_stmt_with_top(Node *top_clause, RangeVar *relation, Node *where_clause, core_yyscan_t yyscanner); static void tsql_update_delete_stmt_from_clause_alias(RangeVar *relation, List *from_clause); -static Node *tsql_insert_output_into_cte_transformation(WithClause *opt_with_clause, RangeVar *insert_target, +static Node *tsql_insert_output_into_cte_transformation(WithClause *opt_with_clause, Node *opt_top_clause, RangeVar *insert_target, List *insert_column_list, List *tsql_output_clause, RangeVar *output_target, List *tsql_output_into_target_columns, InsertStmt *tsql_output_insert_rest, int select_location); static Node *tsql_delete_output_into_cte_transformation(WithClause *opt_with_clause, Node *opt_top_clause, diff --git a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y index 060a6acfec..83b5e8d269 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y @@ -1247,20 +1247,10 @@ tsql_UpdateStmt: opt_with_clause UPDATE relation_expr_opt_alias { UpdateStmt *n = makeNode(UpdateStmt); n->relation = $4; - tsql_update_delete_stmt_from_clause_alias(n->relation, $8); + n->limitCount = $3; n->targetList = $7; - if ($8 != NULL && IsA(linitial($8), JoinExpr)) - { - n = (UpdateStmt*)tsql_update_delete_stmt_with_join( - (Node*)n, $8, $9, $3, $4, - yyscanner); - } - else - { - n->fromClause = $8; - n->whereClause = tsql_update_delete_stmt_with_top($3, - $4, $9, yyscanner); - } + n->fromClause = $8; + n->whereClause = $9; n->returningList = $10; n->withClause = $1; $$ = (Node *)n; @@ -2319,29 +2309,32 @@ tsql_opt_INTO: ; tsql_InsertStmt: - opt_with_clause INSERT tsql_opt_INTO insert_target tsql_opt_table_hint_expr '(' insert_column_list ')' + opt_with_clause INSERT opt_top_clause tsql_opt_INTO insert_target tsql_opt_table_hint_expr '(' insert_column_list ')' tsql_output_insert_rest { - $9->relation = $4; - $9->onConflictClause = NULL; - $9->returningList = NULL; - $9->withClause = $1; - $9->cols = $7; - $$ = (Node *) $9; + $10->limitCount = $3; + $10->relation = $5; + $10->onConflictClause = NULL; + $10->returningList = NULL; + $10->withClause = $1; + $10->cols = $8; + $$ = (Node *) $10; } - | opt_with_clause INSERT tsql_opt_INTO insert_target tsql_opt_table_hint_expr tsql_output_insert_rest + | opt_with_clause INSERT opt_top_clause tsql_opt_INTO insert_target tsql_opt_table_hint_expr tsql_output_insert_rest { - $6->relation = $4; - $6->onConflictClause = NULL; - $6->returningList = NULL; - $6->withClause = $1; - $6->cols = NIL; - $$ = (Node *) $6; + $7->limitCount = $3; + $7->relation = $5; + $7->onConflictClause = NULL; + $7->returningList = NULL; + $7->withClause = $1; + $7->cols = NIL; + $$ = (Node *) $7; } - | opt_with_clause INSERT tsql_opt_INTO insert_target tsql_opt_table_hint_expr DEFAULT TSQL_VALUES + | opt_with_clause INSERT opt_top_clause tsql_opt_INTO insert_target tsql_opt_table_hint_expr DEFAULT TSQL_VALUES { InsertStmt *i = makeNode(InsertStmt); - i->relation = $4; + i->limitCount = $3; + i->relation = $5; i->onConflictClause = NULL; i->returningList = NULL; i->withClause = $1; @@ -2351,42 +2344,45 @@ tsql_InsertStmt: $$ = (Node *) i; } /* OUTPUT syntax */ - | opt_with_clause INSERT tsql_opt_INTO insert_target tsql_opt_table_hint_expr '(' insert_column_list ')' + | opt_with_clause INSERT opt_top_clause tsql_opt_INTO insert_target tsql_opt_table_hint_expr '(' insert_column_list ')' tsql_output_clause tsql_output_insert_rest_no_paren { - if ($10->execStmt) + if ($11->execStmt) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("The OUTPUT clause cannot be used in an INSERT...EXEC statement."), parser_errposition(@10))); - $10->relation = $4; - $10->onConflictClause = NULL; - $10->returningList = $9; - $10->withClause = $1; - $10->cols = $7; - $$ = (Node *) $10; + $11->limitCount = $3; + $11->relation = $5; + $11->onConflictClause = NULL; + $11->returningList = $10; + $11->withClause = $1; + $11->cols = $8; + $$ = (Node *) $11; } - | opt_with_clause INSERT tsql_opt_INTO insert_target tsql_opt_table_hint_expr tsql_output_clause tsql_output_insert_rest_no_paren + | opt_with_clause INSERT opt_top_clause tsql_opt_INTO insert_target tsql_opt_table_hint_expr tsql_output_clause tsql_output_insert_rest_no_paren { - if ($7->execStmt) + if ($8->execStmt) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("The OUTPUT clause cannot be used in an INSERT...EXEC statement."), parser_errposition(@7))); - $7->relation = $4; - $7->onConflictClause = NULL; - $7->returningList = $6; - $7->withClause = $1; - $7->cols = NIL; - $$ = (Node *) $7; + $8->limitCount = $3; + $8->relation = $5; + $8->onConflictClause = NULL; + $8->returningList = $7; + $8->withClause = $1; + $8->cols = NIL; + $$ = (Node *) $8; } /* conflict on DEFAULT (DEFAULT is allowed as a_expr in tsql_output_clause - | opt_with_clause INSERT tsql_opt_INTO insert_target tsql_opt_table_hint_expr tsql_output_clause DEFAULT VALUES + | opt_with_clause INSERT opt_top_clause tsql_opt_INTO insert_target tsql_opt_table_hint_expr tsql_output_clause DEFAULT VALUES { InsertStmt *i = makeNode(InsertStmt); - i->relation = $4; + i->limitCount = $3; + i->relation = $5; i->onConflictClause = NULL; - i->returningList = $6; + i->returningList = $7; i->withClause = $1; i->cols = NIL; i->selectStmt = NULL; @@ -2395,27 +2391,27 @@ tsql_InsertStmt: } */ /* OUTPUT INTO syntax with OUTPUT target column list */ - | opt_with_clause INSERT tsql_opt_INTO insert_target tsql_opt_table_hint_expr '(' insert_column_list ')' + | opt_with_clause INSERT opt_top_clause tsql_opt_INTO insert_target tsql_opt_table_hint_expr '(' insert_column_list ')' tsql_output_clause INTO insert_target tsql_output_into_target_columns tsql_output_insert_rest { - if ($13->execStmt) + if ($14->execStmt) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("The OUTPUT clause cannot be used in an INSERT...EXEC statement."), - parser_errposition(@13))); - $$ = tsql_insert_output_into_cte_transformation($1, $4, $7, $9, $11, $12, $13, 4); + parser_errposition(@14))); + $$ = tsql_insert_output_into_cte_transformation($1, $3, $5, $8, $10, $12, $13, $14, 5); } - | opt_with_clause INSERT tsql_opt_INTO insert_target tsql_opt_table_hint_expr tsql_output_clause + | opt_with_clause INSERT opt_top_clause tsql_opt_INTO insert_target tsql_opt_table_hint_expr tsql_output_clause INTO insert_target tsql_output_into_target_columns tsql_output_insert_rest { - if ($10->execStmt) + if ($11->execStmt) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("The OUTPUT clause cannot be used in an INSERT...EXEC statement."), parser_errposition(@10))); - $$ = tsql_insert_output_into_cte_transformation($1, $4, NULL, $6, $8, $9, $10, 4); + $$ = tsql_insert_output_into_cte_transformation($1, $3, $5, NULL, $7, $9, $10, $11, 5); } - | opt_with_clause INSERT tsql_opt_INTO insert_target tsql_opt_table_hint_expr tsql_output_clause + | opt_with_clause INSERT opt_top_clause tsql_opt_INTO insert_target tsql_opt_table_hint_expr tsql_output_clause INTO insert_target tsql_output_into_target_columns DEFAULT VALUES { InsertStmt *i = makeNode(InsertStmt); @@ -2426,31 +2422,31 @@ tsql_InsertStmt: i->cols = NIL; i->selectStmt = NULL; i->execStmt = NULL; - $$ = tsql_insert_output_into_cte_transformation($1, $4, NULL, $6, $8, $9, i, 4); + $$ = tsql_insert_output_into_cte_transformation($1, $3, $5, NULL, $7, $9, $10, i, 5); } /* Without OUTPUT target column list */ - | opt_with_clause INSERT tsql_opt_INTO insert_target tsql_opt_table_hint_expr '(' insert_column_list ')' + | opt_with_clause INSERT opt_top_clause tsql_opt_INTO insert_target tsql_opt_table_hint_expr '(' insert_column_list ')' tsql_output_clause INTO insert_target tsql_output_insert_rest_no_paren { - if ($12->execStmt) + if ($13->execStmt) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("The OUTPUT clause cannot be used in an INSERT...EXEC statement."), - parser_errposition(@12))); - $$ = tsql_insert_output_into_cte_transformation($1, $4, $7, $9, $11, NIL, $12, 4); + parser_errposition(@13))); + $$ = tsql_insert_output_into_cte_transformation($1, $3, $5, $8, $10, $12, NIL, $13, 5); } - | opt_with_clause INSERT tsql_opt_INTO insert_target tsql_opt_table_hint_expr tsql_output_clause + | opt_with_clause INSERT opt_top_clause tsql_opt_INTO insert_target tsql_opt_table_hint_expr tsql_output_clause INTO insert_target tsql_output_insert_rest_no_paren { - if ($9->execStmt) + if ($10->execStmt) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("The OUTPUT clause cannot be used in an INSERT...EXEC statement."), parser_errposition(@9))); - $$ = tsql_insert_output_into_cte_transformation($1, $4, NULL, $6, $8, NIL, $9, 4); + $$ = tsql_insert_output_into_cte_transformation($1, $3, $5, NULL, $7, $9, NIL, $10, 5); } /* - | opt_with_clause INSERT tsql_opt_INTO insert_target tsql_opt_table_hint_expr tsql_output_clause + | opt_with_clause INSERT opt_top_clause tsql_opt_INTO insert_target tsql_opt_table_hint_expr tsql_output_clause INTO insert_target DEFAULT VALUES { InsertStmt *i = makeNode(InsertStmt); @@ -2461,7 +2457,7 @@ tsql_InsertStmt: i->cols = NIL; i->selectStmt = NULL; i->execStmt = NULL; - $$ = tsql_insert_output_into_cte_transformation($1, $4, NULL, $6, $8, NIL, i, 4); + $$ = tsql_insert_output_into_cte_transformation($1, $3, $5, NULL, $7, $9, NIL, i, 5); } */ ; @@ -3125,28 +3121,10 @@ tsql_DeleteStmt: opt_with_clause DELETE_P opt_top_clause opt_from relation_expr_ tsql_opt_table_hint_expr from_clause where_or_current_clause { DeleteStmt *n = makeNode(DeleteStmt); + n->limitCount = $3; n->relation = $5; - if ($3 != NULL) - { - tsql_update_delete_stmt_from_clause_alias(n->relation, $7); - if ($7 != NULL && IsA(linitial($7), JoinExpr)) - { - n = (DeleteStmt*)tsql_update_delete_stmt_with_join( - (Node*)n, $7, $8, $3, $5, - yyscanner); - } - else - { - n->usingClause = $7; - n->whereClause = tsql_update_delete_stmt_with_top($3, - $5, $8, yyscanner); - } - } - else - { - n->usingClause = $7; - n->whereClause = $8; - } + n->usingClause = $7; + n->whereClause = $8; n->returningList = NULL; n->withClause = $1; $$ = (Node *)n; diff --git a/contrib/babelfishpg_tsql/src/hooks.c b/contrib/babelfishpg_tsql/src/hooks.c index 7001d34088..048f8df6a5 100644 --- a/contrib/babelfishpg_tsql/src/hooks.c +++ b/contrib/babelfishpg_tsql/src/hooks.c @@ -94,6 +94,7 @@ static int pltsql_set_target_table_alternative(ParseState *pstate, Node *stmt, C static void set_output_clause_transformation_info(bool enabled); static bool get_output_clause_transformation_info(void); static Node *output_update_self_join_transformation(ParseState *pstate, UpdateStmt *stmt, Query *query); +static void post_transform_delete(ParseState *pstate, DeleteStmt *stmt, Query *query); static void handle_returning_qualifiers(Query *query, List *returningList, ParseState *pstate); static void check_insert_row(List *icolumns, List *exprList, Oid relid); static void pltsql_post_transform_column_definition(ParseState *pstate, RangeVar *relation, ColumnDef *column, List **alist); @@ -103,7 +104,7 @@ static bool tle_name_comparison(const char *tlename, const char *identifier); static void resolve_target_list_unknowns(ParseState *pstate, List *targetlist); static inline bool is_identifier_char(char c); static int find_attr_by_name_from_relation(Relation rd, const char *attname, bool sysColOK); -static void modify_insert_stmt(InsertStmt *stmt, Oid relid); +static void pre_transform_insert(ParseState *pstate, InsertStmt *stmt, Query *query); static void modify_RangeTblFunction_tupdesc(char *funcname, Node *expr, TupleDesc *tupdesc); static void sort_nulls_first(SortGroupClause * sortcl, bool reverse); @@ -215,11 +216,13 @@ InstallExtendedHooks(void) get_output_clause_status_hook = get_output_clause_transformation_info; pre_output_clause_transformation_hook = output_update_self_join_transformation; + post_transform_delete_hook = post_transform_delete; + prev_pre_transform_returning_hook = pre_transform_returning_hook; pre_transform_returning_hook = handle_returning_qualifiers; prev_pre_transform_insert_hook = pre_transform_insert_hook; - pre_transform_insert_hook = modify_insert_stmt; + pre_transform_insert_hook = pre_transform_insert; prev_post_transform_insert_row_hook = post_transform_insert_row_hook; post_transform_insert_row_hook = check_insert_row; @@ -328,6 +331,7 @@ UninstallExtendedHooks(void) core_yylex_hook = prev_core_yylex_hook; set_target_table_alternative_hook = NULL; get_output_clause_status_hook = NULL; + post_transform_delete_hook = NULL; pre_output_clause_transformation_hook = NULL; pre_transform_returning_hook = prev_pre_transform_returning_hook; pre_transform_insert_hook = prev_pre_transform_insert_hook; @@ -572,6 +576,12 @@ output_update_self_join_transformation(ParseState *pstate, UpdateStmt *stmt, Que if (sql_dialect != SQL_DIALECT_TSQL) return pre_transform_qual; + /* Support Update w/ TOP */ + query->limitCount = transformLimitClause(pstate, stmt->limitCount, + EXPR_KIND_LIMIT, "LIMIT", + LIMIT_OPTION_COUNT); + query->limitOption = LIMIT_OPTION_COUNT; + if (get_output_clause_transformation_info()) { /* @@ -637,6 +647,19 @@ output_update_self_join_transformation(ParseState *pstate, UpdateStmt *stmt, Que return qual; } +static void +post_transform_delete(ParseState *pstate, DeleteStmt *stmt, Query *query) +{ + if (sql_dialect != SQL_DIALECT_TSQL) + return; + + /* Handle DELETE TOP */ + query->limitCount = transformLimitClause(pstate, stmt->limitCount, + EXPR_KIND_LIMIT, "LIMIT", + LIMIT_OPTION_COUNT); + query->limitOption = LIMIT_OPTION_COUNT; +} + static void set_output_clause_transformation_info(bool enabled) { @@ -2192,12 +2215,6 @@ modify_insert_stmt(InsertStmt *stmt, Oid relid) List *insert_col_list = NIL, *temp_col_list; - if (prev_pre_transform_insert_hook) - (*prev_pre_transform_insert_hook) (stmt, relid); - - if (sql_dialect != SQL_DIALECT_TSQL) - return; - if (!output_into_insert_transformation) return; @@ -2239,6 +2256,24 @@ modify_insert_stmt(InsertStmt *stmt, Oid relid) } +static void +pre_transform_insert(ParseState *pstate, InsertStmt *stmt, Query *query) +{ + if (prev_pre_transform_insert_hook) + (*prev_pre_transform_insert_hook) (pstate, stmt, query); + + if (sql_dialect != SQL_DIALECT_TSQL) + return; + + query->limitCount = transformLimitClause(pstate, stmt->limitCount, + EXPR_KIND_LIMIT, "LIMIT", + LIMIT_OPTION_COUNT); + query->limitOption = LIMIT_OPTION_COUNT; + + if (stmt->withClause) + modify_insert_stmt(stmt, RelationGetRelid(pstate->p_target_relation)); +} + /* * Stores view object's TSQL definition to bbf_view_def catalog * Note: It won't store view info if view is created in TSQL dialect from PG diff --git a/test/JDBC/expected/BABEL-3725-vu-prepare.out b/test/JDBC/expected/BABEL-3725-vu-prepare.out new file mode 100644 index 0000000000..7f70ffe545 --- /dev/null +++ b/test/JDBC/expected/BABEL-3725-vu-prepare.out @@ -0,0 +1,14 @@ +create table dbo.babel_3725(a int) +go + +insert into babel_3725 values (1), (2), (NULL) +go +~~ROW COUNT: 3~~ + + +create procedure babel_3725_dml_top_proc as +begin + update top(2) dbo.babel_3725 set a = 100; + delete top(2) dbo.babel_3725; +end +go diff --git a/test/JDBC/expected/BABEL-3725-vu-verify.out b/test/JDBC/expected/BABEL-3725-vu-verify.out new file mode 100644 index 0000000000..6233f81923 --- /dev/null +++ b/test/JDBC/expected/BABEL-3725-vu-verify.out @@ -0,0 +1,12 @@ + +exec babel_3725_dml_top_proc +go +~~ROW COUNT: 2~~ + +~~ROW COUNT: 2~~ + + +drop procedure babel_3725_dml_top_proc +go +drop table dbo.babel_3725 +go diff --git a/test/JDBC/expected/babel_top_in_dml.out b/test/JDBC/expected/babel_top_in_dml.out index 963dd566c2..76cf3f1165 100644 --- a/test/JDBC/expected/babel_top_in_dml.out +++ b/test/JDBC/expected/babel_top_in_dml.out @@ -129,7 +129,7 @@ go ~~ROW COUNT: 1~~ -update top(2) t1 set a = a*-1 from t1 alias1 inner join t2 alias2 on alias1.a = alias2.a +update top(2) t1 set t1.a = t1.a*-1 from t1 inner join t2 alias2 on t1.a = alias2.a go ~~ROW COUNT: 2~~ @@ -247,3 +247,905 @@ go drop table t4 go + + +------------------------------------------------------------- +-- Tests for UPDATE +------------------------------------------------------------- +CREATE TABLE update_test_tbl ( + age int, + fname char(10), + lname char(10), + city nchar(20) +); +go + + +INSERT INTO update_test_tbl(age, fname, lname, city) +VALUES (50, 'fname1', 'lname1', 'london'), + (34, 'fname2', 'lname2', 'paris'), + (35, 'fname3', 'lname3', 'brussels'), + (90, 'fname4', 'lname4', 'new york'), + (26, 'fname5', 'lname5', 'los angeles'), + (74, 'fname6', 'lname6', 'tokyo'), + (44, 'fname7', 'lname7', 'oslo'), + (19, 'fname8', 'lname8', 'hong kong'), + (61, 'fname9', 'lname9', 'shanghai'), + (29, 'fname10', 'lname10', 'mumbai'); +CREATE TABLE update_test_tbl2 ( + year int, + lname char(10), +); +go +~~ROW COUNT: 10~~ + + +INSERT INTO update_test_tbl2(year, lname) +VALUES (51, 'lname1'), + (34, 'lname3'), + (25, 'lname8'), + (95, 'lname9'), + (36, 'lname10'); +go +~~ROW COUNT: 5~~ + + +CREATE TABLE update_test_tbl3 ( + lname char(10), + city char(10), +); +go + +INSERT INTO update_test_tbl3(lname, city) +VALUES ('lname8','london'), + ('lname9','tokyo'), + ('lname10','mumbai'); +go +~~ROW COUNT: 3~~ + + +-- Simple update +UPDATE top(2) update_test_tbl SET fname = 'fname11'; +go +~~ROW COUNT: 2~~ + + +-- Update with where clause +UPDATE top(1) update_test_tbl SET fname = 'fname12' +WHERE age > 30 AND city IN ('london','mumbai', 'new york' ); +go +~~ROW COUNT: 1~~ + + +-- Update with inner join +UPDATE top(1) update_test_tbl SET fname = 'fname13' +FROM update_test_tbl t1 +INNER JOIN update_test_tbl2 t2 +ON t1.lname = t2.lname +WHERE year > 50; +go +~~ROW COUNT: 1~~ + + +UPDATE top(1) update_test_tbl SET fname = 'fname14' +FROM update_test_tbl2 t2 +INNER JOIN update_test_tbl t1 +ON t1.lname = t2.lname +WHERE year < 100 AND city in ('tokyo', 'hong kong'); +go +~~ROW COUNT: 1~~ + + +-- Update with outer join +UPDATE top(1) update_test_tbl SET fname = 'fname15' +FROM update_test_tbl2 t2 +LEFT JOIN update_test_tbl t1 +ON t1.lname = t2.lname +WHERE year > 50; +go +~~ROW COUNT: 1~~ + + +UPDATE top(1) update_test_tbl SET fname = 'fname16' +FROM update_test_tbl2 t2 +FULL JOIN update_test_tbl t1 +ON t1.lname = t2.lname +WHERE year > 50 AND age > 0; +go +~~ROW COUNT: 1~~ + + +-- update with outer join on multiple tables +UPDATE top(1) update_test_tbl +SET fname = 'fname17' +FROM update_test_tbl3 t3 +LEFT JOIN update_test_tbl t1 +ON t3.city = t1.city +LEFT JOIN update_test_tbl2 t2 +ON t1.lname = t2.lname +WHERE t3.city in ('mumbai', 'tokyo'); +go +~~ROW COUNT: 1~~ + + +-- update when target table not shown in JoinExpr +UPDATE top(5) update_test_tbl +SET fname = 'fname19' +from update_test_tbl2 t2 +FULL JOIN update_test_tbl3 t3 +ON t2.lname = t3.lname; +go +~~ROW COUNT: 5~~ + + +-- update with self join +UPDATE top(7) update_test_tbl SET lname='lname13' +FROM update_test_tbl c +JOIN +(SELECT lname, fname, age from update_test_tbl) b +on b.lname = c.lname +JOIN +(SELECT lname, city, age from update_test_tbl) a +on a.city = c.city; +go +~~ROW COUNT: 7~~ + + +-- update when target table only appears in subselect +UPDATE top(2) update_test_tbl SET lname='lname14' +FROM +(SELECT lname, fname, age from update_test_tbl) b +JOIN +(SELECT lname, city, age from update_test_tbl) a +on a.lname = b.lname; +go +~~ROW COUNT: 2~~ + + +DROP TABLE update_test_tbl; +go +DROP TABLE update_test_tbl2; +go +DROP TABLE update_test_tbl3; +go + +------------------------------------------------------------- +-- BABEL-2020 +------------------------------------------------------------- +drop procedure if exists babel_2020_update_ct; +go + +create procedure babel_2020_update_ct as +begin + drop table if exists babel_2020_update_t1 + create table babel_2020_update_t1 (a int) + insert into babel_2020_update_t1 values (1), (2), (NULL) + drop table if exists babel_2020_update_t2 + create table babel_2020_update_t2 (a int) + insert into babel_2020_update_t2 values (2), (3), (NULL) +end +go + +-- single tables in FROM clause +exec babel_2020_update_ct; +update top(1) babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x; +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + + +-- JOIN clause, and top value > than # matching rows +exec babel_2020_update_ct; +update top(5) babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x join babel_2020_update_t2 y on 1 = 1; +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 2~~ + + +exec babel_2020_update_ct; +update top(1) babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x join babel_2020_update_t2 y on y.a = 2; +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + + +-- subqueries +exec babel_2020_update_ct; +update top(1) babel_2020_update_t1 set a = 100 from (select * from babel_2020_update_t1) x; +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + + +-- self join +exec babel_2020_update_ct; +update top(1) babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x, (select * from babel_2020_update_t1) y; +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + + +-- outer joins +exec babel_2020_update_ct; +update top(1) babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x left outer join babel_2020_update_t2 on babel_2020_update_t2.a = x.a; +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + + +-- semi joins +exec babel_2020_update_ct; +update top(1) babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x where x.a in (select a from babel_2020_update_t1 where babel_2020_update_t1.a = x.a); +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + + +exec babel_2020_update_ct; +update top(1) babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x where not exists (select a from babel_2020_update_t1 y where y.a + 1 = x.a); +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + + +drop procedure if exists babel_2020_update_ct; +drop table if exists babel_2020_update_t1; +drop table if exists babel_2020_update_t2; +go + +CREATE TABLE babel_update_tbl1(a INT, b VARCHAR(10)); +CREATE TABLE babel_update_tbl2(a INT, b VARCHAR(10)); +CREATE TABLE babel_update_tbl3 (a INT, c INT); +INSERT INTO babel_update_tbl1 VALUES (1, 'left'), (2, 'inner'); +INSERT INTO babel_update_tbl2 VALUES (10, 'inner'), (30, 'right'); +INSERT INTO babel_update_tbl3 VALUES (1, 10), (3, 10); +go +~~ROW COUNT: 2~~ + +~~ROW COUNT: 2~~ + +~~ROW COUNT: 2~~ + +CREATE VIEW babel_update_view AS SELECT * FROM babel_update_tbl1 WHERE babel_update_tbl1.a > 1; +go +CREATE SCHEMA babel_update_schema +go +CREATE TABLE babel_update_schema.babel_update_tbl1(a INT); +INSERT INTO babel_update_schema.babel_update_tbl1 VALUES (1), (2); +go +~~ROW COUNT: 2~~ + + +------------------------------------------------------------- +-- UPDATE with alias as target +-- BABEL-2020 already covers test cases to use alias in FROM +------------------------------------------------------------- +-- alias + plain update +-- BABEL-2675 +BEGIN TRAN +UPDATE top(1) t1 SET a = a + 1 +FROM babel_update_tbl1 AS t1 +ROLLBACK +GO +~~ROW COUNT: 1~~ + + +-- BABEL-3775 +BEGIN TRAN +UPDATE top(1) t1 SET t1.a = a + 1 +FROM babel_update_tbl1 t1 +ROLLBACK +GO +~~ROW COUNT: 1~~ + + +-- alias + subquery +-- BABEL-1875 +BEGIN TRAN +UPDATE top(1) t1 SET a = t1.a + 1 +FROM babel_update_tbl1 t1 +INNER JOIN (SELECT * FROM babel_update_tbl1) t2 +ON t1.b = t2.b +ROLLBACK +GO +~~ROW COUNT: 1~~ + + +-- alias + join +BEGIN TRAN +UPDATE top(1) t1 SET a = 10 +FROM babel_update_tbl2 t2 +JOIN babel_update_tbl1 t1 +ON t2.b = t1.b +ROLLBACK +go +~~ROW COUNT: 1~~ + + +-- alias + self join +-- BABEL-1330 +BEGIN TRAN +UPDATE top(1) t1 SET t1.a = t1.a + 1 +FROM babel_update_tbl1 t1 +INNER JOIN babel_update_tbl1 t2 +ON t1.b = t2.b +ROLLBACK +go +~~ROW COUNT: 1~~ + + +-- alias + inner join +-- BABEL-3091 +BEGIN TRAN +UPDATE top(1) t1 SET t1.a = t2.a +FROM babel_update_tbl1 AS t1 +INNER JOIN babel_update_tbl2 AS t2 +ON t1.b = t2.b +ROLLBACK +go +~~ROW COUNT: 1~~ + + +-- alias + non-ANSI inner join +-- BABEL-3685 +BEGIN TRAN +UPDATE top(1) t1 SET a = 10 +FROM babel_update_tbl1 t2, babel_update_tbl3 t1 +WHERE c > 1 +ROLLBACK +go +~~ROW COUNT: 1~~ + + +-- alias + outer join +BEGIN TRAN +UPDATE top(1) t1 SET a = 100 +FROM babel_update_tbl1 AS t1 +LEFT OUTER JOIN babel_update_tbl1 t2 +ON t2.b = t1.b +ROLLBACK +go +~~ROW COUNT: 1~~ + + +-- alias + semi join +BEGIN TRAN +UPDATE top(1) t1 SET a = 100 +FROM babel_update_tbl1 AS t1 +WHERE t1.a IN +( + SELECT a FROM babel_update_tbl1 + WHERE babel_update_tbl1.a = t1.a +) +ROLLBACK +go +~~ROW COUNT: 1~~ + + +-- alias + updatable view +BEGIN TRAN +INSERT INTO babel_update_tbl1 VALUES (3, 'extra') +UPDATE top(1) v1 SET a = 100 +FROM babel_update_view v1 +WHERE a = 2 +ROLLBACK +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +-- alias + table ref with schema +BEGIN TRAN +UPDATE top(1) t1 SET t1.a = a + 1 +FROM babel_update_schema.babel_update_tbl1 t1 +ROLLBACK +GO +~~ROW COUNT: 1~~ + + +DROP VIEW babel_update_view +go +DROP TABLE babel_update_tbl1 +DROP TABLE babel_update_tbl2 +DROP TABLE babel_update_tbl3 +DROP TABLE babel_update_schema.babel_update_tbl1 +go +DROP SCHEMA babel_update_schema +go + +------------------------------------------------------------- +-- BABEL-2020: DELETE +------------------------------------------------------------- +drop procedure if exists babel_2020_delete_ct; +go + +create procedure babel_2020_delete_ct as +begin + drop table if exists babel_2020_delete_t1 + create table babel_2020_delete_t1 (a int) + insert into babel_2020_delete_t1 values (1), (2), (NULL) + drop table if exists babel_2020_delete_t2 + create table babel_2020_delete_t2 (a int) + insert into babel_2020_delete_t2 values (2), (3), (NULL) +end +go + +-- single tables in FROM clause +exec babel_2020_delete_ct; +delete top(2) babel_2020_delete_t1 from babel_2020_delete_t1 x; +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 2~~ + + +-- JOIN clause, and top value > than # matching rows +exec babel_2020_delete_ct; +delete top(5) babel_2020_delete_t1 from babel_2020_delete_t1 x join babel_2020_delete_t2 y on 1 = 1; +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 2~~ + + +exec babel_2020_delete_ct; +delete top(2) babel_2020_delete_t1 from babel_2020_delete_t1 x join babel_2020_delete_t2 y on y.a = 2; +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 2~~ + + +-- subqueries +exec babel_2020_delete_ct; +delete top(1) babel_2020_delete_t1 from (select * from babel_2020_delete_t1) x; +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + + +-- self join +exec babel_2020_delete_ct; +delete top(1) babel_2020_delete_t1 from babel_2020_delete_t1 x, (select * from babel_2020_delete_t1) y where x.a + 1 >= y.a; +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + + +-- outer joins +exec babel_2020_delete_ct; +delete top(1) babel_2020_delete_t1 from babel_2020_delete_t1 x left outer join babel_2020_delete_t2 on babel_2020_delete_t2.a = x.a; +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + + +-- semi joins +exec babel_2020_delete_ct; +delete top(1) babel_2020_delete_t1 from babel_2020_delete_t1 x where x.a in (select a from babel_2020_delete_t1 where babel_2020_delete_t1.a = x.a); +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + + +exec babel_2020_delete_ct; +delete top(1) babel_2020_delete_t1 from babel_2020_delete_t1 x where not exists (select a from babel_2020_delete_t1 y where y.a + 1 = x.a); +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + + +drop procedure if exists babel_2020_delete_ct; +drop table if exists babel_2020_delete_t1; +drop table if exists babel_2020_delete_t2; +go + +-- DELETE with alias as target +CREATE TABLE babel_delete_tbl1(a INT, b VARCHAR(10)); +CREATE TABLE babel_delete_tbl2(a INT, b VARCHAR(10)); +CREATE TABLE babel_delete_tbl3 (a INT, c INT); +INSERT INTO babel_delete_tbl1 VALUES (1, 'left'), (2, 'inner'); +INSERT INTO babel_delete_tbl2 VALUES (10, 'inner'), (30, 'right'); +INSERT INTO babel_delete_tbl3 VALUES (1, 10), (3, 10); +go +~~ROW COUNT: 2~~ + +~~ROW COUNT: 2~~ + +~~ROW COUNT: 2~~ + + +CREATE VIEW babel_delete_view AS SELECT * FROM babel_delete_tbl1 WHERE babel_delete_tbl1.a > 1; +go +CREATE SCHEMA babel_delete_schema +go +CREATE TABLE babel_delete_schema.babel_delete_tbl1(a INT); +INSERT INTO babel_delete_schema.babel_delete_tbl1 VALUES (1), (2); +go +~~ROW COUNT: 2~~ + + +-- alias + plain delete +BEGIN TRAN +DELETE top(1) t1 +FROM babel_delete_tbl1 AS t1 +ROLLBACK +GO +~~ROW COUNT: 1~~ + + +BEGIN TRAN +DELETE top(1) t1 +FROM babel_delete_tbl1 t1 +ROLLBACK +GO +~~ROW COUNT: 1~~ + + +-- alias + subquery +BEGIN TRAN +DELETE top(1) t1 +FROM babel_delete_tbl1 t1 +INNER JOIN (SELECT * FROM babel_delete_tbl1) t2 +ON t1.b = t2.b +ROLLBACK +GO +~~ROW COUNT: 1~~ + + +-- alias + join +BEGIN TRAN +DELETE top(1) t1 +FROM babel_delete_tbl2 t2 +JOIN babel_delete_tbl1 t1 +ON t2.b = t1.b +ROLLBACK +go +~~ROW COUNT: 1~~ + + +-- alias + self join +-- BABEL-1330 +BEGIN TRAN +DELETE top(1) t1 +FROM babel_delete_tbl1 t1 +INNER JOIN babel_delete_tbl1 t2 +ON t1.b = t2.b +ROLLBACK +go +~~ROW COUNT: 1~~ + + +-- alias + inner join +BEGIN TRAN +DELETE top(1) t1 +FROM babel_delete_tbl1 AS t1 +INNER JOIN babel_delete_tbl2 AS t2 +ON t1.b = t2.b +ROLLBACK +go +~~ROW COUNT: 1~~ + + +-- alias + non-ANSI inner join +BEGIN TRAN +DELETE top(1) t1 +FROM babel_delete_tbl1 t2, babel_delete_tbl3 t1 +WHERE c > 1 +ROLLBACK +go +~~ROW COUNT: 1~~ + + +-- alias + outer join +BEGIN TRAN +DELETE top(1) t1 +FROM babel_delete_tbl1 AS t1 +LEFT OUTER JOIN babel_delete_tbl1 t2 +ON t2.b = t1.b +ROLLBACK +go +~~ROW COUNT: 1~~ + + +-- alias + semi join +BEGIN TRAN +DELETE top(1) t1 +FROM babel_delete_tbl1 AS t1 +WHERE t1.a IN +( + SELECT a FROM babel_delete_tbl1 + WHERE babel_delete_tbl1.a = t1.a +) +ROLLBACK +go +~~ROW COUNT: 1~~ + + +-- alias + updatable view +BEGIN TRAN +INSERT INTO babel_delete_tbl1 VALUES (3, 'extra') +DELETE top(1) v1 +FROM babel_delete_view v1 +WHERE a = 2 +ROLLBACK +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +-- alias + table ref with schema +BEGIN TRAN +DELETE top(1) t1 +FROM babel_delete_schema.babel_delete_tbl1 t1 +ROLLBACK +GO +~~ROW COUNT: 1~~ + + +-- target with schema +BEGIN TRAN +DELETE top(1) babel_delete_schema.babel_delete_tbl1 +ROLLBACK +GO +~~ROW COUNT: 1~~ + + +-- should fail, same exposed names +DELETE top(1) babel_delete_schema.babel_delete_tbl1 +FROM babel_delete_tbl1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The objects "master_babel_delete_schema.babel_delete_tbl1" and "babel_delete_tbl1" in the FROM clause have the same exposed names. Use correlation names to distinguish them.)~~ + + +-- should fail, same exposed names +DELETE top(1) babel_delete_schema.babel_delete_tbl1 +FROM babel_delete_tbl2 AS babel_delete_tbl1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The correlation name 'babel_delete_tbl1' has the same exposed name as table 'master_babel_delete_schema.babel_delete_tbl1'.)~~ + + + +DROP VIEW babel_delete_view +go +DROP TABLE babel_delete_tbl1 +DROP TABLE babel_delete_tbl2 +DROP TABLE babel_delete_tbl3 +DROP TABLE babel_delete_schema.babel_delete_tbl1 +go +DROP SCHEMA babel_delete_schema +go + +------------------------------------------------------------- +-- UPDATE, INSERT w/ error +------------------------------------------------------------- +create table babel_update_error(a int primary key) +go + +insert into babel_update_error values (1), (2), (3) +go +~~ROW COUNT: 3~~ + + +insert top(2) into babel_update_error values (4), (1), (2) +go +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "babel_update_error_pkey")~~ + + +select * from babel_update_error order by a +go +~~START~~ +int +1 +2 +3 +~~END~~ + + +update top(2) babel_update_error set a = 5 where babel_update_error.a < 3 +go +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "babel_update_error_pkey")~~ + + +select * from babel_update_error order by a +go +~~START~~ +int +1 +2 +3 +~~END~~ + + +drop table babel_update_error +go + +------------------------------------------------------------- +-- BABEL-1139: INSERT TOP INTO +------------------------------------------------------------- +CREATE TABLE babel_1139_t1(a INT); +CREATE TABLE babel_1139_t2(a INT); +GO + +INSERT TOP(3) INTO babel_1139_t1 (a) values (1), (2), (3), (NULL) +GO +~~ROW COUNT: 3~~ + + +INSERT TOP(2) INTO babel_1139_t2 SELECT a FROM babel_1139_t1; +GO +~~ROW COUNT: 2~~ + + +INSERT TOP(1) INTO babel_1139_t1 DEFAULT VALUES; +GO +~~ROW COUNT: 1~~ + + +INSERT TOP(4) INTO babel_1139_t2 DEFAULT VALUES; +GO +~~ROW COUNT: 1~~ + + +TRUNCATE TABLE babel_1139_t1; +TRUNCATE TABLE babel_1139_t2; +GO + +INSERT TOP(5) INTO babel_1139_t1 (a) OUTPUT inserted.* VALUES (1), (1), (1), (1), (1), (1); +GO +~~START~~ +int +1 +1 +1 +1 +1 +~~END~~ + + +INSERT TOP(4) INTO babel_1139_t2 OUTPUT inserted.* SELECT a FROM babel_1139_t1; +GO +~~START~~ +int +1 +1 +1 +1 +~~END~~ + + +INSERT TOP(1) INTO babel_1139_t1 OUTPUT inserted.a DEFAULT VALUES; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'DEFAULT VALUES with OUTPUT clause' is not currently supported in Babelfish)~~ + + +TRUNCATE TABLE babel_1139_t1; +TRUNCATE TABLE babel_1139_t2; +GO + +INSERT TOP(5) INTO babel_1139_t1 (a) OUTPUT inserted.a INTO babel_1139_t2 (a) VALUES (1), (1), (1), (1), (1), (1); +GO +~~ROW COUNT: 5~~ + + +INSERT TOP(4) INTO babel_1139_t1 OUTPUT inserted.a INTO babel_1139_t2 (a) SELECT a FROM babel_1139_t1; +GO +~~ROW COUNT: 4~~ + + +INSERT TOP(1) INTO babel_1139_t1 OUTPUT inserted.a INTO babel_1139_t2 (a) DEFAULT VALUES; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'DEFAULT VALUES with OUTPUT clause' is not currently supported in Babelfish)~~ + + +SELECT COUNT(*) FROM babel_1139_t1; +SELECT COUNT(*) FROM babel_1139_t2; +GO +~~START~~ +int +9 +~~END~~ + +~~START~~ +int +9 +~~END~~ + + +TRUNCATE TABLE babel_1139_t1; +TRUNCATE TABLE babel_1139_t2; +GO + +INSERT TOP(5) INTO babel_1139_t1 (a) OUTPUT inserted.a INTO babel_1139_t2 VALUES (1), (1), (1), (1), (1), (1); +GO +~~ROW COUNT: 5~~ + + +INSERT TOP(4) INTO babel_1139_t1 OUTPUT inserted.a INTO babel_1139_t2 SELECT a FROM babel_1139_t1; +GO +~~ROW COUNT: 4~~ + + +INSERT TOP(1) INTO babel_1139_t1 OUTPUT inserted.a INTO babel_1139_t2 DEFAULT VALUES; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'DEFAULT VALUES with OUTPUT clause' is not currently supported in Babelfish)~~ + + +SELECT COUNT(*) FROM babel_1139_t1; +SELECT COUNT(*) FROM babel_1139_t2; +GO +~~START~~ +int +9 +~~END~~ + +~~START~~ +int +9 +~~END~~ + + +DROP TABLE babel_1139_t1; +DROP TABLE babel_1139_t2; +GO diff --git a/test/JDBC/input/dml/BABEL-3725-vu-prepare.sql b/test/JDBC/input/dml/BABEL-3725-vu-prepare.sql new file mode 100644 index 0000000000..37c8da1bdb --- /dev/null +++ b/test/JDBC/input/dml/BABEL-3725-vu-prepare.sql @@ -0,0 +1,12 @@ +create table dbo.babel_3725(a int) +go + +insert into babel_3725 values (1), (2), (NULL) +go + +create procedure babel_3725_dml_top_proc as +begin + update top(2) dbo.babel_3725 set a = 100; + delete top(2) dbo.babel_3725; +end +go diff --git a/test/JDBC/input/dml/BABEL-3725-vu-verify.sql b/test/JDBC/input/dml/BABEL-3725-vu-verify.sql new file mode 100644 index 0000000000..4ab188a744 --- /dev/null +++ b/test/JDBC/input/dml/BABEL-3725-vu-verify.sql @@ -0,0 +1,8 @@ + +exec babel_3725_dml_top_proc +go + +drop procedure babel_3725_dml_top_proc +go +drop table dbo.babel_3725 +go diff --git a/test/JDBC/input/dml/babel_top_in_dml.sql b/test/JDBC/input/dml/babel_top_in_dml.sql index c0747f3d39..9c581d6ef5 100644 --- a/test/JDBC/input/dml/babel_top_in_dml.sql +++ b/test/JDBC/input/dml/babel_top_in_dml.sql @@ -58,7 +58,7 @@ insert t2 values(400,4) insert t2 values(500,5) go -update top(2) t1 set a = a*-1 from t1 alias1 inner join t2 alias2 on alias1.a = alias2.a +update top(2) t1 set t1.a = t1.a*-1 from t1 inner join t2 alias2 on t1.a = alias2.a go select count(*) from t1 where a < 0 @@ -124,3 +124,620 @@ go drop table t4 go + +------------------------------------------------------------- +-- Tests for UPDATE +------------------------------------------------------------- + +CREATE TABLE update_test_tbl ( + age int, + fname char(10), + lname char(10), + city nchar(20) +); +go + +INSERT INTO update_test_tbl(age, fname, lname, city) +VALUES (50, 'fname1', 'lname1', 'london'), + (34, 'fname2', 'lname2', 'paris'), + (35, 'fname3', 'lname3', 'brussels'), + (90, 'fname4', 'lname4', 'new york'), + (26, 'fname5', 'lname5', 'los angeles'), + (74, 'fname6', 'lname6', 'tokyo'), + (44, 'fname7', 'lname7', 'oslo'), + (19, 'fname8', 'lname8', 'hong kong'), + (61, 'fname9', 'lname9', 'shanghai'), + (29, 'fname10', 'lname10', 'mumbai'); + +CREATE TABLE update_test_tbl2 ( + year int, + lname char(10), +); +go + +INSERT INTO update_test_tbl2(year, lname) +VALUES (51, 'lname1'), + (34, 'lname3'), + (25, 'lname8'), + (95, 'lname9'), + (36, 'lname10'); +go + +CREATE TABLE update_test_tbl3 ( + lname char(10), + city char(10), +); +go + +INSERT INTO update_test_tbl3(lname, city) +VALUES ('lname8','london'), + ('lname9','tokyo'), + ('lname10','mumbai'); +go + +-- Simple update +UPDATE top(2) update_test_tbl SET fname = 'fname11'; +go + +-- Update with where clause +UPDATE top(1) update_test_tbl SET fname = 'fname12' +WHERE age > 30 AND city IN ('london','mumbai', 'new york' ); +go + +-- Update with inner join +UPDATE top(1) update_test_tbl SET fname = 'fname13' +FROM update_test_tbl t1 +INNER JOIN update_test_tbl2 t2 +ON t1.lname = t2.lname +WHERE year > 50; +go + +UPDATE top(1) update_test_tbl SET fname = 'fname14' +FROM update_test_tbl2 t2 +INNER JOIN update_test_tbl t1 +ON t1.lname = t2.lname +WHERE year < 100 AND city in ('tokyo', 'hong kong'); +go + +-- Update with outer join +UPDATE top(1) update_test_tbl SET fname = 'fname15' +FROM update_test_tbl2 t2 +LEFT JOIN update_test_tbl t1 +ON t1.lname = t2.lname +WHERE year > 50; +go + +UPDATE top(1) update_test_tbl SET fname = 'fname16' +FROM update_test_tbl2 t2 +FULL JOIN update_test_tbl t1 +ON t1.lname = t2.lname +WHERE year > 50 AND age > 0; +go + +-- update with outer join on multiple tables +UPDATE top(1) update_test_tbl +SET fname = 'fname17' +FROM update_test_tbl3 t3 +LEFT JOIN update_test_tbl t1 +ON t3.city = t1.city +LEFT JOIN update_test_tbl2 t2 +ON t1.lname = t2.lname +WHERE t3.city in ('mumbai', 'tokyo'); +go + +-- update when target table not shown in JoinExpr +UPDATE top(5) update_test_tbl +SET fname = 'fname19' +from update_test_tbl2 t2 +FULL JOIN update_test_tbl3 t3 +ON t2.lname = t3.lname; +go + +-- update with self join +UPDATE top(7) update_test_tbl SET lname='lname13' +FROM update_test_tbl c +JOIN +(SELECT lname, fname, age from update_test_tbl) b +on b.lname = c.lname +JOIN +(SELECT lname, city, age from update_test_tbl) a +on a.city = c.city; +go + +-- update when target table only appears in subselect +UPDATE top(2) update_test_tbl SET lname='lname14' +FROM +(SELECT lname, fname, age from update_test_tbl) b +JOIN +(SELECT lname, city, age from update_test_tbl) a +on a.lname = b.lname; +go + +DROP TABLE update_test_tbl; +go +DROP TABLE update_test_tbl2; +go +DROP TABLE update_test_tbl3; +go + +------------------------------------------------------------- +-- BABEL-2020 +------------------------------------------------------------- +drop procedure if exists babel_2020_update_ct; +go + +create procedure babel_2020_update_ct as +begin + drop table if exists babel_2020_update_t1 + create table babel_2020_update_t1 (a int) + insert into babel_2020_update_t1 values (1), (2), (NULL) + drop table if exists babel_2020_update_t2 + create table babel_2020_update_t2 (a int) + insert into babel_2020_update_t2 values (2), (3), (NULL) +end +go + +-- single tables in FROM clause +exec babel_2020_update_ct; +update top(1) babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x; +go + +-- JOIN clause, and top value > than # matching rows +exec babel_2020_update_ct; +update top(5) babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x join babel_2020_update_t2 y on 1 = 1; +go + +exec babel_2020_update_ct; +update top(1) babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x join babel_2020_update_t2 y on y.a = 2; +go + +-- subqueries +exec babel_2020_update_ct; +update top(1) babel_2020_update_t1 set a = 100 from (select * from babel_2020_update_t1) x; +go + +-- self join +exec babel_2020_update_ct; +update top(1) babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x, (select * from babel_2020_update_t1) y; +go + +-- outer joins +exec babel_2020_update_ct; +update top(1) babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x left outer join babel_2020_update_t2 on babel_2020_update_t2.a = x.a; +go + +-- semi joins +exec babel_2020_update_ct; +update top(1) babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x where x.a in (select a from babel_2020_update_t1 where babel_2020_update_t1.a = x.a); +go + +exec babel_2020_update_ct; +update top(1) babel_2020_update_t1 set a = 100 from babel_2020_update_t1 x where not exists (select a from babel_2020_update_t1 y where y.a + 1 = x.a); +go + +drop procedure if exists babel_2020_update_ct; +drop table if exists babel_2020_update_t1; +drop table if exists babel_2020_update_t2; +go + +CREATE TABLE babel_update_tbl1(a INT, b VARCHAR(10)); +CREATE TABLE babel_update_tbl2(a INT, b VARCHAR(10)); +CREATE TABLE babel_update_tbl3 (a INT, c INT); +INSERT INTO babel_update_tbl1 VALUES (1, 'left'), (2, 'inner'); +INSERT INTO babel_update_tbl2 VALUES (10, 'inner'), (30, 'right'); +INSERT INTO babel_update_tbl3 VALUES (1, 10), (3, 10); +go +CREATE VIEW babel_update_view AS SELECT * FROM babel_update_tbl1 WHERE babel_update_tbl1.a > 1; +go +CREATE SCHEMA babel_update_schema +go +CREATE TABLE babel_update_schema.babel_update_tbl1(a INT); +INSERT INTO babel_update_schema.babel_update_tbl1 VALUES (1), (2); +go + +------------------------------------------------------------- +-- UPDATE with alias as target +-- BABEL-2020 already covers test cases to use alias in FROM +------------------------------------------------------------- +-- alias + plain update +-- BABEL-2675 +BEGIN TRAN +UPDATE top(1) t1 SET a = a + 1 +FROM babel_update_tbl1 AS t1 +ROLLBACK +GO + +-- BABEL-3775 +BEGIN TRAN +UPDATE top(1) t1 SET t1.a = a + 1 +FROM babel_update_tbl1 t1 +ROLLBACK +GO + +-- alias + subquery +-- BABEL-1875 +BEGIN TRAN +UPDATE top(1) t1 SET a = t1.a + 1 +FROM babel_update_tbl1 t1 +INNER JOIN (SELECT * FROM babel_update_tbl1) t2 +ON t1.b = t2.b +ROLLBACK +GO + +-- alias + join +BEGIN TRAN +UPDATE top(1) t1 SET a = 10 +FROM babel_update_tbl2 t2 +JOIN babel_update_tbl1 t1 +ON t2.b = t1.b +ROLLBACK +go + +-- alias + self join +-- BABEL-1330 +BEGIN TRAN +UPDATE top(1) t1 SET t1.a = t1.a + 1 +FROM babel_update_tbl1 t1 +INNER JOIN babel_update_tbl1 t2 +ON t1.b = t2.b +ROLLBACK +go + +-- alias + inner join +-- BABEL-3091 +BEGIN TRAN +UPDATE top(1) t1 SET t1.a = t2.a +FROM babel_update_tbl1 AS t1 +INNER JOIN babel_update_tbl2 AS t2 +ON t1.b = t2.b +ROLLBACK +go + +-- alias + non-ANSI inner join +-- BABEL-3685 +BEGIN TRAN +UPDATE top(1) t1 SET a = 10 +FROM babel_update_tbl1 t2, babel_update_tbl3 t1 +WHERE c > 1 +ROLLBACK +go + +-- alias + outer join +BEGIN TRAN +UPDATE top(1) t1 SET a = 100 +FROM babel_update_tbl1 AS t1 +LEFT OUTER JOIN babel_update_tbl1 t2 +ON t2.b = t1.b +ROLLBACK +go + +-- alias + semi join +BEGIN TRAN +UPDATE top(1) t1 SET a = 100 +FROM babel_update_tbl1 AS t1 +WHERE t1.a IN +( + SELECT a FROM babel_update_tbl1 + WHERE babel_update_tbl1.a = t1.a +) +ROLLBACK +go + +-- alias + updatable view +BEGIN TRAN +INSERT INTO babel_update_tbl1 VALUES (3, 'extra') +UPDATE top(1) v1 SET a = 100 +FROM babel_update_view v1 +WHERE a = 2 +ROLLBACK +go + +-- alias + table ref with schema +BEGIN TRAN +UPDATE top(1) t1 SET t1.a = a + 1 +FROM babel_update_schema.babel_update_tbl1 t1 +ROLLBACK +GO + +DROP VIEW babel_update_view +go +DROP TABLE babel_update_tbl1 +DROP TABLE babel_update_tbl2 +DROP TABLE babel_update_tbl3 +DROP TABLE babel_update_schema.babel_update_tbl1 +go +DROP SCHEMA babel_update_schema +go + +------------------------------------------------------------- +-- BABEL-2020: DELETE +------------------------------------------------------------- +drop procedure if exists babel_2020_delete_ct; +go + +create procedure babel_2020_delete_ct as +begin + drop table if exists babel_2020_delete_t1 + create table babel_2020_delete_t1 (a int) + insert into babel_2020_delete_t1 values (1), (2), (NULL) + drop table if exists babel_2020_delete_t2 + create table babel_2020_delete_t2 (a int) + insert into babel_2020_delete_t2 values (2), (3), (NULL) +end +go + +-- single tables in FROM clause +exec babel_2020_delete_ct; +delete top(2) babel_2020_delete_t1 from babel_2020_delete_t1 x; +go + +-- JOIN clause, and top value > than # matching rows +exec babel_2020_delete_ct; +delete top(5) babel_2020_delete_t1 from babel_2020_delete_t1 x join babel_2020_delete_t2 y on 1 = 1; +go + +exec babel_2020_delete_ct; +delete top(2) babel_2020_delete_t1 from babel_2020_delete_t1 x join babel_2020_delete_t2 y on y.a = 2; +go + +-- subqueries +exec babel_2020_delete_ct; +delete top(1) babel_2020_delete_t1 from (select * from babel_2020_delete_t1) x; +go + +-- self join +exec babel_2020_delete_ct; +delete top(1) babel_2020_delete_t1 from babel_2020_delete_t1 x, (select * from babel_2020_delete_t1) y where x.a + 1 >= y.a; +go + +-- outer joins +exec babel_2020_delete_ct; +delete top(1) babel_2020_delete_t1 from babel_2020_delete_t1 x left outer join babel_2020_delete_t2 on babel_2020_delete_t2.a = x.a; +go + +-- semi joins +exec babel_2020_delete_ct; +delete top(1) babel_2020_delete_t1 from babel_2020_delete_t1 x where x.a in (select a from babel_2020_delete_t1 where babel_2020_delete_t1.a = x.a); +go + +exec babel_2020_delete_ct; +delete top(1) babel_2020_delete_t1 from babel_2020_delete_t1 x where not exists (select a from babel_2020_delete_t1 y where y.a + 1 = x.a); +go + +drop procedure if exists babel_2020_delete_ct; +drop table if exists babel_2020_delete_t1; +drop table if exists babel_2020_delete_t2; +go + +-- DELETE with alias as target +CREATE TABLE babel_delete_tbl1(a INT, b VARCHAR(10)); +CREATE TABLE babel_delete_tbl2(a INT, b VARCHAR(10)); +CREATE TABLE babel_delete_tbl3 (a INT, c INT); +INSERT INTO babel_delete_tbl1 VALUES (1, 'left'), (2, 'inner'); +INSERT INTO babel_delete_tbl2 VALUES (10, 'inner'), (30, 'right'); +INSERT INTO babel_delete_tbl3 VALUES (1, 10), (3, 10); +go + +CREATE VIEW babel_delete_view AS SELECT * FROM babel_delete_tbl1 WHERE babel_delete_tbl1.a > 1; +go +CREATE SCHEMA babel_delete_schema +go +CREATE TABLE babel_delete_schema.babel_delete_tbl1(a INT); +INSERT INTO babel_delete_schema.babel_delete_tbl1 VALUES (1), (2); +go + +-- alias + plain delete +BEGIN TRAN +DELETE top(1) t1 +FROM babel_delete_tbl1 AS t1 +ROLLBACK +GO + +BEGIN TRAN +DELETE top(1) t1 +FROM babel_delete_tbl1 t1 +ROLLBACK +GO + +-- alias + subquery +BEGIN TRAN +DELETE top(1) t1 +FROM babel_delete_tbl1 t1 +INNER JOIN (SELECT * FROM babel_delete_tbl1) t2 +ON t1.b = t2.b +ROLLBACK +GO + +-- alias + join +BEGIN TRAN +DELETE top(1) t1 +FROM babel_delete_tbl2 t2 +JOIN babel_delete_tbl1 t1 +ON t2.b = t1.b +ROLLBACK +go + +-- alias + self join +-- BABEL-1330 +BEGIN TRAN +DELETE top(1) t1 +FROM babel_delete_tbl1 t1 +INNER JOIN babel_delete_tbl1 t2 +ON t1.b = t2.b +ROLLBACK +go + +-- alias + inner join +BEGIN TRAN +DELETE top(1) t1 +FROM babel_delete_tbl1 AS t1 +INNER JOIN babel_delete_tbl2 AS t2 +ON t1.b = t2.b +ROLLBACK +go + +-- alias + non-ANSI inner join +BEGIN TRAN +DELETE top(1) t1 +FROM babel_delete_tbl1 t2, babel_delete_tbl3 t1 +WHERE c > 1 +ROLLBACK +go + +-- alias + outer join +BEGIN TRAN +DELETE top(1) t1 +FROM babel_delete_tbl1 AS t1 +LEFT OUTER JOIN babel_delete_tbl1 t2 +ON t2.b = t1.b +ROLLBACK +go + +-- alias + semi join +BEGIN TRAN +DELETE top(1) t1 +FROM babel_delete_tbl1 AS t1 +WHERE t1.a IN +( + SELECT a FROM babel_delete_tbl1 + WHERE babel_delete_tbl1.a = t1.a +) +ROLLBACK +go + +-- alias + updatable view +BEGIN TRAN +INSERT INTO babel_delete_tbl1 VALUES (3, 'extra') +DELETE top(1) v1 +FROM babel_delete_view v1 +WHERE a = 2 +ROLLBACK +go + +-- alias + table ref with schema +BEGIN TRAN +DELETE top(1) t1 +FROM babel_delete_schema.babel_delete_tbl1 t1 +ROLLBACK +GO + +-- target with schema +BEGIN TRAN +DELETE top(1) babel_delete_schema.babel_delete_tbl1 +ROLLBACK +GO + +-- should fail, same exposed names +DELETE top(1) babel_delete_schema.babel_delete_tbl1 +FROM babel_delete_tbl1 +GO + +-- should fail, same exposed names +DELETE top(1) babel_delete_schema.babel_delete_tbl1 +FROM babel_delete_tbl2 AS babel_delete_tbl1 +GO + + +DROP VIEW babel_delete_view +go +DROP TABLE babel_delete_tbl1 +DROP TABLE babel_delete_tbl2 +DROP TABLE babel_delete_tbl3 +DROP TABLE babel_delete_schema.babel_delete_tbl1 +go +DROP SCHEMA babel_delete_schema +go + +------------------------------------------------------------- +-- UPDATE, INSERT w/ error +------------------------------------------------------------- +create table babel_update_error(a int primary key) +go + +insert into babel_update_error values (1), (2), (3) +go + +insert top(2) into babel_update_error values (4), (1), (2) +go + +select * from babel_update_error order by a +go + +update top(2) babel_update_error set a = 5 where babel_update_error.a < 3 +go + +select * from babel_update_error order by a +go + +drop table babel_update_error +go + +------------------------------------------------------------- +-- BABEL-1139: INSERT TOP INTO +------------------------------------------------------------- +CREATE TABLE babel_1139_t1(a INT); +CREATE TABLE babel_1139_t2(a INT); +GO + +INSERT TOP(3) INTO babel_1139_t1 (a) values (1), (2), (3), (NULL) +GO + +INSERT TOP(2) INTO babel_1139_t2 SELECT a FROM babel_1139_t1; +GO + +INSERT TOP(1) INTO babel_1139_t1 DEFAULT VALUES; +GO + +INSERT TOP(4) INTO babel_1139_t2 DEFAULT VALUES; +GO + +TRUNCATE TABLE babel_1139_t1; +TRUNCATE TABLE babel_1139_t2; +GO + +INSERT TOP(5) INTO babel_1139_t1 (a) OUTPUT inserted.* VALUES (1), (1), (1), (1), (1), (1); +GO + +INSERT TOP(4) INTO babel_1139_t2 OUTPUT inserted.* SELECT a FROM babel_1139_t1; +GO + +INSERT TOP(1) INTO babel_1139_t1 OUTPUT inserted.a DEFAULT VALUES; +GO + +TRUNCATE TABLE babel_1139_t1; +TRUNCATE TABLE babel_1139_t2; +GO + +INSERT TOP(5) INTO babel_1139_t1 (a) OUTPUT inserted.a INTO babel_1139_t2 (a) VALUES (1), (1), (1), (1), (1), (1); +GO + +INSERT TOP(4) INTO babel_1139_t1 OUTPUT inserted.a INTO babel_1139_t2 (a) SELECT a FROM babel_1139_t1; +GO + +INSERT TOP(1) INTO babel_1139_t1 OUTPUT inserted.a INTO babel_1139_t2 (a) DEFAULT VALUES; +GO + +SELECT COUNT(*) FROM babel_1139_t1; +SELECT COUNT(*) FROM babel_1139_t2; +GO + +TRUNCATE TABLE babel_1139_t1; +TRUNCATE TABLE babel_1139_t2; +GO + +INSERT TOP(5) INTO babel_1139_t1 (a) OUTPUT inserted.a INTO babel_1139_t2 VALUES (1), (1), (1), (1), (1), (1); +GO + +INSERT TOP(4) INTO babel_1139_t1 OUTPUT inserted.a INTO babel_1139_t2 SELECT a FROM babel_1139_t1; +GO + +INSERT TOP(1) INTO babel_1139_t1 OUTPUT inserted.a INTO babel_1139_t2 DEFAULT VALUES; +GO + +SELECT COUNT(*) FROM babel_1139_t1; +SELECT COUNT(*) FROM babel_1139_t2; +GO + +DROP TABLE babel_1139_t1; +DROP TABLE babel_1139_t2; +GO diff --git a/test/JDBC/upgrade/13_4/schedule b/test/JDBC/upgrade/13_4/schedule index 305feb763b..bc8d48f26d 100644 --- a/test/JDBC/upgrade/13_4/schedule +++ b/test/JDBC/upgrade/13_4/schedule @@ -55,6 +55,7 @@ BABEL-3556-before-14_6 BABEL-3588 BABEL-3655 BABEL-3657 +BABEL-3725 BABEL-3938 BABEL-404 BABEL-4078-before-14_8-or-15_3 diff --git a/test/JDBC/upgrade/13_5/schedule b/test/JDBC/upgrade/13_5/schedule index 90ab236dd0..4e0e18efc0 100644 --- a/test/JDBC/upgrade/13_5/schedule +++ b/test/JDBC/upgrade/13_5/schedule @@ -61,6 +61,7 @@ BABEL-3556-before-14_6 BABEL-3588 BABEL-3655 BABEL-3657 +BABEL-3725 BABEL-3938 BABEL-404 BABEL-4078-before-14_8-or-15_3 diff --git a/test/JDBC/upgrade/13_6/schedule b/test/JDBC/upgrade/13_6/schedule index deca094bbe..05545e8933 100644 --- a/test/JDBC/upgrade/13_6/schedule +++ b/test/JDBC/upgrade/13_6/schedule @@ -78,6 +78,7 @@ BABEL-3640 BABEL-3646-before-14_6 BABEL-3655 BABEL-3657 +BABEL-3725 BABEL-3748-before-14_7 BABEL-383 BABEL-3938 diff --git a/test/JDBC/upgrade/13_7/schedule b/test/JDBC/upgrade/13_7/schedule index 557f4e06a1..36167a39bf 100644 --- a/test/JDBC/upgrade/13_7/schedule +++ b/test/JDBC/upgrade/13_7/schedule @@ -76,6 +76,7 @@ BABEL-3640 BABEL-3646-before-14_6 BABEL-3655 BABEL-3657 +BABEL-3725 BABEL-3748-before-14_7 BABEL-383 BABEL-3938 diff --git a/test/JDBC/upgrade/13_8/schedule b/test/JDBC/upgrade/13_8/schedule index 557f4e06a1..36167a39bf 100644 --- a/test/JDBC/upgrade/13_8/schedule +++ b/test/JDBC/upgrade/13_8/schedule @@ -76,6 +76,7 @@ BABEL-3640 BABEL-3646-before-14_6 BABEL-3655 BABEL-3657 +BABEL-3725 BABEL-3748-before-14_7 BABEL-383 BABEL-3938 diff --git a/test/JDBC/upgrade/13_9/schedule b/test/JDBC/upgrade/13_9/schedule index 5aa34cb6fd..5d9f149fdf 100644 --- a/test/JDBC/upgrade/13_9/schedule +++ b/test/JDBC/upgrade/13_9/schedule @@ -75,6 +75,7 @@ BABEL-3588 BABEL-3640 BABEL-3655 BABEL-3657 +BABEL-3725 BABEL-3748-before-14_7 BABEL-383 BABEL-3938 diff --git a/test/JDBC/upgrade/14_3/schedule b/test/JDBC/upgrade/14_3/schedule index e7fe2f889e..3de0979ba2 100644 --- a/test/JDBC/upgrade/14_3/schedule +++ b/test/JDBC/upgrade/14_3/schedule @@ -78,6 +78,7 @@ BABEL-3640 BABEL-3646-before-14_6 BABEL-3655 BABEL-3657 +BABEL-3725 BABEL-3748-before-14_7 BABEL-3801 BABEL-3818 diff --git a/test/JDBC/upgrade/14_5/schedule b/test/JDBC/upgrade/14_5/schedule index 45cb0fb9fc..e7913fb159 100644 --- a/test/JDBC/upgrade/14_5/schedule +++ b/test/JDBC/upgrade/14_5/schedule @@ -76,6 +76,7 @@ BABEL-3640 BABEL-3646-before-14_6 BABEL-3655 BABEL-3657 +BABEL-3725 BABEL-3748-before-14_7 BABEL-3801 BABEL-3818 diff --git a/test/JDBC/upgrade/14_6/schedule b/test/JDBC/upgrade/14_6/schedule index d09cdadca3..96f5d2612c 100644 --- a/test/JDBC/upgrade/14_6/schedule +++ b/test/JDBC/upgrade/14_6/schedule @@ -89,6 +89,7 @@ BABEL-3640 BABEL-3646 BABEL-3655 BABEL-3657 +BABEL-3725 BABEL-3748-before-14_7 BABEL-3801 BABEL-3818 diff --git a/test/JDBC/upgrade/14_7/schedule b/test/JDBC/upgrade/14_7/schedule index 3ca5f6bde3..3e28b7db29 100644 --- a/test/JDBC/upgrade/14_7/schedule +++ b/test/JDBC/upgrade/14_7/schedule @@ -92,6 +92,7 @@ BABEL-3646 BABEL-3655 BABEL-3657 BABEL-3702 +BABEL-3725 BABEL-3747 BABEL-3748 BABEL-3781 diff --git a/test/JDBC/upgrade/14_8/schedule b/test/JDBC/upgrade/14_8/schedule index b00fb9484b..cbd606a245 100644 --- a/test/JDBC/upgrade/14_8/schedule +++ b/test/JDBC/upgrade/14_8/schedule @@ -92,6 +92,7 @@ BABEL-3646 BABEL-3655 BABEL-3657 BABEL-3702 +BABEL-3725 BABEL-3747 BABEL-3748 BABEL-3781 diff --git a/test/JDBC/upgrade/15_1/schedule b/test/JDBC/upgrade/15_1/schedule index e31e64d534..f743903aa3 100644 --- a/test/JDBC/upgrade/15_1/schedule +++ b/test/JDBC/upgrade/15_1/schedule @@ -89,6 +89,7 @@ BABEL-3640 BABEL-3646 BABEL-3655 BABEL-3657 +BABEL-3725 BABEL-3748-before-14_7 BABEL-3801 BABEL-3818 diff --git a/test/JDBC/upgrade/15_2/schedule b/test/JDBC/upgrade/15_2/schedule index 74340a9caf..e7529a3013 100644 --- a/test/JDBC/upgrade/15_2/schedule +++ b/test/JDBC/upgrade/15_2/schedule @@ -92,6 +92,7 @@ BABEL-3646 BABEL-3655 BABEL-3657 BABEL-3702 +BABEL-3725 BABEL-3747 BABEL-3748 BABEL-3781 diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index aa1fa2e5b9..10ab355d80 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -96,6 +96,7 @@ BABEL-3657 BABEL-3696 BABEL-3697 BABEL-3702 +BABEL-3725 BABEL-3747 BABEL-3748 BABEL-3781 From 7f0e703d74dc83e07f37358cfd082f595c6aff92 Mon Sep 17 00:00:00 2001 From: Yanjie Xu Date: Mon, 24 Apr 2023 16:35:18 -0400 Subject: [PATCH 071/363] Fix @@NESTLEVEL is 1 unit too high (#1442) * [BABEL-2810] Fix @@NESTLEVEL is 1 too high This commit fixed @@NESTLEVEL in Babelfish is 1 unit too high. Task: BABEL-2810 Signed-off-by: Yanjie Xu --- .../babelfishpg_tsql/sql/sys_functions.sql | 4 +- .../babelfishpg_tsql--3.1.0--3.2.0.sql | 22 ++- test/JDBC/expected/BABEL-2843.out | 8 +- test/JDBC/expected/BABEL-2903.out | 8 +- .../JDBC/expected/TestTableType-vu-verify.out | 4 +- .../expected/sys-nestlevel-dep-vu-cleanup.out | 20 +++ .../expected/sys-nestlevel-dep-vu-prepare.out | 31 +++++ .../expected/sys-nestlevel-dep-vu-verify.out | 50 +++++++ test/JDBC/expected/sys-nestlevel.out | 131 ++++++++++++++++++ .../expected/table-variable-vu-verify.out | 8 +- .../input/sys-nestlevel-dep-vu-cleanup.sql | 20 +++ .../input/sys-nestlevel-dep-vu-prepare.sql | 31 +++++ .../input/sys-nestlevel-dep-vu-verify.sql | 10 ++ test/JDBC/input/sys-nestlevel.sql | 81 +++++++++++ test/JDBC/upgrade/13_4/schedule | 1 + test/JDBC/upgrade/13_5/schedule | 1 + test/JDBC/upgrade/13_6/schedule | 1 + test/JDBC/upgrade/13_7/schedule | 1 + test/JDBC/upgrade/13_8/schedule | 1 + test/JDBC/upgrade/13_9/schedule | 1 + test/JDBC/upgrade/14_3/schedule | 1 + test/JDBC/upgrade/14_5/schedule | 1 + test/JDBC/upgrade/14_6/schedule | 1 + test/JDBC/upgrade/14_7/schedule | 1 + test/JDBC/upgrade/14_8/schedule | 1 + test/JDBC/upgrade/15_1/schedule | 1 + test/JDBC/upgrade/15_2/schedule | 1 + test/JDBC/upgrade/latest/schedule | 1 + .../expected_create.out | 1 - 29 files changed, 425 insertions(+), 18 deletions(-) create mode 100644 test/JDBC/expected/sys-nestlevel-dep-vu-cleanup.out create mode 100644 test/JDBC/expected/sys-nestlevel-dep-vu-prepare.out create mode 100644 test/JDBC/expected/sys-nestlevel-dep-vu-verify.out create mode 100644 test/JDBC/expected/sys-nestlevel.out create mode 100644 test/JDBC/input/sys-nestlevel-dep-vu-cleanup.sql create mode 100644 test/JDBC/input/sys-nestlevel-dep-vu-prepare.sql create mode 100644 test/JDBC/input/sys-nestlevel-dep-vu-verify.sql create mode 100644 test/JDBC/input/sys-nestlevel.sql diff --git a/contrib/babelfishpg_tsql/sql/sys_functions.sql b/contrib/babelfishpg_tsql/sql/sys_functions.sql index 0ab3160864..48977065f6 100644 --- a/contrib/babelfishpg_tsql/sql/sys_functions.sql +++ b/contrib/babelfishpg_tsql/sql/sys_functions.sql @@ -1887,8 +1887,8 @@ DECLARE result integer; BEGIN GET DIAGNOSTICS stack = PG_CONTEXT; - result := array_length(string_to_array(stack, 'function'), 1) - 2; - IF result < 0 THEN + result := array_length(string_to_array(stack, 'function'), 1) - 3; + IF result < -1 THEN RAISE EXCEPTION 'Invalid output, check stack trace %', stack; ELSE RETURN result; diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql index 13f2e58b37..c3ef5921da 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql @@ -37,7 +37,27 @@ LANGUAGE plpgsql; * So make sure that any SQL statement (DDL/DML) being added here can be executed multiple times without affecting * final behaviour. */ - +ALTER FUNCTION sys.nestlevel() RENAME TO nestlevel_deprecated_in_3_2_0; + +CREATE OR REPLACE FUNCTION sys.nestlevel() RETURNS INTEGER AS +$$ +DECLARE + stack text; + result integer; +BEGIN + GET DIAGNOSTICS stack = PG_CONTEXT; + result := array_length(string_to_array(stack, 'function'), 1) - 3; + IF result < -1 THEN + RAISE EXCEPTION 'Invalid output, check stack trace %', stack; + ELSE + RETURN result; + END IF; +END; +$$ +LANGUAGE plpgsql STABLE; + +CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'nestlevel_deprecated_in_3_2_0'); + -- SYSUSERS CREATE OR REPLACE VIEW sys.sysusers AS SELECT Dbp.principal_id AS uid, diff --git a/test/JDBC/expected/BABEL-2843.out b/test/JDBC/expected/BABEL-2843.out index 63b5a58830..f29af4488e 100644 --- a/test/JDBC/expected/BABEL-2843.out +++ b/test/JDBC/expected/BABEL-2843.out @@ -289,7 +289,7 @@ Result (cost=0.00..0.26 rows=1 width=4) (actual rows=1 loops=1) ~~START~~ text Query Text: insert into "@tab" select * from babel_2843_t1 where a1 = "@param"; -Insert on "@tab_2" (cost=0.00..38.25 rows=0 width=0) (actual rows=0 loops=1) +Insert on "@tab_1" (cost=0.00..38.25 rows=0 width=0) (actual rows=0 loops=1) -> Seq Scan on babel_2843_t1 (cost=0.00..38.25 rows=11 width=8) (actual rows=1 loops=1) Filter: (a1 = 1) Rows Removed by Filter: 2 @@ -298,15 +298,15 @@ Insert on "@tab_2" (cost=0.00..38.25 rows=0 width=0) (actual rows=0 loops=1) ~~START~~ text Query Text: insert into "@tab" select * from babel_2843_t2 where a2 = "@param"; -Insert on "@tab_2" (cost=0.00..38.25 rows=0 width=0) (actual rows=0 loops=1) +Insert on "@tab_1" (cost=0.00..38.25 rows=0 width=0) (actual rows=0 loops=1) -> Seq Scan on babel_2843_t2 (cost=0.00..38.25 rows=11 width=8) (actual rows=1 loops=1) Filter: (a2 = 1) ~~END~~ ~~START~~ text -Query Text: select * from @tab_2 -Seq Scan on "@tab_2" (cost=0.00..32.60 rows=2260 width=8) (actual rows=2 loops=1) +Query Text: select * from @tab_1 +Seq Scan on "@tab_1" (cost=0.00..32.60 rows=2260 width=8) (actual rows=2 loops=1) ~~END~~ ~~START~~ diff --git a/test/JDBC/expected/BABEL-2903.out b/test/JDBC/expected/BABEL-2903.out index 67b96940fc..03ecc93832 100644 --- a/test/JDBC/expected/BABEL-2903.out +++ b/test/JDBC/expected/BABEL-2903.out @@ -60,7 +60,7 @@ Query Text: ASSIGN @b = SELECT 5 -> Result (cost=0.00..0.01 rows=1 width=4) Query Text: EXEC babel_2903_outer_proc @a, @b Query Text: DECLARE TABLE @t - Query Text: CREATE TEMPORARY TABLE IF NOT EXISTS @t_2 (a int, b int) + Query Text: CREATE TEMPORARY TABLE IF NOT EXISTS @t_1 (a int, b int) Query Text: ASSIGN @a = SELECT 3 Query Text: SELECT 3 -> Result (cost=0.00..0.01 rows=1 width=4) @@ -80,11 +80,11 @@ Query Text: EXEC babel_2903_outer_proc @a, @b -> Insert on babel_2903_t1 (cost=0.00..0.01 rows=0 width=0) -> Result (cost=0.00..0.01 rows=1 width=8) Query Text: insert into "@t" select * from babel_2903_t1; - -> Insert on "@t_2" (cost=0.00..32.60 rows=0 width=0) + -> Insert on "@t_1" (cost=0.00..32.60 rows=0 width=0) -> Seq Scan on babel_2903_t1 (cost=0.00..32.60 rows=2260 width=8) Query Text: select * from "@t" - -> Seq Scan on "@t_2" (cost=0.00..32.60 rows=2260 width=8) - Query Text: DROP TABLE @t_2 + -> Seq Scan on "@t_1" (cost=0.00..32.60 rows=2260 width=8) + Query Text: DROP TABLE @t_1 Query Text: select "@a", "@b" Result (cost=0.00..0.01 rows=1 width=8) ~~END~~ diff --git a/test/JDBC/expected/TestTableType-vu-verify.out b/test/JDBC/expected/TestTableType-vu-verify.out index c37e92b8b5..628126f7a7 100644 --- a/test/JDBC/expected/TestTableType-vu-verify.out +++ b/test/JDBC/expected/TestTableType-vu-verify.out @@ -36,7 +36,7 @@ int#!#varchar ~~ERROR (Code: 547)~~ -~~ERROR (Message: new row for relation "@tv_1" violates check constraint "testtabletype_vu_prepare_t2_c1_check")~~ +~~ERROR (Message: new row for relation "@tv_0" violates check constraint "testtabletype_vu_prepare_t2_c1_check")~~ declare @tv TestTableType_vu_prepare_t3; @@ -66,7 +66,7 @@ go ~~ERROR (Code: 2627)~~ -~~ERROR (Message: duplicate key value violates unique constraint "@tv_1_a_key")~~ +~~ERROR (Message: duplicate key value violates unique constraint "@tv_0_a_key")~~ ~~START~~ varchar#!#nvarchar#!#int#!#char#!#nchar#!#datetime#!#numeric diff --git a/test/JDBC/expected/sys-nestlevel-dep-vu-cleanup.out b/test/JDBC/expected/sys-nestlevel-dep-vu-cleanup.out new file mode 100644 index 0000000000..22802f8f67 --- /dev/null +++ b/test/JDBC/expected/sys-nestlevel-dep-vu-cleanup.out @@ -0,0 +1,20 @@ +USE nextleveldb +GO + +DROP PROC p4 +GO + +DROP PROC p3 +GO + +DROP PROC p2 +GO + +DROP PROC p1 +GO + +USE master +GO + +DROP DATABASE nextleveldb +GO diff --git a/test/JDBC/expected/sys-nestlevel-dep-vu-prepare.out b/test/JDBC/expected/sys-nestlevel-dep-vu-prepare.out new file mode 100644 index 0000000000..02d713b088 --- /dev/null +++ b/test/JDBC/expected/sys-nestlevel-dep-vu-prepare.out @@ -0,0 +1,31 @@ +CREATE DATABASE nextleveldb +GO + +USE nextleveldb +GO + +CREATE PROC p1 +AS +SELECT @@NESTLEVEL AS p1BeforeShouldBe1 +EXEC p2 +SELECT @@NESTLEVEL AS p1AfterShouldBe1 +GO + +CREATE PROC p2 + AS + SELECT @@NESTLEVEL AS p2BeforeShouldBe2 + EXEC p3 + SELECT @@NESTLEVEL AS p2AfterShouldBe2 +GO + +CREATE PROC p3 +AS +SELECT @@NESTLEVEL AS p3BeforeShouldBe3 +EXEC p4 +SELECT @@NESTLEVEL AS p3AfterShouldBe3 +GO + +CREATE PROC p4 +AS +SELECT @@NESTLEVEL AS p4ShouldBe4 +GO diff --git a/test/JDBC/expected/sys-nestlevel-dep-vu-verify.out b/test/JDBC/expected/sys-nestlevel-dep-vu-verify.out new file mode 100644 index 0000000000..aa23385d84 --- /dev/null +++ b/test/JDBC/expected/sys-nestlevel-dep-vu-verify.out @@ -0,0 +1,50 @@ +USE nextleveldb +GO + +-- should expect print out of 1, 2, 3, 4, 3, 2, 1 +EXEC p1 +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +2 +~~END~~ + +~~START~~ +int +3 +~~END~~ + +~~START~~ +int +4 +~~END~~ + +~~START~~ +int +3 +~~END~~ + +~~START~~ +int +2 +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +-- should expect print out of 0 +SELECT @@NESTLEVEL +GO +~~START~~ +int +0 +~~END~~ + diff --git a/test/JDBC/expected/sys-nestlevel.out b/test/JDBC/expected/sys-nestlevel.out new file mode 100644 index 0000000000..ffe9916a27 --- /dev/null +++ b/test/JDBC/expected/sys-nestlevel.out @@ -0,0 +1,131 @@ +CREATE DATABASE nextleveldb +GO + +USE nextleveldb +GO + +CREATE PROC p1 +AS +SELECT @@NESTLEVEL AS p1BeforeShouldBe1 +EXEC p2 +SELECT @@NESTLEVEL AS p1AfterShouldBe1 +GO + +CREATE PROC p2 + AS + SELECT @@NESTLEVEL AS p2BeforeShouldBe2 + EXEC p3 + SELECT @@NESTLEVEL AS p2AfterShouldBe2 +GO + +CREATE PROC p3 +AS +SELECT @@NESTLEVEL AS p3BeforeShouldBe3 +EXEC p4 +SELECT @@NESTLEVEL AS p3AfterShouldBe3 +GO + +CREATE PROC p4 +AS +SELECT @@NESTLEVEL AS p4ShouldBe4 +GO + +CREATE VIEW v0 +AS +SELECT @@NESTLEVEL AS v0ShouldBe0 +GO + +CREATE VIEW v1 +AS +SELECT * FROM v0 +GO + +-- should expect print out of 1, 2, 3, 4, 3, 2, 1 +EXEC p1 +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +2 +~~END~~ + +~~START~~ +int +3 +~~END~~ + +~~START~~ +int +4 +~~END~~ + +~~START~~ +int +3 +~~END~~ + +~~START~~ +int +2 +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +-- should expect print out of 0 +SELECT @@NESTLEVEL +GO +~~START~~ +int +0 +~~END~~ + + +-- should expect print out of 0 +SELECT * from v0 +GO +~~START~~ +int +0 +~~END~~ + + +-- should expect print out of 0 +SELECT * from v1 +GO +~~START~~ +int +0 +~~END~~ + + +DROP PROC p4 +GO + +DROP PROC p3 +GO + +DROP PROC p2 +GO + +DROP PROC p1 +GO + +DROP VIEW v1 +GO + +DROP VIEW v0 +GO + +USE master +GO + +DROP DATABASE nextleveldb +GO diff --git a/test/JDBC/expected/table-variable-vu-verify.out b/test/JDBC/expected/table-variable-vu-verify.out index 6eb29f6fc9..de790af8cf 100644 --- a/test/JDBC/expected/table-variable-vu-verify.out +++ b/test/JDBC/expected/table-variable-vu-verify.out @@ -70,7 +70,7 @@ Query Text: ASSIGN @b = SELECT 5 -> Result (cost=0.00..0.01 rows=1 width=4) Query Text: EXEC table_variable_vu_prepareouter_proc @a, @b Query Text: DECLARE TABLE @t - Query Text: CREATE TEMPORARY TABLE IF NOT EXISTS @t_2 (a int, b int) + Query Text: CREATE TEMPORARY TABLE IF NOT EXISTS @t_1 (a int, b int) Query Text: ASSIGN @a = SELECT 3 Query Text: SELECT 3 -> Result (cost=0.00..0.01 rows=1 width=4) @@ -90,11 +90,11 @@ Query Text: EXEC table_variable_vu_prepareouter_proc @a, @b -> Insert on table_variable_vu_preparet1 (cost=0.00..0.01 rows=0 width=0) -> Result (cost=0.00..0.01 rows=1 width=8) Query Text: insert into "@t" select * from table_variable_vu_preparet1; - -> Insert on "@t_2" (cost=0.00..32.60 rows=0 width=0) + -> Insert on "@t_1" (cost=0.00..32.60 rows=0 width=0) -> Seq Scan on table_variable_vu_preparet1 (cost=0.00..32.60 rows=2260 width=8) Query Text: select * from "@t" - -> Seq Scan on "@t_2" (cost=0.00..32.60 rows=2260 width=8) - Query Text: DROP TABLE @t_2 + -> Seq Scan on "@t_1" (cost=0.00..32.60 rows=2260 width=8) + Query Text: DROP TABLE @t_1 Query Text: select "@a", "@b" Result (cost=0.00..0.01 rows=1 width=8) ~~END~~ diff --git a/test/JDBC/input/sys-nestlevel-dep-vu-cleanup.sql b/test/JDBC/input/sys-nestlevel-dep-vu-cleanup.sql new file mode 100644 index 0000000000..aaf501170a --- /dev/null +++ b/test/JDBC/input/sys-nestlevel-dep-vu-cleanup.sql @@ -0,0 +1,20 @@ +USE nextleveldb +GO + +DROP PROC p4 +GO + +DROP PROC p3 +GO + +DROP PROC p2 +GO + +DROP PROC p1 +GO + +USE master +GO + +DROP DATABASE nextleveldb +GO \ No newline at end of file diff --git a/test/JDBC/input/sys-nestlevel-dep-vu-prepare.sql b/test/JDBC/input/sys-nestlevel-dep-vu-prepare.sql new file mode 100644 index 0000000000..edb4c2d6f4 --- /dev/null +++ b/test/JDBC/input/sys-nestlevel-dep-vu-prepare.sql @@ -0,0 +1,31 @@ +CREATE DATABASE nextleveldb +GO + +USE nextleveldb +GO + +CREATE PROC p1 +AS +SELECT @@NESTLEVEL AS p1BeforeShouldBe1 +EXEC p2 +SELECT @@NESTLEVEL AS p1AfterShouldBe1 +GO + +CREATE PROC p2 + AS + SELECT @@NESTLEVEL AS p2BeforeShouldBe2 + EXEC p3 + SELECT @@NESTLEVEL AS p2AfterShouldBe2 +GO + +CREATE PROC p3 +AS +SELECT @@NESTLEVEL AS p3BeforeShouldBe3 +EXEC p4 +SELECT @@NESTLEVEL AS p3AfterShouldBe3 +GO + +CREATE PROC p4 +AS +SELECT @@NESTLEVEL AS p4ShouldBe4 +GO \ No newline at end of file diff --git a/test/JDBC/input/sys-nestlevel-dep-vu-verify.sql b/test/JDBC/input/sys-nestlevel-dep-vu-verify.sql new file mode 100644 index 0000000000..8f819b3120 --- /dev/null +++ b/test/JDBC/input/sys-nestlevel-dep-vu-verify.sql @@ -0,0 +1,10 @@ +USE nextleveldb +GO + +-- should expect print out of 1, 2, 3, 4, 3, 2, 1 +EXEC p1 +GO + +-- should expect print out of 0 +SELECT @@NESTLEVEL +GO \ No newline at end of file diff --git a/test/JDBC/input/sys-nestlevel.sql b/test/JDBC/input/sys-nestlevel.sql new file mode 100644 index 0000000000..ac99d83050 --- /dev/null +++ b/test/JDBC/input/sys-nestlevel.sql @@ -0,0 +1,81 @@ +CREATE DATABASE nextleveldb +GO + +USE nextleveldb +GO + +CREATE PROC p1 +AS +SELECT @@NESTLEVEL AS p1BeforeShouldBe1 +EXEC p2 +SELECT @@NESTLEVEL AS p1AfterShouldBe1 +GO + +CREATE PROC p2 + AS + SELECT @@NESTLEVEL AS p2BeforeShouldBe2 + EXEC p3 + SELECT @@NESTLEVEL AS p2AfterShouldBe2 +GO + +CREATE PROC p3 +AS +SELECT @@NESTLEVEL AS p3BeforeShouldBe3 +EXEC p4 +SELECT @@NESTLEVEL AS p3AfterShouldBe3 +GO + +CREATE PROC p4 +AS +SELECT @@NESTLEVEL AS p4ShouldBe4 +GO + +CREATE VIEW v0 +AS +SELECT @@NESTLEVEL AS v0ShouldBe0 +GO + +CREATE VIEW v1 +AS +SELECT * FROM v0 +GO + +-- should expect print out of 1, 2, 3, 4, 3, 2, 1 +EXEC p1 +GO + +-- should expect print out of 0 +SELECT @@NESTLEVEL +GO + +-- should expect print out of 0 +SELECT * from v0 +GO + +-- should expect print out of 0 +SELECT * from v1 +GO + +DROP PROC p4 +GO + +DROP PROC p3 +GO + +DROP PROC p2 +GO + +DROP PROC p1 +GO + +DROP VIEW v1 +GO + +DROP VIEW v0 +GO + +USE master +GO + +DROP DATABASE nextleveldb +GO \ No newline at end of file diff --git a/test/JDBC/upgrade/13_4/schedule b/test/JDBC/upgrade/13_4/schedule index bc8d48f26d..cba037bb48 100644 --- a/test/JDBC/upgrade/13_4/schedule +++ b/test/JDBC/upgrade/13_4/schedule @@ -140,6 +140,7 @@ sys-key_constraints sys-key_constraints-dep sys-lock_timeout sys-max_connections +sys-nestlevel-dep sys-objects sys-original_login sys-procedures diff --git a/test/JDBC/upgrade/13_5/schedule b/test/JDBC/upgrade/13_5/schedule index 4e0e18efc0..dadc24c693 100644 --- a/test/JDBC/upgrade/13_5/schedule +++ b/test/JDBC/upgrade/13_5/schedule @@ -172,6 +172,7 @@ sys-key_constraints-dep sys-lock_timeout sys-master_files sys-max_connections +sys-nestlevel-dep sys-objects sys-original_login sys-procedures diff --git a/test/JDBC/upgrade/13_6/schedule b/test/JDBC/upgrade/13_6/schedule index 05545e8933..945ee8ce26 100644 --- a/test/JDBC/upgrade/13_6/schedule +++ b/test/JDBC/upgrade/13_6/schedule @@ -220,6 +220,7 @@ sys-key_constraints-dep sys-lock_timeout sys-master_files sys-max_connections +sys-nestlevel-dep sys-objects sys-original_login sys-procedures diff --git a/test/JDBC/upgrade/13_7/schedule b/test/JDBC/upgrade/13_7/schedule index 36167a39bf..113873ea3f 100644 --- a/test/JDBC/upgrade/13_7/schedule +++ b/test/JDBC/upgrade/13_7/schedule @@ -215,6 +215,7 @@ sys-key_constraints-dep sys-lock_timeout sys-master_files sys-max_connections +sys-nestlevel-dep sys-objects sys-original_login sys-procedures diff --git a/test/JDBC/upgrade/13_8/schedule b/test/JDBC/upgrade/13_8/schedule index 36167a39bf..113873ea3f 100644 --- a/test/JDBC/upgrade/13_8/schedule +++ b/test/JDBC/upgrade/13_8/schedule @@ -215,6 +215,7 @@ sys-key_constraints-dep sys-lock_timeout sys-master_files sys-max_connections +sys-nestlevel-dep sys-objects sys-original_login sys-procedures diff --git a/test/JDBC/upgrade/13_9/schedule b/test/JDBC/upgrade/13_9/schedule index 5d9f149fdf..b2f4cd13f0 100644 --- a/test/JDBC/upgrade/13_9/schedule +++ b/test/JDBC/upgrade/13_9/schedule @@ -216,6 +216,7 @@ sys-key_constraints-dep sys-lock_timeout sys-master_files sys-max_connections +sys-nestlevel-dep sys-objects sys-original_login sys-procedures diff --git a/test/JDBC/upgrade/14_3/schedule b/test/JDBC/upgrade/14_3/schedule index 3de0979ba2..4646968640 100644 --- a/test/JDBC/upgrade/14_3/schedule +++ b/test/JDBC/upgrade/14_3/schedule @@ -230,6 +230,7 @@ sys-key_constraints-dep sys-lock_timeout sys-master_files sys-max_connections +sys-nestlevel-dep sys-objects sys-original_login sys-procedures diff --git a/test/JDBC/upgrade/14_5/schedule b/test/JDBC/upgrade/14_5/schedule index e7913fb159..d96a49051e 100644 --- a/test/JDBC/upgrade/14_5/schedule +++ b/test/JDBC/upgrade/14_5/schedule @@ -242,6 +242,7 @@ sys-key_constraints-dep sys-lock_timeout sys-master_files sys-max_connections +sys-nestlevel-dep sys-numbered_procedures sys-objects sys-original_login diff --git a/test/JDBC/upgrade/14_6/schedule b/test/JDBC/upgrade/14_6/schedule index 96f5d2612c..b85283ea55 100644 --- a/test/JDBC/upgrade/14_6/schedule +++ b/test/JDBC/upgrade/14_6/schedule @@ -273,6 +273,7 @@ sys-key_constraints-dep sys-lock_timeout sys-master_files sys-max_connections +sys-nestlevel-dep sys-numbered_procedures sys-objects sys-original_login diff --git a/test/JDBC/upgrade/14_7/schedule b/test/JDBC/upgrade/14_7/schedule index 3e28b7db29..bc12474613 100644 --- a/test/JDBC/upgrade/14_7/schedule +++ b/test/JDBC/upgrade/14_7/schedule @@ -291,6 +291,7 @@ sys-key_constraints-dep sys-lock_timeout sys-master_files sys-max_connections +sys-nestlevel-dep sys-numbered_procedures sys-objects sys-original_login diff --git a/test/JDBC/upgrade/14_8/schedule b/test/JDBC/upgrade/14_8/schedule index cbd606a245..892eeb4fb3 100644 --- a/test/JDBC/upgrade/14_8/schedule +++ b/test/JDBC/upgrade/14_8/schedule @@ -290,6 +290,7 @@ sys-key_constraints-dep sys-lock_timeout sys-master_files sys-max_connections +sys-nestlevel-dep sys-numbered_procedures sys-objects sys-original_login diff --git a/test/JDBC/upgrade/15_1/schedule b/test/JDBC/upgrade/15_1/schedule index f743903aa3..bc9f81b99f 100644 --- a/test/JDBC/upgrade/15_1/schedule +++ b/test/JDBC/upgrade/15_1/schedule @@ -273,6 +273,7 @@ sys-key_constraints-dep sys-lock_timeout sys-master_files sys-max_connections +sys-nestlevel-dep sys-numbered_procedures sys-objects sys-original_login diff --git a/test/JDBC/upgrade/15_2/schedule b/test/JDBC/upgrade/15_2/schedule index e7529a3013..5db7699572 100644 --- a/test/JDBC/upgrade/15_2/schedule +++ b/test/JDBC/upgrade/15_2/schedule @@ -295,6 +295,7 @@ sys-key_constraints-dep sys-lock_timeout sys-master_files sys-max_connections +sys-nestlevel-dep sys-numbered_procedures sys-objects sys-original_login diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index 10ab355d80..98d2ae9b95 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -307,6 +307,7 @@ sys-key_constraints-dep sys-lock_timeout sys-master_files sys-max_connections +sys-nestlevel-dep sys-numbered_procedures sys-objects sys-original_login diff --git a/test/python/expected/sql_validation_framework/expected_create.out b/test/python/expected/sql_validation_framework/expected_create.out index a3b4bbe11f..e08a501960 100644 --- a/test/python/expected/sql_validation_framework/expected_create.out +++ b/test/python/expected/sql_validation_framework/expected_create.out @@ -132,7 +132,6 @@ Could not find upgrade tests for function sys.is_rolemember_internal Could not find upgrade tests for function sys.language Could not find upgrade tests for function sys.max_precision Could not find upgrade tests for function sys.microsoftversion -Could not find upgrade tests for function sys.nestlevel Could not find upgrade tests for function sys.openjson_array Could not find upgrade tests for function sys.openjson_object Could not find upgrade tests for function sys.openjson_simple From 7bb23758913cd114857b5d47b73f11d033d7ba67 Mon Sep 17 00:00:00 2001 From: Suthapalli-Ramya-satya-vasavi-srija <110654856+Suthapalli-Ramya-satya-vasavi-srija@users.noreply.github.com> Date: Tue, 25 Apr 2023 22:01:28 +0530 Subject: [PATCH 072/363] Fix ownership_restrictions_from_pg test file (#1463) [OSS-ONLY] The test file 'ownership_restrictions_from_pg' creates an SUPERUSER and tests the changes using SUPERUSER and in jdbc_testdb(DB where BBF is initialized). This commit creates an separate test file to test the changes for SUPERUSER and jdbc_testdb. Signed-off-by: vasavi suthapalli --- .../ownership_restrictions_from_pg.out | 136 ++-------------- ...ownership_restrictions_from_pg_su_user.out | 154 ++++++++++++++++++ .../input/ownership_restrictions_from_pg.mix | 76 ++------- ...ownership_restrictions_from_pg_su_user.mix | 89 ++++++++++ 4 files changed, 265 insertions(+), 190 deletions(-) create mode 100644 test/JDBC/expected/ownership_restrictions_from_pg_su_user.out create mode 100644 test/JDBC/input/ownership_restrictions_from_pg_su_user.mix diff --git a/test/JDBC/expected/ownership_restrictions_from_pg.out b/test/JDBC/expected/ownership_restrictions_from_pg.out index 8f8277b99e..e618e28255 100644 --- a/test/JDBC/expected/ownership_restrictions_from_pg.out +++ b/test/JDBC/expected/ownership_restrictions_from_pg.out @@ -1,5 +1,5 @@ -- tsql -CREATE LOGIN ownership_restrictions_from_pg_login1 WITH password = '123'; +CREATE LOGIN ownership_restrictions_from_pg_login1 WITH password = '12345678'; GO CREATE ROLE ownership_restrictions_from_pg_role1; @@ -15,9 +15,6 @@ GO CREATE USER ownership_restrictions_from_pg_test_user WITH PASSWORD '12345678' inherit; go -CREATE USER ownership_restrictions_from_pg_test_su_user WITH SUPERUSER LOGIN PASSWORD 'abc'; -GO - -- psql user=ownership_restrictions_from_pg_login1 password=12345678 -- If tsql login connected through psql Alter ROLE of an bbf created logins/user/roles for password, -- connection limit and valid until should be working fine @@ -41,10 +38,10 @@ GO Server SQLState: 42501)~~ -ALTER ROLE master_ownership_restrictions_from_pg_role1 with ENCRYPTED password '123'; +ALTER ROLE master_ownership_restrictions_from_pg_role1 with ENCRYPTED password '12345678'; GO -ALTER ROLE master_ownership_restrictions_from_pg_role1 with password '123'; +ALTER ROLE master_ownership_restrictions_from_pg_role1 with password '12345678'; GO ALTER ROLE master_ownership_restrictions_from_pg_role1 with password NULL; @@ -173,14 +170,6 @@ GO Server SQLState: 3D000)~~ -ALTER ROLE ALL IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; -GO -~~ERROR (Code: 0)~~ - -~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session - Server SQLState: 42501)~~ - - ALTER ROLE master_ownership_restrictions_from_pg_role1 set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; GO ~~ERROR (Code: 0)~~ @@ -221,38 +210,6 @@ GO Server SQLState: 42501)~~ -ALTER ROLE master_ownership_restrictions_from_pg_role1 IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; -GO -~~ERROR (Code: 0)~~ - -~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session - Server SQLState: 42501)~~ - - -ALTER ROLE CURRENT_ROLE IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; -GO -~~ERROR (Code: 0)~~ - -~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session - Server SQLState: 42501)~~ - - -ALTER ROLE CURRENT_USER IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; -GO -~~ERROR (Code: 0)~~ - -~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session - Server SQLState: 42501)~~ - - -ALTER ROLE SESSION_USER IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; -GO -~~ERROR (Code: 0)~~ - -~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session - Server SQLState: 42501)~~ - - ALTER ROLE ownership_restrictions_from_pg_login1 RENAME TO ownership_restrictions_from_pg_role2; GO ~~ERROR (Code: 0)~~ @@ -264,7 +221,7 @@ GO ALTER ROLE ownership_restrictions_from_pg_login1 VALID UNTIL 'infinity'; GO -alter role ownership_restrictions_from_pg_login1 with password '123'; +alter role ownership_restrictions_from_pg_login1 with password '12345678'; GO ALTER ROLE ownership_restrictions_from_pg_login1 IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; @@ -275,16 +232,8 @@ GO Server SQLState: 42501)~~ -ALTER ROLE ownership_restrictions_from_pg_login1 IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; -GO -~~ERROR (Code: 0)~~ - -~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session - Server SQLState: 42501)~~ - - -- If the stmt contains a non-allowed option then altering of role not allowed -ALTER ROLE master_ownership_restrictions_from_pg_role1 WITH NOCREATEDB CONNECTION LIMIT 1 password '123'; +ALTER ROLE master_ownership_restrictions_from_pg_role1 WITH NOCREATEDB CONNECTION LIMIT 1 password '12345678'; GO ~~ERROR (Code: 0)~~ @@ -292,7 +241,7 @@ GO Server SQLState: 42501)~~ -ALTER ROLE ownership_restrictions_from_pg_login1 WITH NOCREATEDB CONNECTION LIMIT 1 password '123'; +ALTER ROLE ownership_restrictions_from_pg_login1 WITH NOCREATEDB CONNECTION LIMIT 1 password '12345678'; GO ~~ERROR (Code: 0)~~ @@ -328,7 +277,7 @@ GO Server SQLState: 42501)~~ -ALTER ROLE master_ownership_restrictions_from_pg_role1 with ENCRYPTED password '123'; +ALTER ROLE master_ownership_restrictions_from_pg_role1 with ENCRYPTED password '12345678'; GO ~~ERROR (Code: 0)~~ @@ -336,7 +285,7 @@ GO Server SQLState: 42501)~~ -ALTER ROLE master_ownership_restrictions_from_pg_role1 with password '123'; +ALTER ROLE master_ownership_restrictions_from_pg_role1 with password '12345678'; GO ~~ERROR (Code: 0)~~ @@ -480,14 +429,6 @@ GO Server SQLState: 3D000)~~ -ALTER ROLE ALL IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; -GO -~~ERROR (Code: 0)~~ - -~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session - Server SQLState: 42501)~~ - - ALTER ROLE master_ownership_restrictions_from_pg_role1 set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; GO ~~ERROR (Code: 0)~~ @@ -528,38 +469,6 @@ GO Server SQLState: 3D000)~~ -ALTER ROLE master_ownership_restrictions_from_pg_role1 IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; -GO -~~ERROR (Code: 0)~~ - -~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session - Server SQLState: 42501)~~ - - -ALTER ROLE CURRENT_ROLE IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; -GO -~~ERROR (Code: 0)~~ - -~~ERROR (Message: ERROR: permission denied to set parameter "babelfishpg_tsql.ownership_restrictions_from_pg_test_variable" - Server SQLState: 42501)~~ - - -ALTER ROLE CURRENT_USER IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; -GO -~~ERROR (Code: 0)~~ - -~~ERROR (Message: ERROR: permission denied to set parameter "babelfishpg_tsql.ownership_restrictions_from_pg_test_variable" - Server SQLState: 42501)~~ - - -ALTER ROLE SESSION_USER IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; -GO -~~ERROR (Code: 0)~~ - -~~ERROR (Message: ERROR: permission denied to set parameter "babelfishpg_tsql.ownership_restrictions_from_pg_test_variable" - Server SQLState: 42501)~~ - - ALTER ROLE ownership_restrictions_from_pg_login1 RENAME TO ownership_restrictions_from_pg_role2; GO ~~ERROR (Code: 0)~~ @@ -576,7 +485,7 @@ GO Server SQLState: 42501)~~ -alter role ownership_restrictions_from_pg_login1 with password '123'; +alter role ownership_restrictions_from_pg_login1 with password '12345678'; GO ~~ERROR (Code: 0)~~ @@ -592,16 +501,8 @@ GO Server SQLState: 42501)~~ -ALTER ROLE ownership_restrictions_from_pg_login1 IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; -GO -~~ERROR (Code: 0)~~ - -~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session - Server SQLState: 42501)~~ - - -- If the stmt contains a non-allowed option then altering of role not allowed -ALTER ROLE master_ownership_restrictions_from_pg_role1 WITH NOCREATEDB CONNECTION LIMIT 1 password '123'; +ALTER ROLE master_ownership_restrictions_from_pg_role1 WITH NOCREATEDB CONNECTION LIMIT 1 password '12345678'; GO ~~ERROR (Code: 0)~~ @@ -609,7 +510,7 @@ GO Server SQLState: 42501)~~ -ALTER ROLE ownership_restrictions_from_pg_login1 WITH NOCREATEDB CONNECTION LIMIT 1 password '123'; +ALTER ROLE ownership_restrictions_from_pg_login1 WITH NOCREATEDB CONNECTION LIMIT 1 password '12345678'; GO ~~ERROR (Code: 0)~~ @@ -617,14 +518,6 @@ GO Server SQLState: 42501)~~ --- psql user=ownership_restrictions_from_pg_test_su_user password=abc --- Altering of babelfish created logins/roles should suceeded for superuser -ALTER ROLE ownership_restrictions_from_pg_login1 VALID UNTIL 'infinity'; -GO - -ALTER ROLE master_ownership_restrictions_from_pg_role1 WITH NOCREATEDB CONNECTION LIMIT 1 password '123'; -GO - -- psql -- Dropping login from psql port should fail DROP ROLE ownership_restrictions_from_pg_login1; @@ -690,13 +583,6 @@ GO DROP ROLE ownership_restrictions_from_pg_role4; GO -SET enable_drop_babelfish_role = true; -go -DROP USER ownership_restrictions_from_pg_test_su_user; -go -SET enable_drop_babelfish_role = false; -go - DROP USER ownership_restrictions_from_pg_test_user; GO diff --git a/test/JDBC/expected/ownership_restrictions_from_pg_su_user.out b/test/JDBC/expected/ownership_restrictions_from_pg_su_user.out new file mode 100644 index 0000000000..190e9dac73 --- /dev/null +++ b/test/JDBC/expected/ownership_restrictions_from_pg_su_user.out @@ -0,0 +1,154 @@ +-- tsql +CREATE LOGIN ownership_restrictions_from_pg_login1 WITH password = '12345678'; +GO + +CREATE ROLE ownership_restrictions_from_pg_role1; +GO + +DECLARE @ownership_restrictions_from_pg_test_variable int = 100; +GO + +-- psql +CREATE USER ownership_restrictions_from_pg_test_user WITH PASSWORD '12345678' inherit; +go + +CREATE USER ownership_restrictions_from_pg_test_su_user WITH SUPERUSER LOGIN PASSWORD '12345678'; +GO + +-- psql user=ownership_restrictions_from_pg_login1 password=12345678 +-- If tsql login connected through psql Alter ROLE of an bbf created logins/user/roles for password, +-- connection limit and valid until should be working fine +-- and the rest of alter role operations should throw an error. +ALTER ROLE ALL IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE CURRENT_ROLE IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE CURRENT_USER IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE SESSION_USER IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE ownership_restrictions_from_pg_login1 IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +-- psql user=ownership_restrictions_from_pg_test_user password=12345678 +-- For plain psql user Alter ROLE of an bbf created logins/user/roles for password, +-- connection limit and valid until should be working fine +-- and the rest of alter role operations should throw an error. +ALTER ROLE ALL IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE master_ownership_restrictions_from_pg_role1 IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +ALTER ROLE CURRENT_ROLE IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: permission denied to set parameter "babelfishpg_tsql.ownership_restrictions_from_pg_test_variable" + Server SQLState: 42501)~~ + + +ALTER ROLE CURRENT_USER IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: permission denied to set parameter "babelfishpg_tsql.ownership_restrictions_from_pg_test_variable" + Server SQLState: 42501)~~ + + +ALTER ROLE SESSION_USER IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: permission denied to set parameter "babelfishpg_tsql.ownership_restrictions_from_pg_test_variable" + Server SQLState: 42501)~~ + + +ALTER ROLE ownership_restrictions_from_pg_login1 IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +-- psql user=ownership_restrictions_from_pg_test_su_user password=12345678 +-- Altering of babelfish created logins/roles should suceeded for superuser +ALTER ROLE ownership_restrictions_from_pg_login1 VALID UNTIL 'infinity'; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 WITH NOCREATEDB CONNECTION LIMIT 1 password '12345678'; +GO + +-- psql +SET enable_drop_babelfish_role = true; +go +DROP USER ownership_restrictions_from_pg_test_su_user; +go +SET enable_drop_babelfish_role = false; +go + +DROP USER ownership_restrictions_from_pg_test_user; +GO + +-- Need to terminate active session before cleaning up the login +SELECT pg_terminate_backend(pid) FROM pg_stat_get_activity(NULL) +WHERE sys.suser_name(usesysid) = 'ownership_restrictions_from_pg_login1' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +GO +~~START~~ +bool +t +~~END~~ + + +-- tsql +DROP ROLE ownership_restrictions_from_pg_role1; +DROP LOGIN ownership_restrictions_from_pg_login1; +GO diff --git a/test/JDBC/input/ownership_restrictions_from_pg.mix b/test/JDBC/input/ownership_restrictions_from_pg.mix index dc373e93b8..f2ff786f35 100644 --- a/test/JDBC/input/ownership_restrictions_from_pg.mix +++ b/test/JDBC/input/ownership_restrictions_from_pg.mix @@ -1,5 +1,5 @@ -- tsql -CREATE LOGIN ownership_restrictions_from_pg_login1 WITH password = '123'; +CREATE LOGIN ownership_restrictions_from_pg_login1 WITH password = '12345678'; GO CREATE ROLE ownership_restrictions_from_pg_role1; @@ -15,9 +15,6 @@ GO CREATE USER ownership_restrictions_from_pg_test_user WITH PASSWORD '12345678' inherit; go -CREATE USER ownership_restrictions_from_pg_test_su_user WITH SUPERUSER LOGIN PASSWORD 'abc'; -GO - -- psql user=ownership_restrictions_from_pg_login1 password=12345678 -- If tsql login connected through psql Alter ROLE of an bbf created logins/user/roles for password, -- connection limit and valid until should be working fine @@ -31,10 +28,10 @@ GO ALTER ROLE master_ownership_restrictions_from_pg_role1 rename to master_ownership_restrictions_from_pg_role5; GO -ALTER ROLE master_ownership_restrictions_from_pg_role1 with ENCRYPTED password '123'; +ALTER ROLE master_ownership_restrictions_from_pg_role1 with ENCRYPTED password '12345678'; GO -ALTER ROLE master_ownership_restrictions_from_pg_role1 with password '123'; +ALTER ROLE master_ownership_restrictions_from_pg_role1 with password '12345678'; GO ALTER ROLE master_ownership_restrictions_from_pg_role1 with password NULL; @@ -88,9 +85,6 @@ GO ALTER ROLE ALL IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; GO -ALTER ROLE ALL IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; -GO - ALTER ROLE master_ownership_restrictions_from_pg_role1 set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; GO @@ -106,38 +100,23 @@ GO ALTER ROLE SESSION_USER IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; GO -ALTER ROLE master_ownership_restrictions_from_pg_role1 IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; -GO - -ALTER ROLE CURRENT_ROLE IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; -GO - -ALTER ROLE CURRENT_USER IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; -GO - -ALTER ROLE SESSION_USER IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; -GO - ALTER ROLE ownership_restrictions_from_pg_login1 RENAME TO ownership_restrictions_from_pg_role2; GO ALTER ROLE ownership_restrictions_from_pg_login1 VALID UNTIL 'infinity'; GO -alter role ownership_restrictions_from_pg_login1 with password '123'; +alter role ownership_restrictions_from_pg_login1 with password '12345678'; GO ALTER ROLE ownership_restrictions_from_pg_login1 IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; GO -ALTER ROLE ownership_restrictions_from_pg_login1 IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; -GO - -- If the stmt contains a non-allowed option then altering of role not allowed -ALTER ROLE master_ownership_restrictions_from_pg_role1 WITH NOCREATEDB CONNECTION LIMIT 1 password '123'; +ALTER ROLE master_ownership_restrictions_from_pg_role1 WITH NOCREATEDB CONNECTION LIMIT 1 password '12345678'; GO -ALTER ROLE ownership_restrictions_from_pg_login1 WITH NOCREATEDB CONNECTION LIMIT 1 password '123'; +ALTER ROLE ownership_restrictions_from_pg_login1 WITH NOCREATEDB CONNECTION LIMIT 1 password '12345678'; GO -- psql user=ownership_restrictions_from_pg_test_user password=12345678 @@ -153,10 +132,10 @@ GO ALTER ROLE master_ownership_restrictions_from_pg_role1 rename to master_ownership_restrictions_from_pg_role5; GO -ALTER ROLE master_ownership_restrictions_from_pg_role1 with ENCRYPTED password '123'; +ALTER ROLE master_ownership_restrictions_from_pg_role1 with ENCRYPTED password '12345678'; GO -ALTER ROLE master_ownership_restrictions_from_pg_role1 with password '123'; +ALTER ROLE master_ownership_restrictions_from_pg_role1 with password '12345678'; GO ALTER ROLE master_ownership_restrictions_from_pg_role1 with password NULL; @@ -210,9 +189,6 @@ GO ALTER ROLE ALL IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; GO -ALTER ROLE ALL IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; -GO - ALTER ROLE master_ownership_restrictions_from_pg_role1 set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; GO @@ -228,46 +204,23 @@ GO ALTER ROLE SESSION_USER IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; GO -ALTER ROLE master_ownership_restrictions_from_pg_role1 IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; -GO - -ALTER ROLE CURRENT_ROLE IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; -GO - -ALTER ROLE CURRENT_USER IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; -GO - -ALTER ROLE SESSION_USER IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; -GO - ALTER ROLE ownership_restrictions_from_pg_login1 RENAME TO ownership_restrictions_from_pg_role2; GO ALTER ROLE ownership_restrictions_from_pg_login1 VALID UNTIL 'infinity'; GO -alter role ownership_restrictions_from_pg_login1 with password '123'; +alter role ownership_restrictions_from_pg_login1 with password '12345678'; GO ALTER ROLE ownership_restrictions_from_pg_login1 IN DATABASE ownership_restrictions_from_pg_db set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; GO -ALTER ROLE ownership_restrictions_from_pg_login1 IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; -GO - -- If the stmt contains a non-allowed option then altering of role not allowed -ALTER ROLE master_ownership_restrictions_from_pg_role1 WITH NOCREATEDB CONNECTION LIMIT 1 password '123'; -GO - -ALTER ROLE ownership_restrictions_from_pg_login1 WITH NOCREATEDB CONNECTION LIMIT 1 password '123'; +ALTER ROLE master_ownership_restrictions_from_pg_role1 WITH NOCREATEDB CONNECTION LIMIT 1 password '12345678'; GO --- psql user=ownership_restrictions_from_pg_test_su_user password=abc --- Altering of babelfish created logins/roles should suceeded for superuser -ALTER ROLE ownership_restrictions_from_pg_login1 VALID UNTIL 'infinity'; -GO - -ALTER ROLE master_ownership_restrictions_from_pg_role1 WITH NOCREATEDB CONNECTION LIMIT 1 password '123'; +ALTER ROLE ownership_restrictions_from_pg_login1 WITH NOCREATEDB CONNECTION LIMIT 1 password '12345678'; GO -- psql @@ -320,13 +273,6 @@ GO DROP ROLE ownership_restrictions_from_pg_role4; GO -SET enable_drop_babelfish_role = true; -go -DROP USER ownership_restrictions_from_pg_test_su_user; -go -SET enable_drop_babelfish_role = false; -go - DROP USER ownership_restrictions_from_pg_test_user; GO diff --git a/test/JDBC/input/ownership_restrictions_from_pg_su_user.mix b/test/JDBC/input/ownership_restrictions_from_pg_su_user.mix new file mode 100644 index 0000000000..ff44d0719b --- /dev/null +++ b/test/JDBC/input/ownership_restrictions_from_pg_su_user.mix @@ -0,0 +1,89 @@ +-- tsql +CREATE LOGIN ownership_restrictions_from_pg_login1 WITH password = '12345678'; +GO + +CREATE ROLE ownership_restrictions_from_pg_role1; +GO + +DECLARE @ownership_restrictions_from_pg_test_variable int = 100; +GO + +-- psql +CREATE USER ownership_restrictions_from_pg_test_user WITH PASSWORD '12345678' inherit; +go + +CREATE USER ownership_restrictions_from_pg_test_su_user WITH SUPERUSER LOGIN PASSWORD '12345678'; +GO + +-- psql user=ownership_restrictions_from_pg_login1 password=12345678 +-- If tsql login connected through psql Alter ROLE of an bbf created logins/user/roles for password, +-- connection limit and valid until should be working fine +-- and the rest of alter role operations should throw an error. +ALTER ROLE ALL IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE CURRENT_ROLE IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE CURRENT_USER IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE SESSION_USER IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE ownership_restrictions_from_pg_login1 IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +-- psql user=ownership_restrictions_from_pg_test_user password=12345678 +-- For plain psql user Alter ROLE of an bbf created logins/user/roles for password, +-- connection limit and valid until should be working fine +-- and the rest of alter role operations should throw an error. +ALTER ROLE ALL IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE CURRENT_ROLE IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE CURRENT_USER IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE SESSION_USER IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +ALTER ROLE ownership_restrictions_from_pg_login1 IN DATABASE jdbc_testdb set babelfishpg_tsql.ownership_restrictions_from_pg_test_variable = 101; +GO + +-- psql user=ownership_restrictions_from_pg_test_su_user password=12345678 +-- Altering of babelfish created logins/roles should suceeded for superuser +ALTER ROLE ownership_restrictions_from_pg_login1 VALID UNTIL 'infinity'; +GO + +ALTER ROLE master_ownership_restrictions_from_pg_role1 WITH NOCREATEDB CONNECTION LIMIT 1 password '12345678'; +GO + +-- psql +SET enable_drop_babelfish_role = true; +go +DROP USER ownership_restrictions_from_pg_test_su_user; +go +SET enable_drop_babelfish_role = false; +go + +DROP USER ownership_restrictions_from_pg_test_user; +GO + +-- Need to terminate active session before cleaning up the login +SELECT pg_terminate_backend(pid) FROM pg_stat_get_activity(NULL) +WHERE sys.suser_name(usesysid) = 'ownership_restrictions_from_pg_login1' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +GO + +-- tsql +DROP ROLE ownership_restrictions_from_pg_role1; +DROP LOGIN ownership_restrictions_from_pg_login1; +GO From 7299f000a8d50f3d3512177ad753ed9f701e6653 Mon Sep 17 00:00:00 2001 From: Zhibai Date: Tue, 25 Apr 2023 17:28:58 -0700 Subject: [PATCH 073/363] support '[' and ']' wildcharacter for Like operater (#1459) Previously Babelfish didn't support '[' and ']' for like operator. This commit support this feature by changing the like execution. Add support to deal with '[' and ']' when it appears in pattern. Signed-off-by: Zhibai Song Task: BABEL-3198 --- .../expected/BABEL-SP_COLUMN_PRIVILEGES.out | 21 +- .../BABEL-SP_STORED_PROCEDURES-vu-verify.out | 5 + .../expected/BABEL-SP_STORED_PROCEDURES.out | 5 + .../expected/BABEL-SP_TABLE_PRIVILEGES.out | 20 ++ .../BABEL-SP_TABLE_PRIVILIGES-vu-verify.out | 20 ++ test/JDBC/expected/like_expression.out | 259 ++++++++++++++++++ .../JDBC/input/BABEL-SP_COLUMN_PRIVILEGES.mix | 1 - test/JDBC/input/like_expression.sql | 89 ++++++ 8 files changed, 418 insertions(+), 2 deletions(-) create mode 100644 test/JDBC/expected/like_expression.out create mode 100644 test/JDBC/input/like_expression.sql diff --git a/test/JDBC/expected/BABEL-SP_COLUMN_PRIVILEGES.out b/test/JDBC/expected/BABEL-SP_COLUMN_PRIVILEGES.out index 9a423f7f41..2f70a831c4 100644 --- a/test/JDBC/expected/BABEL-SP_COLUMN_PRIVILEGES.out +++ b/test/JDBC/expected/BABEL-SP_COLUMN_PRIVILEGES.out @@ -263,11 +263,18 @@ db1#!#dbo#!#t4#!#testcolumn#!#dbo#!#dbo#!#UPDATE#!#YES ~~END~~ --- NOTE: Incorrect output with [] wildcards, see BABEL-2452 EXEC sp_column_privileges @table_name = 't4', @table_owner = 'dbo', @COLUMN_NAME='t[ea]stcolumn' GO ~~START~~ varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +db1#!#dbo#!#t4#!#tastcolumn#!#dbo#!#dbo#!#INSERT#!#YES +db1#!#dbo#!#t4#!#tastcolumn#!#dbo#!#dbo#!#REFERENCES#!#YES +db1#!#dbo#!#t4#!#tastcolumn#!#dbo#!#dbo#!#SELECT#!#YES +db1#!#dbo#!#t4#!#tastcolumn#!#dbo#!#dbo#!#UPDATE#!#YES +db1#!#dbo#!#t4#!#testcolumn#!#dbo#!#dbo#!#INSERT#!#YES +db1#!#dbo#!#t4#!#testcolumn#!#dbo#!#dbo#!#REFERENCES#!#YES +db1#!#dbo#!#t4#!#testcolumn#!#dbo#!#dbo#!#SELECT#!#YES +db1#!#dbo#!#t4#!#testcolumn#!#dbo#!#dbo#!#UPDATE#!#YES ~~END~~ @@ -275,6 +282,10 @@ EXEC sp_column_privileges @table_name = 't4', @table_owner = 'dbo', @COLUMN_NAME GO ~~START~~ varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +db1#!#dbo#!#t4#!#tastcolumn#!#dbo#!#dbo#!#INSERT#!#YES +db1#!#dbo#!#t4#!#tastcolumn#!#dbo#!#dbo#!#REFERENCES#!#YES +db1#!#dbo#!#t4#!#tastcolumn#!#dbo#!#dbo#!#SELECT#!#YES +db1#!#dbo#!#t4#!#tastcolumn#!#dbo#!#dbo#!#UPDATE#!#YES ~~END~~ @@ -282,6 +293,14 @@ EXEC sp_column_privileges @table_name = 't4', @table_owner = 'dbo', @COLUMN_NAME GO ~~START~~ varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +db1#!#dbo#!#t4#!#tastcolumn#!#dbo#!#dbo#!#INSERT#!#YES +db1#!#dbo#!#t4#!#tastcolumn#!#dbo#!#dbo#!#REFERENCES#!#YES +db1#!#dbo#!#t4#!#tastcolumn#!#dbo#!#dbo#!#SELECT#!#YES +db1#!#dbo#!#t4#!#tastcolumn#!#dbo#!#dbo#!#UPDATE#!#YES +db1#!#dbo#!#t4#!#testcolumn#!#dbo#!#dbo#!#INSERT#!#YES +db1#!#dbo#!#t4#!#testcolumn#!#dbo#!#dbo#!#REFERENCES#!#YES +db1#!#dbo#!#t4#!#testcolumn#!#dbo#!#dbo#!#SELECT#!#YES +db1#!#dbo#!#t4#!#testcolumn#!#dbo#!#dbo#!#UPDATE#!#YES ~~END~~ diff --git a/test/JDBC/expected/BABEL-SP_STORED_PROCEDURES-vu-verify.out b/test/JDBC/expected/BABEL-SP_STORED_PROCEDURES-vu-verify.out index ed343831aa..5e9a4e2c12 100644 --- a/test/JDBC/expected/BABEL-SP_STORED_PROCEDURES-vu-verify.out +++ b/test/JDBC/expected/BABEL-SP_STORED_PROCEDURES-vu-verify.out @@ -125,6 +125,8 @@ EXEC sp_stored_procedures @sp_name='babel_sp_stored_procedures_vu_prepare_sel[eu GO ~~START~~ varchar#!#varchar#!#nvarchar#!#int#!#int#!#int#!#varchar#!#smallint +babel_sp_stored_procedures_vu_prepare_db1#!#dbo#!#babel_sp_stored_procedures_vu_prepare_select_all;1#!#-1#!#-1#!#-1#!##!#2 +babel_sp_stored_procedures_vu_prepare_db1#!#dbo#!#babel_sp_stored_procedures_vu_prepare_seluct_all;1#!#-1#!#-1#!#-1#!##!#2 ~~END~~ @@ -132,6 +134,7 @@ EXEC sp_stored_procedures @sp_name='babel_sp_stored_procedures_vu_prepare_sel[^u GO ~~START~~ varchar#!#varchar#!#nvarchar#!#int#!#int#!#int#!#varchar#!#smallint +babel_sp_stored_procedures_vu_prepare_db1#!#dbo#!#babel_sp_stored_procedures_vu_prepare_select_all;1#!#-1#!#-1#!#-1#!##!#2 ~~END~~ @@ -139,5 +142,7 @@ EXEC sp_stored_procedures @sp_name='babel_sp_stored_procedures_vu_prepare_sel[a- GO ~~START~~ varchar#!#varchar#!#nvarchar#!#int#!#int#!#int#!#varchar#!#smallint +babel_sp_stored_procedures_vu_prepare_db1#!#dbo#!#babel_sp_stored_procedures_vu_prepare_select_all;1#!#-1#!#-1#!#-1#!##!#2 +babel_sp_stored_procedures_vu_prepare_db1#!#dbo#!#babel_sp_stored_procedures_vu_prepare_seluct_all;1#!#-1#!#-1#!#-1#!##!#2 ~~END~~ diff --git a/test/JDBC/expected/BABEL-SP_STORED_PROCEDURES.out b/test/JDBC/expected/BABEL-SP_STORED_PROCEDURES.out index 92924dff54..48d22efb8c 100644 --- a/test/JDBC/expected/BABEL-SP_STORED_PROCEDURES.out +++ b/test/JDBC/expected/BABEL-SP_STORED_PROCEDURES.out @@ -176,6 +176,8 @@ EXEC sp_stored_procedures @sp_name='sel[eu]ct_all' GO ~~START~~ varchar#!#varchar#!#nvarchar#!#int#!#int#!#int#!#varchar#!#smallint +db1#!#dbo#!#select_all;1#!#-1#!#-1#!#-1#!##!#2 +db1#!#dbo#!#seluct_all;1#!#-1#!#-1#!#-1#!##!#2 ~~END~~ @@ -183,6 +185,7 @@ EXEC sp_stored_procedures @sp_name='sel[^u]ct_all' GO ~~START~~ varchar#!#varchar#!#nvarchar#!#int#!#int#!#int#!#varchar#!#smallint +db1#!#dbo#!#select_all;1#!#-1#!#-1#!#-1#!##!#2 ~~END~~ @@ -190,6 +193,8 @@ EXEC sp_stored_procedures @sp_name='sel[a-u]ct_all' GO ~~START~~ varchar#!#varchar#!#nvarchar#!#int#!#int#!#int#!#varchar#!#smallint +db1#!#dbo#!#select_all;1#!#-1#!#-1#!#-1#!##!#2 +db1#!#dbo#!#seluct_all;1#!#-1#!#-1#!#-1#!##!#2 ~~END~~ diff --git a/test/JDBC/expected/BABEL-SP_TABLE_PRIVILEGES.out b/test/JDBC/expected/BABEL-SP_TABLE_PRIVILEGES.out index f06b1e417f..1a26363d0a 100644 --- a/test/JDBC/expected/BABEL-SP_TABLE_PRIVILEGES.out +++ b/test/JDBC/expected/BABEL-SP_TABLE_PRIVILEGES.out @@ -243,6 +243,16 @@ exec sp_table_privileges @table_name = 'fo[ol]bar1' go ~~START~~ varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +db1#!#dbo#!#folbar1#!#dbo#!#dbo#!#DELETE#!#YES +db1#!#dbo#!#folbar1#!#dbo#!#dbo#!#INSERT#!#YES +db1#!#dbo#!#folbar1#!#dbo#!#dbo#!#REFERENCES#!#YES +db1#!#dbo#!#folbar1#!#dbo#!#dbo#!#SELECT#!#YES +db1#!#dbo#!#folbar1#!#dbo#!#dbo#!#UPDATE#!#YES +db1#!#dbo#!#foobar1#!#dbo#!#dbo#!#DELETE#!#YES +db1#!#dbo#!#foobar1#!#dbo#!#dbo#!#INSERT#!#YES +db1#!#dbo#!#foobar1#!#dbo#!#dbo#!#REFERENCES#!#YES +db1#!#dbo#!#foobar1#!#dbo#!#dbo#!#SELECT#!#YES +db1#!#dbo#!#foobar1#!#dbo#!#dbo#!#UPDATE#!#YES ~~END~~ @@ -250,6 +260,11 @@ exec sp_table_privileges @table_name = 'fo[^o]bar1' go ~~START~~ varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +db1#!#dbo#!#folbar1#!#dbo#!#dbo#!#DELETE#!#YES +db1#!#dbo#!#folbar1#!#dbo#!#dbo#!#INSERT#!#YES +db1#!#dbo#!#folbar1#!#dbo#!#dbo#!#REFERENCES#!#YES +db1#!#dbo#!#folbar1#!#dbo#!#dbo#!#SELECT#!#YES +db1#!#dbo#!#folbar1#!#dbo#!#dbo#!#UPDATE#!#YES ~~END~~ @@ -257,6 +272,11 @@ exec sp_table_privileges @table_name = 'fo[a-l]bar1' go ~~START~~ varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +db1#!#dbo#!#folbar1#!#dbo#!#dbo#!#DELETE#!#YES +db1#!#dbo#!#folbar1#!#dbo#!#dbo#!#INSERT#!#YES +db1#!#dbo#!#folbar1#!#dbo#!#dbo#!#REFERENCES#!#YES +db1#!#dbo#!#folbar1#!#dbo#!#dbo#!#SELECT#!#YES +db1#!#dbo#!#folbar1#!#dbo#!#dbo#!#UPDATE#!#YES ~~END~~ diff --git a/test/JDBC/expected/BABEL-SP_TABLE_PRIVILIGES-vu-verify.out b/test/JDBC/expected/BABEL-SP_TABLE_PRIVILIGES-vu-verify.out index f037c28acf..f435d07d15 100644 --- a/test/JDBC/expected/BABEL-SP_TABLE_PRIVILIGES-vu-verify.out +++ b/test/JDBC/expected/BABEL-SP_TABLE_PRIVILIGES-vu-verify.out @@ -223,6 +223,16 @@ exec sp_table_privileges @table_name = 'babel_sp_table_priviliges_vu_prepare_fo[ go ~~START~~ varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_folbar1#!#dbo#!#dbo#!#DELETE#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_folbar1#!#dbo#!#dbo#!#INSERT#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_folbar1#!#dbo#!#dbo#!#REFERENCES#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_folbar1#!#dbo#!#dbo#!#SELECT#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_folbar1#!#dbo#!#dbo#!#UPDATE#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_foobar1#!#dbo#!#dbo#!#DELETE#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_foobar1#!#dbo#!#dbo#!#INSERT#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_foobar1#!#dbo#!#dbo#!#REFERENCES#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_foobar1#!#dbo#!#dbo#!#SELECT#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_foobar1#!#dbo#!#dbo#!#UPDATE#!#YES ~~END~~ @@ -230,6 +240,11 @@ exec sp_table_privileges @table_name = 'babel_sp_table_priviliges_vu_prepare_fo[ go ~~START~~ varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_folbar1#!#dbo#!#dbo#!#DELETE#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_folbar1#!#dbo#!#dbo#!#INSERT#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_folbar1#!#dbo#!#dbo#!#REFERENCES#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_folbar1#!#dbo#!#dbo#!#SELECT#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_folbar1#!#dbo#!#dbo#!#UPDATE#!#YES ~~END~~ @@ -237,6 +252,11 @@ exec sp_table_privileges @table_name = 'babel_sp_table_priviliges_vu_prepare_fo[ go ~~START~~ varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_folbar1#!#dbo#!#dbo#!#DELETE#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_folbar1#!#dbo#!#dbo#!#INSERT#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_folbar1#!#dbo#!#dbo#!#REFERENCES#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_folbar1#!#dbo#!#dbo#!#SELECT#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_folbar1#!#dbo#!#dbo#!#UPDATE#!#YES ~~END~~ diff --git a/test/JDBC/expected/like_expression.out b/test/JDBC/expected/like_expression.out new file mode 100644 index 0000000000..e805ec698c --- /dev/null +++ b/test/JDBC/expected/like_expression.out @@ -0,0 +1,259 @@ +create table t ( a varchar(30)) +GO + +insert into t values ('abc'),('bbc'),('cbc'),('=bc'),('Abc'),('a[bc'),('a]bc'); +GO +~~ROW COUNT: 7~~ + + +select * from t where a like '[c-a]bc' +GO +~~START~~ +varchar +cbc +~~END~~ + + +select * from t where a like '[<->]bc' +GO +~~START~~ +varchar +=bc +~~END~~ + + +select * from t where a like '[0-a]bc'; +GO +~~START~~ +varchar +abc +=bc +Abc +~~END~~ + + +select * from t where a like '[abc]bc'; +GO +~~START~~ +varchar +abc +bbc +cbc +Abc +~~END~~ + + +select * from t where a like '[a-c]bc'; +GO +~~START~~ +varchar +abc +bbc +cbc +Abc +~~END~~ + + +select * from t where a like '[abc]_c'; +GO +~~START~~ +varchar +abc +bbc +cbc +Abc +~~END~~ + + +select * from t where a like '[a]%c'; +GO +~~START~~ +varchar +abc +Abc +a[bc +a]bc +~~END~~ + + +select * from t where a like '%[abc]c'; +GO +~~START~~ +varchar +abc +bbc +cbc +=bc +Abc +a[bc +a]bc +~~END~~ + + +select * from t where a like '[%]bc'; +GO +~~START~~ +varchar +~~END~~ + + +select * from t where a like '[_]bc'; +GO +~~START~~ +varchar +~~END~~ + + +select * from t where a like 'a[bc]c'; +GO +~~START~~ +varchar +abc +Abc +~~END~~ + + +select * from t where a like '[a-z][a-z]c'; +GO +~~START~~ +varchar +abc +bbc +cbc +Abc +~~END~~ + + +select * from t where a like '[^ a][a-z]c'; +GO +~~START~~ +varchar +bbc +cbc +=bc +~~END~~ + + +select * from t where a like '[^ a-b][a-z]c'; +GO +~~START~~ +varchar +cbc +=bc +~~END~~ + + +select * from t where a like '%bc'; +GO +~~START~~ +varchar +abc +bbc +cbc +=bc +Abc +a[bc +a]bc +~~END~~ + + +select * from t where a like '[0-9a-f][0-9a-f][0-9a-f]'; +GO +~~START~~ +varchar +abc +bbc +cbc +Abc +~~END~~ + + +insert into t values (']bc') +GO +~~ROW COUNT: 1~~ + + +insert into t values ('[bc') +GO +~~ROW COUNT: 1~~ + + +select * from t where a like ('[]]bc'); +GO +~~START~~ +varchar +~~END~~ + + +select * from t where a like ('[[]bc'); +GO +~~START~~ +varchar +[bc +~~END~~ + + +select * from t where a like ']bc'; +GO +~~START~~ +varchar +]bc +~~END~~ + + +insert into t values ('11.22'); +GO +~~ROW COUNT: 1~~ + + +select * from t where a like '[0-9][0-9].[0-9][0-9]' +GO +~~START~~ +varchar +11.22 +~~END~~ + + +create table t2 ( b varchar(30) collate BBF_Unicode_General_CS_AS) +GO + +insert into t2 values ('[abc]bc'),('[abc]_c'),('[]]bc'),('[[]bc'),('%[abc]c'),('[^ a-b][a-z]c'),('[0-9][0-9].[0-9][0-9]'),('[<->]bc') +GO +~~ROW COUNT: 8~~ + + +select * from t2 join t on a like b; +GO +~~START~~ +varchar#!#varchar +[abc]bc#!#abc +[abc]bc#!#bbc +[abc]bc#!#cbc +[abc]_c#!#abc +[abc]_c#!#bbc +[abc]_c#!#cbc +[[]bc#!#[bc +%[abc]c#!#abc +%[abc]c#!#bbc +%[abc]c#!#cbc +%[abc]c#!#=bc +%[abc]c#!#Abc +%[abc]c#!#a[bc +%[abc]c#!#a]bc +%[abc]c#!#]bc +%[abc]c#!#[bc +[^ a-b][a-z]c#!#cbc +[^ a-b][a-z]c#!#=bc +[^ a-b][a-z]c#!#Abc +[^ a-b][a-z]c#!#]bc +[^ a-b][a-z]c#!#[bc +[0-9][0-9].[0-9][0-9]#!#11.22 +[<->]bc#!#=bc +~~END~~ + + +drop table t2; +GO + +drop table t; +GO diff --git a/test/JDBC/input/BABEL-SP_COLUMN_PRIVILEGES.mix b/test/JDBC/input/BABEL-SP_COLUMN_PRIVILEGES.mix index 4e7cea4d45..871a588e3f 100644 --- a/test/JDBC/input/BABEL-SP_COLUMN_PRIVILEGES.mix +++ b/test/JDBC/input/BABEL-SP_COLUMN_PRIVILEGES.mix @@ -108,7 +108,6 @@ GO EXEC sp_column_privileges @table_name = 't4', @table_owner = 'dbo', @COLUMN_NAME='t_stcolumn' GO --- NOTE: Incorrect output with [] wildcards, see BABEL-2452 EXEC sp_column_privileges @table_name = 't4', @table_owner = 'dbo', @COLUMN_NAME='t[ea]stcolumn' GO diff --git a/test/JDBC/input/like_expression.sql b/test/JDBC/input/like_expression.sql new file mode 100644 index 0000000000..1a18a0fbfd --- /dev/null +++ b/test/JDBC/input/like_expression.sql @@ -0,0 +1,89 @@ +create table t ( a varchar(30)) +GO + +insert into t values ('abc'),('bbc'),('cbc'),('=bc'),('Abc'),('a[bc'),('a]bc'); +GO + +select * from t where a like '[c-a]bc' +GO + +select * from t where a like '[<->]bc' +GO + +select * from t where a like '[0-a]bc'; +GO + +select * from t where a like '[abc]bc'; +GO + +select * from t where a like '[a-c]bc'; +GO + +select * from t where a like '[abc]_c'; +GO + +select * from t where a like '[a]%c'; +GO + +select * from t where a like '%[abc]c'; +GO + +select * from t where a like '[%]bc'; +GO + +select * from t where a like '[_]bc'; +GO + +select * from t where a like 'a[bc]c'; +GO + +select * from t where a like '[a-z][a-z]c'; +GO + +select * from t where a like '[^ a][a-z]c'; +GO + +select * from t where a like '[^ a-b][a-z]c'; +GO + +select * from t where a like '%bc'; +GO + +select * from t where a like '[0-9a-f][0-9a-f][0-9a-f]'; +GO + +insert into t values (']bc') +GO + +insert into t values ('[bc') +GO + +select * from t where a like ('[]]bc'); +GO + +select * from t where a like ('[[]bc'); +GO + +select * from t where a like ']bc'; +GO + +insert into t values ('11.22'); +GO + +select * from t where a like '[0-9][0-9].[0-9][0-9]' +GO + +create table t2 ( b varchar(30) collate BBF_Unicode_General_CS_AS) +GO + +insert into t2 values ('[abc]bc'),('[abc]_c'),('[]]bc'),('[[]bc'),('%[abc]c'),('[^ a-b][a-z]c'),('[0-9][0-9].[0-9][0-9]'),('[<->]bc') +GO + +select * from t2 join t on a like b; +GO + +drop table t2; +GO + +drop table t; +GO \ No newline at end of file From 70c00df3362e1d62504be86de62514db42d758e6 Mon Sep 17 00:00:00 2001 From: Sharu Goel <30777678+thephantomthief@users.noreply.github.com> Date: Wed, 26 Apr 2023 11:20:58 +0530 Subject: [PATCH 074/363] Rework logic of TDS SSL Pre-login Handshake (#1453) This commit rewrites the logic of SSL prelogin handshake read. Previously, whatever segments we were reading from the SSL prelogin handshake packet, if the first byte started with TDS_PRELOGIN, then we assumed that the segment is actually the first segment of the SSL handshake packet from the client containing the TDS prelogin header. This assumption is incorrect. It is possible that the segment being read by the SSL Handshake read method might not contain the TDS prelogin header but still has its first byte as TDS_PRELOGIN. There is no restriction on this for the encrypted handshake message. We rewrite this logic to check for the TDS prelogin header only if we have fully read the entire previous SSL handshake packet from client or if this is actually the very first SSL packet from client (client hello). Task: BABEL-4096 Signed-off-by: Sharu Goel goelshar@amazon.com --- .../src/backend/tds/tdssecure.c | 128 +++++++++++------- 1 file changed, 78 insertions(+), 50 deletions(-) diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdssecure.c b/contrib/babelfishpg_tds/src/backend/tds/tdssecure.c index 72f9371d62..6b3c0307f8 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tdssecure.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tdssecure.c @@ -41,6 +41,26 @@ int tds_ssl_min_protocol_version; int tds_ssl_max_protocol_version; #ifdef USE_SSL + +/* + * The SSL packets is packed in a TDS prelogin packet. The following + * structure is used to store the TDS prelogin header. It's not safe + * to access inidividual union members until we read the entire header + * in the buf. + */ +typedef union TDSPacketHeader { + struct header { + uint8_t pkt_type; + uint8_t status; + uint16_t length; + } header; + char buf[TDS_PACKET_HEADER_SIZE]; +} TDSPacketHeader; + +/* tracks how much packet data we've read */ +static int pkt_bytes_read = 0; +static TDSPacketHeader pkt_data = {0}; + /* * SslRead - TDS secure read function, similar to my_sock_read */ @@ -69,72 +89,77 @@ SslRead(BIO * h, char *buf, int size) /* * my_tds_sock_read - TDS secure read function, similar to my_sock_read * During the initial handshake, strip off the inital 8 bytes header, when - * filling in the data in buf called from openssl library + * filling in the data in buf called from openssl library. + * + * The function can handle the scenario if it returns while reading the + * header. In that case, it resumes reading the header from where it left. */ + static int SslHandShakeRead(BIO * h, char *buf, int size) { - int res = 0; + int res = 0; - if ((res = SslRead(h, buf, size)) <= 0) - return res; - - /* very first packet of prelogin SSL handshake */ - if (size > 0 && res > 0 && buf[0] == TDS_PRELOGIN) + /* + * Read the TDS header if not read. It's possible that we're reading + * the header in multiple iteration. + */ + if (pkt_bytes_read < TDS_PACKET_HEADER_SIZE) { + /* only read the bytes left in header */ + int header_left = TDS_PACKET_HEADER_SIZE - pkt_bytes_read; - if (res < TDS_PACKET_HEADER_SIZE) + /* read untill we get the header at least */ + while (header_left > 0) { - int remainingRead = TDS_PACKET_HEADER_SIZE - res; - char tempBuf[TDS_PACKET_HEADER_SIZE]; - - res = 0; + char *cur_loc; - /* - * Read the complete remaining of the header and throw away the - * bytes - */ - while (res < remainingRead) - { - int tmp_res = 0; + if ((res = SslRead(h, buf, header_left)) <= 0) + return res; - if ((tmp_res = SslRead(h, tempBuf, remainingRead - res)) <= 0) - { - return tmp_res; - } - res += tmp_res; - } + /* copy the header data read */ + cur_loc = &(pkt_data.buf[pkt_bytes_read]); + memcpy(cur_loc, buf, res); + pkt_bytes_read += res; - /* - * Read the actual data and return the res of the actual data read - * Don't worry if complete read, Openssl library will take care - */ - if ((res = SslRead(h, buf, size)) <= 0) - return res; + header_left -= res; } - else - { - int tmp_res = 0; - int i = TDS_PACKET_HEADER_SIZE; - for (i = TDS_PACKET_HEADER_SIZE; i < res; i++) - { - buf[i - TDS_PACKET_HEADER_SIZE] = buf[i]; - } - res -= TDS_PACKET_HEADER_SIZE; + if (unlikely(pkt_data.header.pkt_type != TDS_PRELOGIN)) + ereport(FATAL, + (errcode(ERRCODE_ADMIN_SHUTDOWN), + errmsg("terminating connection due to unexpected ssl packet header"))); + + /* endian conversion is required for length */ + pkt_data.header.length = pg_bswap16(pkt_data.header.length); - /* - * Read remaining of the data. Even if the read is less than - * requested size due to whatever reasons, we are good, since we - * are returning the correct res value, so caller will take care - * of reading the remaining data - */ - if ((tmp_res = SslRead(h, &buf[res], TDS_PACKET_HEADER_SIZE)) <= 0) - return tmp_res; - res += tmp_res; - } } + /* At this point, we must have read the TDS header */ + Assert(pkt_bytes_read >= TDS_PACKET_HEADER_SIZE); + + /* + * If SSL packet expands the current TDS prelogin packet, we need to + * read some data in next iteration. For now, just read till end of the + * packet. The caller will try to read the remaining data in the next + * iteration. + * XXX: We've not really seen this scenario. + */ + if (pkt_bytes_read + size > pkt_data.header.length) + { + TDS_DEBUG(TDS_DEBUG1, "SSL packet expand more than one TDS packet"); + size = pkt_data.header.length - pkt_bytes_read; + } + + if ((res = SslRead(h, buf, size)) <= 0) + return res; + + pkt_bytes_read += res; + + /* if we're done reading the packet, reset packet data state */ + if (pkt_bytes_read == pkt_data.header.length) + pkt_bytes_read = 0; + return res; } @@ -228,6 +253,9 @@ SslHandShakeWrite(BIO * h, const char *buf, int size) BIO_METHOD * TdsBioSecureSocket(BIO_METHOD * my_bio_methods) { + /* reset the tds packet data state*/ + pkt_bytes_read = 0; + if (my_bio_methods == NULL) { BIO_METHOD *biom = (BIO_METHOD *) BIO_s_socket(); From 56b0e40ce176387217ed4e3dda044d2f88f2ee61 Mon Sep 17 00:00:00 2001 From: Satarupa Biswas Date: Wed, 26 Apr 2023 12:54:09 +0530 Subject: [PATCH 075/363] Adding explicit numeic casting to sys.sp_databases_view (#1464) Error found in GitFarm while upgrading babelfishpg_tsql extension Investigation Looks like Numeric/BigInt CAST actually exists, the same statement runs successfully when sys schema is not in the path: babelfish_db=# show search_path; search_path pg_catalog, public (1 row) babelfish_db=# select pg_relation_size('sys.babelfish_namespace_ext')/1024.0; ?column? 8.0000000000000000 (1 row) But fails if we add sys in the path. Solution Following the error hint (as below) resolves the issue, so adding explicit NUMERIC casting to sys.sp_databases_view: select pg_relation_size('sys.babelfish_namespace_ext')::numeric/1024.0; Co-authored-by: Satarupa Biswas --- contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql | 4 ++-- .../sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql index adca986fef..59bc52385d 100644 --- a/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql +++ b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql @@ -1081,8 +1081,8 @@ DROP VIEW IF EXISTS sys.sp_databases_view CASCADE; CREATE VIEW sys.sp_databases_view AS SELECT CAST(database_name AS sys.SYSNAME), -- DATABASE_SIZE returns a NULL value for databases larger than 2.15 TB - CASE WHEN (sum(table_size)/1024.0) > 2.15 * 1024.0 * 1024.0 * 1024.0 THEN NULL - ELSE CAST((sum(table_size)/1024.0) AS int) END as database_size, + CASE WHEN (sum(table_size)::NUMERIC/1024.0) > 2.15 * 1024.0 * 1024.0 * 1024.0 THEN NULL + ELSE CAST((sum(table_size)::NUMERIC/1024.0) AS int) END as database_size, CAST(NULL AS sys.VARCHAR(254)) as remarks FROM ( SELECT pg_catalog.pg_namespace.oid as schema_oid, diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql index c3ef5921da..9f065b612e 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql @@ -1489,8 +1489,8 @@ CREATE OR REPLACE VIEW sys.spt_tablecollations_view AS CREATE OR REPLACE VIEW sys.sp_databases_view AS SELECT CAST(database_name AS sys.SYSNAME), -- DATABASE_SIZE returns a NULL value for databases larger than 2.15 TB - CASE WHEN (sum(table_size)/1024.0) > 2.15 * 1024.0 * 1024.0 * 1024.0 THEN NULL - ELSE CAST((sum(table_size)/1024.0) AS int) END as database_size, + CASE WHEN (sum(table_size)::NUMERIC/1024.0) > 2.15 * 1024.0 * 1024.0 * 1024.0 THEN NULL + ELSE CAST((sum(table_size)::NUMERIC/1024.0) AS int) END as database_size, CAST(NULL AS sys.VARCHAR(254)) as remarks FROM ( SELECT pg_catalog.pg_namespace.oid as schema_oid, From b934264f9e00667111b833130a7f15a18a46a4c5 Mon Sep 17 00:00:00 2001 From: Ashish Prasad <56514722+hash-16@users.noreply.github.com> Date: Wed, 26 Apr 2023 17:07:07 +0530 Subject: [PATCH 076/363] BABEL-3834 :- Support SSMS scripting for User defined datatypes (#1426) Implemented the typeproperty to support user defined datatypes. The Typeproperty function returns information based on data type from the current object . It supports 2 parameters, an TYPE (string expression) and PROPERTY (string expression). The function returns an int and the values depend on the PROPERTY parameter. Supported Property:- Owner ID AllowsNull Precision Scale Issues Resolved BABEL-3834 , 802 Signed-off-by: Ashish Prasad pashisht@amazon.com --- .../babelfishpg_tsql/sql/sys_functions.sql | 95 ++++++ .../babelfishpg_tsql--3.1.0--3.2.0.sql | 95 ++++++ .../expected/typeproperty-dep-vu-cleanup.out | 14 + .../expected/typeproperty-dep-vu-prepare.out | 21 ++ .../expected/typeproperty-dep-vu-verify.out | 23 ++ .../JDBC/expected/typeproperty-vu-cleanup.out | 17 + .../JDBC/expected/typeproperty-vu-prepare.out | 17 + test/JDBC/expected/typeproperty-vu-verify.out | 318 ++++++++++++++++++ .../functions/typeproperty-dep-vu-cleanup.sql | 14 + .../functions/typeproperty-dep-vu-prepare.sql | 21 ++ .../functions/typeproperty-dep-vu-verify.sql | 8 + .../functions/typeproperty-vu-cleanup.sql | 17 + .../functions/typeproperty-vu-prepare.sql | 17 + .../functions/typeproperty-vu-verify.sql | 148 ++++++++ test/JDBC/upgrade/15_2/schedule | 1 + test/JDBC/upgrade/latest/schedule | 2 + 16 files changed, 828 insertions(+) create mode 100644 test/JDBC/expected/typeproperty-dep-vu-cleanup.out create mode 100644 test/JDBC/expected/typeproperty-dep-vu-prepare.out create mode 100644 test/JDBC/expected/typeproperty-dep-vu-verify.out create mode 100644 test/JDBC/expected/typeproperty-vu-cleanup.out create mode 100644 test/JDBC/expected/typeproperty-vu-prepare.out create mode 100644 test/JDBC/expected/typeproperty-vu-verify.out create mode 100644 test/JDBC/input/functions/typeproperty-dep-vu-cleanup.sql create mode 100644 test/JDBC/input/functions/typeproperty-dep-vu-prepare.sql create mode 100644 test/JDBC/input/functions/typeproperty-dep-vu-verify.sql create mode 100644 test/JDBC/input/functions/typeproperty-vu-cleanup.sql create mode 100644 test/JDBC/input/functions/typeproperty-vu-prepare.sql create mode 100644 test/JDBC/input/functions/typeproperty-vu-verify.sql diff --git a/contrib/babelfishpg_tsql/sql/sys_functions.sql b/contrib/babelfishpg_tsql/sql/sys_functions.sql index 48977065f6..b7728b32a7 100644 --- a/contrib/babelfishpg_tsql/sql/sys_functions.sql +++ b/contrib/babelfishpg_tsql/sql/sys_functions.sql @@ -3382,6 +3382,101 @@ END; $$ LANGUAGE plpgsql STABLE; +CREATE OR REPLACE FUNCTION typeproperty( + typename sys.VARCHAR, + property sys.VARCHAR + ) +RETURNS INT +AS $$ +DECLARE + var_sc int; + schemaid int; + schema_name VARCHAR; + type_name VARCHAR; + sys_id int; + testt VARCHAR; +BEGIN + + property := TRIM(LOWER(COALESCE(property,''))); + + IF typename LIKE '%.%' THEN + schema_name := lower(split_part(typename COLLATE "C", '.', 1)); + type_name := lower(split_part(typename COLLATE "C",'.', 2)); + ELSE + schema_name := 'dbo'; + type_name := typename; + END IF; + + + IF NOT EXISTS (SELECT ao.name FROM sys.types ao WHERE ao.name = type_name COLLATE sys.database_default) + THEN + RETURN NULL; + END IF; + + IF NOT EXISTS (SELECT ao.name FROM sys.schemas ao WHERE ao.name = schema_name COLLATE sys.database_default OR schema_name = 'sys' OR schema_name = 'pg_catalog') + THEN + RETURN NULL ; + END IF; + + IF NOT EXISTS (SELECT ty.is_user_defined FROM sys.types ty WHERE ty.name = type_name COLLATE sys.database_default AND ty.is_user_defined = 0) THEN + schemaid := (SELECT sc.schema_id FROM sys.schemas sc WHERE sc.name = schema_name COLLATE sys.database_default); + ELSE + schemaid := (SELECT sc.schema_id FROM sys.types sc WHERE sc.name = type_name COLLATE sys.database_default); + END IF; + + + if (SELECT schema_id(schema_name)) <> schemaid THEN + RETURN NULL; + END IF; + + IF property = 'allowsnull' + THEN + RETURN ( + SELECT CAST( t1.is_nullable AS INT) + FROM sys.types t1 + WHERE t1.name = type_name COLLATE sys.database_default AND t1.schema_id = schemaid ); + + ELSEIF property = 'precision' + THEN + RETURN (SELECT CAST(dc.precision AS INT) FROM sys.types dc WHERE dc.name = type_name COLLATE sys.database_default AND dc.schema_id = schemaid); + + ELSEIF property = 'scale' + THEN + sys_id := (SELECT CAST(dc.system_type_id AS INT) FROM sys.types dc WHERE dc.name = type_name COLLATE sys.database_default AND dc.schema_id = schemaid); + type_name := (SELECT CAST(dc.name AS VARCHAR) FROM sys.types dc WHERE dc.system_type_id = sys_id AND dc.is_user_defined = 0); + IF type_name::regtype IN ('bigint'::regtype, 'int'::regtype, 'smallint'::regtype,'tinyint'::regtype, + 'numeric'::regtype, 'float'::regtype, 'real'::regtype, 'money'::regtype) + THEN + RETURN(SELECT CAST(dc.scale AS INT) FROM sys.types dc WHERE dc.name = type_name COLLATE sys.database_default); + ELSE + RETURN NULL; + END IF; + ELSEIF property = 'ownerid' + THEN + IF NOT EXISTS (SELECT ty.name FROM sys.types ty WHERE ty.name = type_name COLLATE sys.database_default AND ty.is_user_defined = 0) THEN + RETURN(SELECT CAST(dc.nspowner AS INT) FROM pg_catalog.pg_namespace dc WHERE dc.oid = schemaid); + ELSE + RETURN 10; + END IF; + + ELSEIF property = 'usesansitrim' + THEN + IF type_name::regtype IN ('bigint'::regtype, 'int'::regtype, 'smallint'::regtype,'tinyint'::regtype, + 'numeric'::regtype, 'float'::regtype, 'real'::regtype, 'money'::regtype) + THEN + RETURN NULL; + ELSE + RETURN 1; + END IF; + + END IF; + + RETURN NULL; +END; +$$ +LANGUAGE plpgsql STABLE; + + CREATE OR REPLACE FUNCTION OBJECTPROPERTYEX( id INT, property SYS.VARCHAR diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql index 9f065b612e..90cab0d61e 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql @@ -156,6 +156,101 @@ END; $body$ LANGUAGE plpgsql IMMUTABLE; +CREATE OR REPLACE FUNCTION typeproperty( + typename sys.VARCHAR, + property sys.VARCHAR + ) +RETURNS INT +AS $$ +DECLARE + var_sc int; + schemaid int; + schema_name VARCHAR; + type_name VARCHAR; + sys_id int; + testt VARCHAR; +BEGIN + + property := TRIM(LOWER(COALESCE(property,''))); + + IF typename LIKE '%.%' THEN + schema_name := lower(split_part(typename COLLATE "C", '.', 1)); + type_name := lower(split_part(typename COLLATE "C",'.', 2)); + ELSE + schema_name := 'dbo'; + type_name := typename; + END IF; + + + IF NOT EXISTS (SELECT ao.name FROM sys.types ao WHERE ao.name = type_name COLLATE sys.database_default) + THEN + RETURN NULL; + END IF; + + IF NOT EXISTS (SELECT ao.name FROM sys.schemas ao WHERE ao.name = schema_name COLLATE sys.database_default OR schema_name = 'sys' OR schema_name = 'pg_catalog') + THEN + RETURN NULL ; + END IF; + + IF NOT EXISTS (SELECT ty.is_user_defined FROM sys.types ty WHERE ty.name = type_name COLLATE sys.database_default AND ty.is_user_defined = 0) THEN + schemaid := (SELECT sc.schema_id FROM sys.schemas sc WHERE sc.name = schema_name COLLATE sys.database_default); + ELSE + schemaid := (SELECT sc.schema_id FROM sys.types sc WHERE sc.name = type_name COLLATE sys.database_default); + END IF; + + + if (SELECT schema_id(schema_name)) <> schemaid THEN + RETURN NULL; + END IF; + + IF property = 'allowsnull' + THEN + RETURN ( + SELECT CAST( t1.is_nullable AS INT) + FROM sys.types t1 + WHERE t1.name = type_name COLLATE sys.database_default AND t1.schema_id = schemaid ); + + ELSEIF property = 'precision' + THEN + RETURN (SELECT CAST(dc.precision AS INT) FROM sys.types dc WHERE dc.name = type_name COLLATE sys.database_default AND dc.schema_id = schemaid); + + ELSEIF property = 'scale' + THEN + sys_id := (SELECT CAST(dc.system_type_id AS INT) FROM sys.types dc WHERE dc.name = type_name COLLATE sys.database_default AND dc.schema_id = schemaid); + type_name := (SELECT CAST(dc.name AS VARCHAR) FROM sys.types dc WHERE dc.system_type_id = sys_id AND dc.is_user_defined = 0); + IF type_name::regtype IN ('bigint'::regtype, 'int'::regtype, 'smallint'::regtype,'tinyint'::regtype, + 'numeric'::regtype, 'float'::regtype, 'real'::regtype, 'money'::regtype) + THEN + RETURN(SELECT CAST(dc.scale AS INT) FROM sys.types dc WHERE dc.name = type_name COLLATE sys.database_default); + ELSE + RETURN NULL; + END IF; + ELSEIF property = 'ownerid' + THEN + IF NOT EXISTS (SELECT ty.name FROM sys.types ty WHERE ty.name = type_name COLLATE sys.database_default AND ty.is_user_defined = 0) THEN + RETURN(SELECT CAST(dc.nspowner AS INT) FROM pg_catalog.pg_namespace dc WHERE dc.oid = schemaid); + ELSE + RETURN 10; + END IF; + + ELSEIF property = 'usesansitrim' + THEN + IF type_name::regtype IN ('bigint'::regtype, 'int'::regtype, 'smallint'::regtype,'tinyint'::regtype, + 'numeric'::regtype, 'float'::regtype, 'real'::regtype, 'money'::regtype) + THEN + RETURN NULL; + ELSE + RETURN 1; + END IF; + + END IF; + + RETURN NULL; +END; +$$ +LANGUAGE plpgsql STABLE; + + CREATE OR REPLACE FUNCTION sys.dateadd_numeric_representation_helper(IN datepart PG_CATALOG.TEXT, IN num INTEGER, IN startdate ANYELEMENT) RETURNS DATETIME AS $$ DECLARE digit_to_startdate DATETIME; diff --git a/test/JDBC/expected/typeproperty-dep-vu-cleanup.out b/test/JDBC/expected/typeproperty-dep-vu-cleanup.out new file mode 100644 index 0000000000..6e72b89c13 --- /dev/null +++ b/test/JDBC/expected/typeproperty-dep-vu-cleanup.out @@ -0,0 +1,14 @@ +DROP VIEW typeproperty_vu_prepare_dep_view +GO + +DROP PROC typeproperty_vu_prepare_dep_proc +GO + +DROP FUNCTION typeproperty_vu_prepare_dep_func +GO + +DROP TYPE typeproperty_test1_dep_vu.null_check1_dep_vu +GO + +DROP SCHEMA typeproperty_test1_dep_vu +GO diff --git a/test/JDBC/expected/typeproperty-dep-vu-prepare.out b/test/JDBC/expected/typeproperty-dep-vu-prepare.out new file mode 100644 index 0000000000..69e0ad8442 --- /dev/null +++ b/test/JDBC/expected/typeproperty-dep-vu-prepare.out @@ -0,0 +1,21 @@ +CREATE SCHEMA typeproperty_test1_dep_vu +GO + +CREATE TYPE typeproperty_test1_dep_vu.null_check1_dep_vu FROM varchar(11) NOT NULL ; +GO + +CREATE VIEW typeproperty_vu_prepare_dep_view AS +SELECT TYPEPROPERTY('typeproperty_test1_dep_vu.null_check1_dep_vu', 'scale') +GO + +CREATE PROC typeproperty_vu_prepare_dep_proc AS +SELECT TYPEPROPERTY('typeproperty_test1_dep_vu.null_check1_dep_vu', 'allowsnull') +GO + +CREATE FUNCTION typeproperty_vu_prepare_dep_func() +RETURNS INT +AS +BEGIN +RETURN TYPEPROPERTY('typeproperty_test1_dep_vu.null_check1_dep_vu', 'precision') +END +GO diff --git a/test/JDBC/expected/typeproperty-dep-vu-verify.out b/test/JDBC/expected/typeproperty-dep-vu-verify.out new file mode 100644 index 0000000000..0d7b2a77e0 --- /dev/null +++ b/test/JDBC/expected/typeproperty-dep-vu-verify.out @@ -0,0 +1,23 @@ +SELECT * FROM typeproperty_vu_prepare_dep_view +GO +~~START~~ +int + +~~END~~ + + +EXEC typeproperty_vu_prepare_dep_proc +GO +~~START~~ +int +0 +~~END~~ + + +SELECT * FROM typeproperty_vu_prepare_dep_func() +GO +~~START~~ +int +0 +~~END~~ + diff --git a/test/JDBC/expected/typeproperty-vu-cleanup.out b/test/JDBC/expected/typeproperty-vu-cleanup.out new file mode 100644 index 0000000000..6968d455e4 --- /dev/null +++ b/test/JDBC/expected/typeproperty-vu-cleanup.out @@ -0,0 +1,17 @@ +DROP TYPE typeproperty_test1.null_check1 +Go + +DROP TYPE typeproperty_test1.null_check2 +Go + +DROP TYPE typeproperty_test2.null_check1 +Go + +DROP TYPE typeproperty_test2.null_check2 +Go + +DROP SCHEMA typeproperty_test1 +GO + +DROP SCHEMA typeproperty_test2 +GO diff --git a/test/JDBC/expected/typeproperty-vu-prepare.out b/test/JDBC/expected/typeproperty-vu-prepare.out new file mode 100644 index 0000000000..bddfd3e662 --- /dev/null +++ b/test/JDBC/expected/typeproperty-vu-prepare.out @@ -0,0 +1,17 @@ +Create schema typeproperty_test1 +Go + +Create schema typeproperty_test2 +Go + +Create type typeproperty_test1.null_check1 FROM varchar(11) NOT NULL ; +GO + +Create type typeproperty_test1.null_check2 FROM int NULL ; +GO + +Create type typeproperty_test2.null_check1 FROM varchar(11) NULL ; +GO + +Create type typeproperty_test2.null_check2 FROM int NOT NULL ; +GO diff --git a/test/JDBC/expected/typeproperty-vu-verify.out b/test/JDBC/expected/typeproperty-vu-verify.out new file mode 100644 index 0000000000..17079ab5f4 --- /dev/null +++ b/test/JDBC/expected/typeproperty-vu-verify.out @@ -0,0 +1,318 @@ +-- =============== AllowsNull =============== +Select typeproperty('sys.int','allowsnull') +Go +~~START~~ +int + +~~END~~ + + +Select typeproperty('pg_catalog.int','allowsnull') +Go +~~START~~ +int +1 +~~END~~ + + +Select typeproperty('pg_catalog.int','allowsnul') +GO +~~START~~ +int + +~~END~~ + + +Select typeproperty('pg_catalog.int',' allowsnull ') +Go +~~START~~ +int +1 +~~END~~ + + +Select typeproperty('typeproperty_test1.null_check1','allowsnull') +GO +~~START~~ +int +0 +~~END~~ + + +Select typeproperty('typeproperty_test1.null_check2','allowsnull') +GO +~~START~~ +int +1 +~~END~~ + + +Select typeproperty('typeproperty_test2.null_check1','allowsnull') +GO +~~START~~ +int +1 +~~END~~ + + +Select typeproperty('typeproperty_test2.null_check2','allowsnull') +GO +~~START~~ +int +0 +~~END~~ + + + +-- =============== Precision =============== +Select typeproperty('sys.int','precision') +Go +~~START~~ +int + +~~END~~ + + +Select typeproperty('pg_catalog.int','precision') +Go +~~START~~ +int +10 +~~END~~ + + +Select typeproperty('pg_catalog.int','precisusn') +GO +~~START~~ +int + +~~END~~ + + +Select typeproperty('pg_catalog.int',' precision ') +Go +~~START~~ +int +10 +~~END~~ + + +Select typeproperty('typeproperty_test1.null_check1','precision') +GO +~~START~~ +int +0 +~~END~~ + + +Select typeproperty('typeproperty_test1.null_check2','precision') +GO +~~START~~ +int +10 +~~END~~ + + +Select typeproperty('typeproperty_test2.null_check1','precision') +GO +~~START~~ +int +0 +~~END~~ + + +Select typeproperty('typeproperty_test2.null_check2','precision') +GO +~~START~~ +int +10 +~~END~~ + + + +-- ===============Scale=============== +Select typeproperty('sys.int','scale') +Go +~~START~~ +int + +~~END~~ + + +Select typeproperty('pg_catalog.int','scale') +Go +~~START~~ +int +0 +~~END~~ + + +Select typeproperty('pg_catalog.int','scael') +GO +~~START~~ +int + +~~END~~ + + +Select typeproperty('pg_catalog.int',' scale ') +Go +~~START~~ +int +0 +~~END~~ + + +Select typeproperty('sys.char',' scale ') +Go +~~START~~ +int + +~~END~~ + + +Select typeproperty('sys.money',' scale ') +Go +~~START~~ +int +4 +~~END~~ + + +Select typeproperty('typeproperty_test1.null_check1','scale') +GO +~~START~~ +int + +~~END~~ + + +Select typeproperty('typeproperty_test1.null_check2','scale') +GO +~~START~~ +int +0 +~~END~~ + + +Select typeproperty('typeproperty_test2.null_check1','scale') +GO +~~START~~ +int + +~~END~~ + + +Select typeproperty('typeproperty_test2.null_check2','scale') +GO +~~START~~ +int +0 +~~END~~ + + + +-- ===============OwnerId=============== +SELECT CASE + WHEN typeproperty('sys.int','ownerid') IS NOT NULL + Then 'SUCCESS' + ELSE + 'FAILED' +END +GO +~~START~~ +text +FAILED +~~END~~ + + +SELECT CASE + WHEN typeproperty('pg_catalog.int','ownerid') IS NOT NULL + Then 'SUCCESS' + ELSE + 'FAILED' +END +GO +~~START~~ +text +SUCCESS +~~END~~ + + +SELECT CASE + WHEN typeproperty('pg_catalog.int','ownerdi') IS NOT NULL + Then 'SUCCESS' + ELSE + 'FAILED' +END +GO +~~START~~ +text +FAILED +~~END~~ + + +SELECT CASE + WHEN typeproperty('pg_catalog.int',' ownerid ') IS NOT NULL + Then 'SUCCESS' + ELSE + 'FAILED' +END +GO +~~START~~ +text +SUCCESS +~~END~~ + + +SELECT CASE + WHEN typeproperty('typeproperty_test1.null_check1','ownerid') IS NOT NULL + Then 'SUCCESS' + ELSE + 'FAILED' +END +GO +~~START~~ +text +SUCCESS +~~END~~ + + +SELECT CASE + WHEN typeproperty('typeproperty_test1.null_check2','ownerid') IS NOT NULL + Then 'SUCCESS' + ELSE + 'FAILED' +END +GO +~~START~~ +text +SUCCESS +~~END~~ + + +SELECT CASE + WHEN typeproperty('typeproperty_test2.null_check1','ownerid') IS NOT NULL + Then 'SUCCESS' + ELSE + 'FAILED' +END +GO +~~START~~ +text +SUCCESS +~~END~~ + + +SELECT CASE + WHEN typeproperty('typeproperty_test2.null_check2','ownerid') IS NOT NULL + Then 'SUCCESS' + ELSE + 'FAILED' +END +GO +~~START~~ +text +SUCCESS +~~END~~ + diff --git a/test/JDBC/input/functions/typeproperty-dep-vu-cleanup.sql b/test/JDBC/input/functions/typeproperty-dep-vu-cleanup.sql new file mode 100644 index 0000000000..6e72b89c13 --- /dev/null +++ b/test/JDBC/input/functions/typeproperty-dep-vu-cleanup.sql @@ -0,0 +1,14 @@ +DROP VIEW typeproperty_vu_prepare_dep_view +GO + +DROP PROC typeproperty_vu_prepare_dep_proc +GO + +DROP FUNCTION typeproperty_vu_prepare_dep_func +GO + +DROP TYPE typeproperty_test1_dep_vu.null_check1_dep_vu +GO + +DROP SCHEMA typeproperty_test1_dep_vu +GO diff --git a/test/JDBC/input/functions/typeproperty-dep-vu-prepare.sql b/test/JDBC/input/functions/typeproperty-dep-vu-prepare.sql new file mode 100644 index 0000000000..69e0ad8442 --- /dev/null +++ b/test/JDBC/input/functions/typeproperty-dep-vu-prepare.sql @@ -0,0 +1,21 @@ +CREATE SCHEMA typeproperty_test1_dep_vu +GO + +CREATE TYPE typeproperty_test1_dep_vu.null_check1_dep_vu FROM varchar(11) NOT NULL ; +GO + +CREATE VIEW typeproperty_vu_prepare_dep_view AS +SELECT TYPEPROPERTY('typeproperty_test1_dep_vu.null_check1_dep_vu', 'scale') +GO + +CREATE PROC typeproperty_vu_prepare_dep_proc AS +SELECT TYPEPROPERTY('typeproperty_test1_dep_vu.null_check1_dep_vu', 'allowsnull') +GO + +CREATE FUNCTION typeproperty_vu_prepare_dep_func() +RETURNS INT +AS +BEGIN +RETURN TYPEPROPERTY('typeproperty_test1_dep_vu.null_check1_dep_vu', 'precision') +END +GO diff --git a/test/JDBC/input/functions/typeproperty-dep-vu-verify.sql b/test/JDBC/input/functions/typeproperty-dep-vu-verify.sql new file mode 100644 index 0000000000..b2e2d9ba64 --- /dev/null +++ b/test/JDBC/input/functions/typeproperty-dep-vu-verify.sql @@ -0,0 +1,8 @@ +SELECT * FROM typeproperty_vu_prepare_dep_view +GO + +EXEC typeproperty_vu_prepare_dep_proc +GO + +SELECT * FROM typeproperty_vu_prepare_dep_func() +GO diff --git a/test/JDBC/input/functions/typeproperty-vu-cleanup.sql b/test/JDBC/input/functions/typeproperty-vu-cleanup.sql new file mode 100644 index 0000000000..6968d455e4 --- /dev/null +++ b/test/JDBC/input/functions/typeproperty-vu-cleanup.sql @@ -0,0 +1,17 @@ +DROP TYPE typeproperty_test1.null_check1 +Go + +DROP TYPE typeproperty_test1.null_check2 +Go + +DROP TYPE typeproperty_test2.null_check1 +Go + +DROP TYPE typeproperty_test2.null_check2 +Go + +DROP SCHEMA typeproperty_test1 +GO + +DROP SCHEMA typeproperty_test2 +GO diff --git a/test/JDBC/input/functions/typeproperty-vu-prepare.sql b/test/JDBC/input/functions/typeproperty-vu-prepare.sql new file mode 100644 index 0000000000..bddfd3e662 --- /dev/null +++ b/test/JDBC/input/functions/typeproperty-vu-prepare.sql @@ -0,0 +1,17 @@ +Create schema typeproperty_test1 +Go + +Create schema typeproperty_test2 +Go + +Create type typeproperty_test1.null_check1 FROM varchar(11) NOT NULL ; +GO + +Create type typeproperty_test1.null_check2 FROM int NULL ; +GO + +Create type typeproperty_test2.null_check1 FROM varchar(11) NULL ; +GO + +Create type typeproperty_test2.null_check2 FROM int NOT NULL ; +GO diff --git a/test/JDBC/input/functions/typeproperty-vu-verify.sql b/test/JDBC/input/functions/typeproperty-vu-verify.sql new file mode 100644 index 0000000000..5d2c806240 --- /dev/null +++ b/test/JDBC/input/functions/typeproperty-vu-verify.sql @@ -0,0 +1,148 @@ +-- =============== AllowsNull =============== +Select typeproperty('sys.int','allowsnull') +Go + +Select typeproperty('pg_catalog.int','allowsnull') +Go + +Select typeproperty('pg_catalog.int','allowsnul') +GO + +Select typeproperty('pg_catalog.int',' allowsnull ') +Go + +Select typeproperty('typeproperty_test1.null_check1','allowsnull') +GO + +Select typeproperty('typeproperty_test1.null_check2','allowsnull') +GO + +Select typeproperty('typeproperty_test2.null_check1','allowsnull') +GO + +Select typeproperty('typeproperty_test2.null_check2','allowsnull') +GO + +-- =============== Precision =============== + +Select typeproperty('sys.int','precision') +Go + +Select typeproperty('pg_catalog.int','precision') +Go + +Select typeproperty('pg_catalog.int','precisusn') +GO + +Select typeproperty('pg_catalog.int',' precision ') +Go + +Select typeproperty('typeproperty_test1.null_check1','precision') +GO + +Select typeproperty('typeproperty_test1.null_check2','precision') +GO + +Select typeproperty('typeproperty_test2.null_check1','precision') +GO + +Select typeproperty('typeproperty_test2.null_check2','precision') +GO + +-- ===============Scale=============== + +Select typeproperty('sys.int','scale') +Go + +Select typeproperty('pg_catalog.int','scale') +Go + +Select typeproperty('pg_catalog.int','scael') +GO + +Select typeproperty('pg_catalog.int',' scale ') +Go + +Select typeproperty('sys.char',' scale ') +Go + +Select typeproperty('sys.money',' scale ') +Go + +Select typeproperty('typeproperty_test1.null_check1','scale') +GO + +Select typeproperty('typeproperty_test1.null_check2','scale') +GO + +Select typeproperty('typeproperty_test2.null_check1','scale') +GO + +Select typeproperty('typeproperty_test2.null_check2','scale') +GO + +-- ===============OwnerId=============== + +SELECT CASE + WHEN typeproperty('sys.int','ownerid') IS NOT NULL + Then 'SUCCESS' + ELSE + 'FAILED' +END +GO + +SELECT CASE + WHEN typeproperty('pg_catalog.int','ownerid') IS NOT NULL + Then 'SUCCESS' + ELSE + 'FAILED' +END +GO + +SELECT CASE + WHEN typeproperty('pg_catalog.int','ownerdi') IS NOT NULL + Then 'SUCCESS' + ELSE + 'FAILED' +END +GO + +SELECT CASE + WHEN typeproperty('pg_catalog.int',' ownerid ') IS NOT NULL + Then 'SUCCESS' + ELSE + 'FAILED' +END +GO + +SELECT CASE + WHEN typeproperty('typeproperty_test1.null_check1','ownerid') IS NOT NULL + Then 'SUCCESS' + ELSE + 'FAILED' +END +GO + +SELECT CASE + WHEN typeproperty('typeproperty_test1.null_check2','ownerid') IS NOT NULL + Then 'SUCCESS' + ELSE + 'FAILED' +END +GO + +SELECT CASE + WHEN typeproperty('typeproperty_test2.null_check1','ownerid') IS NOT NULL + Then 'SUCCESS' + ELSE + 'FAILED' +END +GO + +SELECT CASE + WHEN typeproperty('typeproperty_test2.null_check2','ownerid') IS NOT NULL + Then 'SUCCESS' + ELSE + 'FAILED' +END +GO diff --git a/test/JDBC/upgrade/15_2/schedule b/test/JDBC/upgrade/15_2/schedule index 5db7699572..177496db35 100644 --- a/test/JDBC/upgrade/15_2/schedule +++ b/test/JDBC/upgrade/15_2/schedule @@ -407,3 +407,4 @@ TestVariableDataLength TestXML timefromparts triggers_with_transaction +typeproperty diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index 98d2ae9b95..977f64ed92 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -429,3 +429,5 @@ test_windows_sp_helpuser TestXML timefromparts triggers_with_transaction +typeproperty +typeproperty-dep From 8ea7b35f6ff7daf4f9b67b780b10615bf69eef32 Mon Sep 17 00:00:00 2001 From: zhenye <73271404+ZhenyeLee@users.noreply.github.com> Date: Wed, 26 Apr 2023 10:19:06 -0700 Subject: [PATCH 077/363] Support numeric representation for DATENAME() and DATEPART() function (#1462) * Support numeric representation for DATENAME() and DATEPART() function Before this PR, we didn't support numeric representation for DATENAME() and DATEPART() function. In this PR, for DATEPART() function, we added the code to CAST numeric representation to DATETIME first. And for DATENAME() function, we CAST the input into DATETIME instead of DATE to make sure DATENAME() function accept numeric representation input. Task: BABEL-323 Signed-off-by: Zhenye Li --- .../babelfishpg_tsql/sql/sys_functions.sql | 40 +- .../babelfishpg_tsql--3.1.0--3.2.0.sql | 123 +++++- ...ime-numeric-dateaddfunction-vu-prepare.out | 351 +++++++++++++++++- ...time-numeric-dateaddfunction-vu-verify.out | 41 +- ...ime-numeric-dateaddfunction-vu-prepare.sql | 171 ++++++++- ...time-numeric-dateaddfunction-vu-verify.sql | 18 +- 6 files changed, 683 insertions(+), 61 deletions(-) diff --git a/contrib/babelfishpg_tsql/sql/sys_functions.sql b/contrib/babelfishpg_tsql/sql/sys_functions.sql index b7728b32a7..e9c6acb4c3 100644 --- a/contrib/babelfishpg_tsql/sql/sys_functions.sql +++ b/contrib/babelfishpg_tsql/sql/sys_functions.sql @@ -1141,7 +1141,7 @@ CREATE OR REPLACE FUNCTION sys.dateadd(IN datepart PG_CATALOG.TEXT, IN num INTEG AS $body$ BEGIN - RAISE EXCEPTION 'Argument data type bit is invalid for argument 2 of dateadd function.'; + return sys.dateadd_numeric_representation_helper(datepart, num, startdate); END; $body$ LANGUAGE plpgsql IMMUTABLE; @@ -1193,8 +1193,8 @@ CREATE OR REPLACE FUNCTION sys.dateadd_numeric_representation_helper(IN datepart DECLARE digit_to_startdate DATETIME; BEGIN - IF pg_typeof(startdate) IN ('bigint'::regtype, 'int'::regtype, 'smallint'::regtype,'sys.tinyint'::regtype, - 'numeric'::regtype, 'float'::regtype,'double precision'::regtype, 'real'::regtype, 'sys.money'::regtype,'sys.smallmoney'::regtype) THEN + IF pg_typeof(startdate) IN ('bigint'::regtype, 'int'::regtype, 'smallint'::regtype,'sys.tinyint'::regtype,'sys.decimal'::regtype, + 'numeric'::regtype, 'float'::regtype,'double precision'::regtype, 'real'::regtype, 'sys.money'::regtype,'sys.smallmoney'::regtype,'sys.bit'::regtype) THEN digit_to_startdate := CAST('1900-01-01 00:00:00.0' AS sys.DATETIME) + CAST(startdate as sys.DATETIME); END IF; @@ -1235,7 +1235,37 @@ DECLARE first_day DATE; first_week_end INTEGER; day INTEGER; + datapart_date sys.DATETIME; BEGIN + IF pg_typeof(arg) IN ('bigint'::regtype, 'int'::regtype, 'smallint'::regtype,'sys.tinyint'::regtype,'sys.decimal'::regtype,'numeric'::regtype, + 'float'::regtype, 'double precision'::regtype, 'real'::regtype, 'sys.money'::regtype,'sys.smallmoney'::regtype,'sys.bit'::regtype) THEN + datapart_date = CAST(arg AS sys.DATETIME); + CASE datepart + WHEN 'dow' THEN + result = (date_part(datepart, datapart_date)::INTEGER - current_setting('babelfishpg_tsql.datefirst')::INTEGER + 7) % 7 + 1; + WHEN 'tsql_week' THEN + first_day = make_date(date_part('year', datapart_date)::INTEGER, 1, 1); + first_week_end = 8 - sys.datepart_internal('dow', first_day)::INTEGER; + day = date_part('doy', datapart_date)::INTEGER; + IF day <= first_week_end THEN + result = 1; + ELSE + result = 2 + (day - first_week_end - 1) / 7; + END IF; + WHEN 'second' THEN + result = TRUNC(date_part(datepart, datapart_date))::INTEGER; + WHEN 'millisecond' THEN + result = right(date_part(datepart, datapart_date)::TEXT, 3)::INTEGER; + WHEN 'microsecond' THEN + result = right(date_part(datepart, datapart_date)::TEXT, 6)::INTEGER; + WHEN 'nanosecond' THEN + -- Best we can do - Postgres does not support nanosecond precision + result = right(date_part('microsecond', datapart_date)::TEXT, 6)::INTEGER * 1000; + ELSE + result = date_part(datepart, datapart_date)::INTEGER; + END CASE; + RETURN result; + END IF; CASE datepart WHEN 'dow' THEN result = (date_part(datepart, arg)::INTEGER - current_setting('babelfishpg_tsql.datefirst')::INTEGER + 7) % 7 + 1; @@ -1693,10 +1723,10 @@ $BODY$ SELECT CASE WHEN dp = 'month'::text THEN - to_char(arg::date, 'TMMonth') + to_char(arg::sys.DATETIME, 'TMMonth') -- '1969-12-28' is a Sunday WHEN dp = 'dow'::text THEN - to_char(arg::date, 'TMDay') + to_char(arg::sys.DATETIME, 'TMDay') ELSE sys.datepart(dp, arg)::TEXT END diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql index 90cab0d61e..97521af502 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql @@ -119,11 +119,130 @@ SELECT FROM sys.babelfish_syslanguages; GRANT SELECT ON sys.syslanguages TO PUBLIC; +CREATE OR REPLACE FUNCTION sys.datename(IN dp PG_CATALOG.TEXT, IN arg anyelement) RETURNS TEXT AS +$BODY$ +SELECT + CASE + WHEN dp = 'month'::text THEN + to_char(arg::sys.DATETIME, 'TMMonth') + -- '1969-12-28' is a Sunday + WHEN dp = 'dow'::text THEN + to_char(arg::sys.DATETIME, 'TMDay') + ELSE + sys.datepart(dp, arg)::TEXT + END +$BODY$ +STRICT +LANGUAGE sql IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.datepart_internal(IN datepart PG_CATALOG.TEXT, IN arg anyelement,IN df_tz INTEGER DEFAULT 0) RETURNS INTEGER AS $$ +DECLARE + result INTEGER; + first_day DATE; + first_week_end INTEGER; + day INTEGER; + datapart_date sys.DATETIME; +BEGIN + IF pg_typeof(arg) IN ('bigint'::regtype, 'int'::regtype, 'smallint'::regtype,'sys.tinyint'::regtype,'sys.decimal'::regtype,'numeric'::regtype, + 'float'::regtype, 'double precision'::regtype, 'real'::regtype, 'sys.money'::regtype,'sys.smallmoney'::regtype,'sys.bit'::regtype) THEN + datapart_date = CAST(arg AS sys.DATETIME); + CASE datepart + WHEN 'dow' THEN + result = (date_part(datepart, datapart_date)::INTEGER - current_setting('babelfishpg_tsql.datefirst')::INTEGER + 7) % 7 + 1; + WHEN 'tsql_week' THEN + first_day = make_date(date_part('year', datapart_date)::INTEGER, 1, 1); + first_week_end = 8 - sys.datepart_internal('dow', first_day)::INTEGER; + day = date_part('doy', datapart_date)::INTEGER; + IF day <= first_week_end THEN + result = 1; + ELSE + result = 2 + (day - first_week_end - 1) / 7; + END IF; + WHEN 'second' THEN + result = TRUNC(date_part(datepart, datapart_date))::INTEGER; + WHEN 'millisecond' THEN + result = right(date_part(datepart, datapart_date)::TEXT, 3)::INTEGER; + WHEN 'microsecond' THEN + result = right(date_part(datepart, datapart_date)::TEXT, 6)::INTEGER; + WHEN 'nanosecond' THEN + -- Best we can do - Postgres does not support nanosecond precision + result = right(date_part('microsecond', datapart_date)::TEXT, 6)::INTEGER * 1000; + ELSE + result = date_part(datepart, datapart_date)::INTEGER; + END CASE; + RETURN result; + END IF; + CASE datepart + WHEN 'dow' THEN + result = (date_part(datepart, arg)::INTEGER - current_setting('babelfishpg_tsql.datefirst')::INTEGER + 7) % 7 + 1; + WHEN 'tsql_week' THEN + first_day = make_date(date_part('year', arg)::INTEGER, 1, 1); + first_week_end = 8 - sys.datepart_internal('dow', first_day)::INTEGER; + day = date_part('doy', arg)::INTEGER; + IF day <= first_week_end THEN + result = 1; + ELSE + result = 2 + (day - first_week_end - 1) / 7; + END IF; + WHEN 'second' THEN + result = TRUNC(date_part(datepart, arg))::INTEGER; + WHEN 'millisecond' THEN + result = right(date_part(datepart, arg)::TEXT, 3)::INTEGER; + WHEN 'microsecond' THEN + result = right(date_part(datepart, arg)::TEXT, 6)::INTEGER; + WHEN 'nanosecond' THEN + -- Best we can do - Postgres does not support nanosecond precision + result = right(date_part('microsecond', arg)::TEXT, 6)::INTEGER * 1000; + WHEN 'tzoffset' THEN + -- timezone for datetimeoffset + result = df_tz; + ELSE + result = date_part(datepart, arg)::INTEGER; + END CASE; + RETURN result; +EXCEPTION WHEN invalid_parameter_value or feature_not_supported THEN + -- date_part() throws an exception when trying to get day/month/year etc. from + -- TIME, so we just need to catch the exception in this case + -- date_part() returns 0 when trying to get hour/minute/second etc. from + -- DATE, which is the desirable behavior for datepart() as well. + -- If the date argument data type does not have the specified datepart, + -- date_part() will return the default value for that datepart. + CASE datepart + -- Case for datepart is year, yy and yyyy, all mappings are defined in gram.y. + WHEN 'year' THEN RETURN 1900; + -- Case for datepart is quater, qq and q + WHEN 'quarter' THEN RETURN 1; + -- Case for datepart is month, mm and m + WHEN 'month' THEN RETURN 1; + -- Case for datepart is day, dd and d + WHEN 'day' THEN RETURN 1; + -- Case for datepart is dayofyear, dy + WHEN 'doy' THEN RETURN 1; + -- Case for datepart is y(also refers to dayofyear) + WHEN 'y' THEN RETURN 1; + -- Case for datepart is week, wk and ww + WHEN 'tsql_week' THEN RETURN 1; + -- Case for datepart is iso_week, isowk and isoww + WHEN 'week' THEN RETURN 1; + -- Case for datepart is tzoffset and tz + WHEN 'tzoffset' THEN RETURN 0; + -- Case for datepart is weekday and dw, return dow according to datefirst + WHEN 'dow' THEN + RETURN (1 - current_setting('babelfishpg_tsql.datefirst')::INTEGER + 7) % 7 + 1 ; + ELSE + RAISE EXCEPTION '''%'' is not a recognized datepart option', datepart; + RETURN -1; + END CASE; +END; +$$ +STRICT +LANGUAGE plpgsql IMMUTABLE; + CREATE OR REPLACE FUNCTION sys.dateadd(IN datepart PG_CATALOG.TEXT, IN num INTEGER, IN startdate sys.bit) RETURNS DATETIME AS $body$ BEGIN - RAISE EXCEPTION 'Argument data type bit is invalid for argument 2 of dateadd function.'; + return sys.dateadd_numeric_representation_helper(datepart, num, startdate); END; $body$ LANGUAGE plpgsql IMMUTABLE; @@ -255,7 +374,7 @@ CREATE OR REPLACE FUNCTION sys.dateadd_numeric_representation_helper(IN datepart DECLARE digit_to_startdate DATETIME; BEGIN - IF pg_typeof(startdate) IN ('bigint'::regtype, 'int'::regtype, 'smallint'::regtype,'sys.tinyint'::regtype, + IF pg_typeof(startdate) IN ('bigint'::regtype, 'int'::regtype, 'smallint'::regtype,'sys.tinyint'::regtype,'sys.decimal'::regtype, 'numeric'::regtype, 'float'::regtype,'double precision'::regtype, 'real'::regtype, 'sys.money'::regtype,'sys.smallmoney'::regtype,'sys.bit'::regtype) THEN digit_to_startdate := CAST('1900-01-01 00:00:00.0' AS sys.DATETIME) + CAST(startdate as sys.DATETIME); END IF; diff --git a/test/JDBC/expected/TestDatetime-numeric-dateaddfunction-vu-prepare.out b/test/JDBC/expected/TestDatetime-numeric-dateaddfunction-vu-prepare.out index 1745959ec9..6a9a9d3e22 100644 --- a/test/JDBC/expected/TestDatetime-numeric-dateaddfunction-vu-prepare.out +++ b/test/JDBC/expected/TestDatetime-numeric-dateaddfunction-vu-prepare.out @@ -111,28 +111,341 @@ smalldatetime ~~ERROR (Message: data out of range for smalldatetime)~~ +-- Should all fail +SELECT CONVERT(DATETIME2, CAST(-2.5 as DECIMAL)) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type "decimal" to datetime2)~~ + +SELECT CONVERT(DATETIME2, CAST(-2.5 as NUMERIC(30,8))) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type numeric to datetime2)~~ + +SELECT CONVERT(DATETIME2, CAST(-2.5 as FLOAT)) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type double precision to datetime2)~~ + +SELECT CONVERT(DATETIME2, CAST(-2.5 as REAL)) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type real to datetime2)~~ + +SELECT CONVERT(DATETIME2, CAST(-2.5 as INT)) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type integer to datetime2)~~ + +SELECT CONVERT(DATETIME2, CAST(-2.5 as BIGINT)) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type bigint to datetime2)~~ + +SELECT CONVERT(DATETIME2, CAST(-2.5 as SMALLINT)) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type smallint to datetime2)~~ + +SELECT CONVERT(DATETIME2, CAST(-2.5 as MONEY)) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type money to datetime2)~~ + +SELECT CONVERT(DATETIME2, CAST(-2.5 as SMALLMONEY)) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type smallmoney to datetime2)~~ + + +-- Should all fail +SELECT CONVERT(DATETIMEOFFSET, CAST(-2.5 as DECIMAL)) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type "decimal" to datetimeoffset)~~ + +SELECT CONVERT(DATETIMEOFFSET, CAST(-2.5 as NUMERIC(30,8))) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type numeric to datetimeoffset)~~ + +SELECT CONVERT(DATETIMEOFFSET, CAST(-2.5 as FLOAT)) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type double precision to datetimeoffset)~~ + +SELECT CONVERT(DATETIMEOFFSET, CAST(-2.5 as REAL)) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type real to datetimeoffset)~~ + +SELECT CONVERT(DATETIMEOFFSET, CAST(-2.5 as INT)) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type integer to datetimeoffset)~~ + +SELECT CONVERT(DATETIMEOFFSET, CAST(-2.5 as BIGINT)) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type bigint to datetimeoffset)~~ + +SELECT CONVERT(DATETIMEOFFSET, CAST(-2.5 as SMALLINT)) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type smallint to datetimeoffset)~~ + +SELECT CONVERT(DATETIMEOFFSET, CAST(-2.5 as MONEY)) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type money to datetimeoffset)~~ + +SELECT CONVERT(DATETIMEOFFSET, CAST(-2.5 as SMALLMONEY)) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type smallmoney to datetimeoffset)~~ + + +-- Should all fail +SELECT CONVERT(DATE, CAST(-2.5 as DECIMAL)) +GO +~~START~~ +date +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type "decimal" to date)~~ + +SELECT CONVERT(DATE, CAST(-2.5 as NUMERIC(30,8))) +GO +~~START~~ +date +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type numeric to date)~~ + +SELECT CONVERT(DATE, CAST(-2.5 as FLOAT)) +GO +~~START~~ +date +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type double precision to date)~~ + +SELECT CONVERT(DATE, CAST(-2.5 as REAL)) +GO +~~START~~ +date +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type real to date)~~ + +SELECT CONVERT(DATE, CAST(-2.5 as INT)) +GO +~~START~~ +date +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type integer to date)~~ + +SELECT CONVERT(DATE, CAST(-2.5 as BIGINT)) +GO +~~START~~ +date +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type bigint to date)~~ + +SELECT CONVERT(DATE, CAST(-2.5 as SMALLINT)) +GO +~~START~~ +date +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type smallint to date)~~ + +SELECT CONVERT(DATE, CAST(-2.5 as MONEY)) +GO +~~START~~ +date +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type money to date)~~ + +SELECT CONVERT(DATE, CAST(-2.5 as SMALLMONEY)) +GO +~~START~~ +date +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type smallmoney to date)~~ + + +-- Should all fail +SELECT CONVERT(TIME, CAST(-2.5 as DECIMAL)) +GO +~~START~~ +time +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type "decimal" to time without time zone)~~ + +SELECT CONVERT(TIME, CAST(-2.5 as NUMERIC(30,8))) +GO +~~START~~ +time +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type numeric to time without time zone)~~ + +SELECT CONVERT(TIME, CAST(-2.5 as FLOAT)) +GO +~~START~~ +time +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type double precision to time without time zone)~~ + +SELECT CONVERT(TIME, CAST(-2.5 as REAL)) +GO +~~START~~ +time +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type real to time without time zone)~~ + +SELECT CONVERT(TIME, CAST(-2.5 as INT)) +GO +~~START~~ +time +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type integer to time without time zone)~~ + +SELECT CONVERT(TIME, CAST(-2.5 as BIGINT)) +GO +~~START~~ +time +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type bigint to time without time zone)~~ + +SELECT CONVERT(TIME, CAST(-2.5 as SMALLINT)) +GO +~~START~~ +time +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type smallint to time without time zone)~~ + +SELECT CONVERT(TIME, CAST(-2.5 as MONEY)) +GO +~~START~~ +time +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type money to time without time zone)~~ + +SELECT CONVERT(TIME, CAST(-2.5 as SMALLMONEY)) +GO +~~START~~ +time +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot cast type smallmoney to time without time zone)~~ + CREATE VIEW Datetime_view5 as ( SELECT - DATEADD(minute, CAST(1 as DECIMAL), CAST(2.5 as DECIMAL)) as re1, - DATEADD(minute, CAST(1 as NUMERIC(30,8)), CAST(2.5 as NUMERIC(30,8))) as re2, - DATEADD(minute, CAST(1 as FLOAT), CAST(2.5 as FLOAT)) as re3, - DATEADD(minute, CAST(1 as REAL), CAST(2.5 as REAL)) as re4, - DATEADD(minute, CAST(1 as INT), CAST(2.5 as INT)) as re5, - DATEADD(minute, CAST(1 as BIGINT), CAST(2.5 as BIGINT)) as re6, - DATEADD(minute, CAST(1 as SMALLINT), CAST(2.5 as SMALLINT)) as re7, - DATEADD(minute, CAST(1 as TINYINT), CAST(2.5 as TINYINT)) as re8, - DATEADD(minute, CAST(1 as MONEY), CAST(2.5 as MONEY)) as re9, - DATEADD(minute, CAST(1 as SMALLMONEY), CAST(2.5 as SMALLMONEY)) as re10, - DATEADD(minute, CAST(-1 as DECIMAL), CAST(-2.5 as DECIMAL)) as re11, - DATEADD(minute, CAST(-1 as NUMERIC(30,8)), CAST(-2.5 as NUMERIC(30,8))) as re12, - DATEADD(minute, CAST(-1 as FLOAT), CAST(-2.5 as FLOAT)) as re13, - DATEADD(minute, CAST(-1 as REAL), CAST(-2.5 as REAL)) as re14, - DATEADD(minute, CAST(-1 as INT), CAST(-2.5 as INT)) as re15, - DATEADD(minute, CAST(-1 as BIGINT), CAST(-2.5 as BIGINT)) as re16, - DATEADD(minute, CAST(-1 as SMALLINT), CAST(-2.5 as SMALLINT)) as re17, - DATEADD(minute, CAST(-1 as MONEY), CAST(-2.5 as MONEY)) as re18, - DATEADD(minute, CAST(-1 as SMALLMONEY), CAST(-2.5 as SMALLMONEY)) as re19 + DATEADD(minute, 1, CAST(2.5 as DECIMAL)) as re1, + DATEADD(minute, 1, CAST(2.5 as NUMERIC(30,8))) as re2, + DATEADD(minute, 1, CAST(2.5 as FLOAT)) as re3, + DATEADD(minute, 1, CAST(2.5 as REAL)) as re4, + DATEADD(minute, 1, CAST(2.5 as INT)) as re5, + DATEADD(minute, 1, CAST(2.5 as BIGINT)) as re6, + DATEADD(minute, 1, CAST(2.5 as SMALLINT)) as re7, + DATEADD(minute, 1, CAST(2.5 as TINYINT)) as re8, + DATEADD(minute, 1, CAST(2.5 as MONEY)) as re9, + DATEADD(minute, 1, CAST(2.5 as SMALLMONEY)) as re10, + DATEADD(minute, 1, CAST(-2.5 as BIT)) as re11, + DATEADD(minute, 1, CAST(-2.5 as DECIMAL)) as re12, + DATEADD(minute, 1, CAST(-2.5 as NUMERIC(30,8))) as re13, + DATEADD(minute, 1, CAST(-2.5 as FLOAT)) as re14, + DATEADD(minute, 1, CAST(-2.5 as REAL)) as re15, + DATEADD(minute, 1, CAST(-2.5 as INT)) as re16, + DATEADD(minute, 1, CAST(-2.5 as BIGINT)) as re17, + DATEADD(minute, 1, CAST(-2.5 as SMALLINT)) as re18, + DATEADD(minute, 1, CAST(-2.5 as MONEY)) as re19, + DATEADD(minute, 1, CAST(-2.5 as SMALLMONEY)) as re20, + DATEADD(minute, 1, CAST(-2.5 as BIT)) as re21 +); +GO + +CREATE VIEW Datetime_view7 as ( + SELECT + DATENAME(day, CAST(2.5 as DECIMAL)) as re1, + DATENAME(day, CAST(2.5 as NUMERIC(30,8))) as re2, + DATENAME(day, CAST(2.5 as FLOAT)) as re3, + DATENAME(day, CAST(2.5 as REAL)) as re4, + DATENAME(day, CAST(2.5 as INT)) as re5, + DATENAME(day, CAST(2.5 as BIGINT)) as re6, + DATENAME(day, CAST(2.5 as SMALLINT)) as re7, + DATENAME(day, CAST(2.5 as TINYINT)) as re8, + DATENAME(day, CAST(2.5 as MONEY)) as re9, + DATENAME(day, CAST(2.5 as SMALLMONEY)) as re10, + DATENAME(day, CAST(2.5 as BIT)) as re11, + DATENAME(day, CAST(-2.5 as DECIMAL)) as re12, + DATENAME(day, CAST(-2.5 as NUMERIC(30,8))) as re13, + DATENAME(day, CAST(-2.5 as FLOAT)) as re14, + DATENAME(day, CAST(-2.5 as REAL)) as re15, + DATENAME(day, CAST(-2.5 as INT)) as re16, + DATENAME(day, CAST(-2.5 as BIGINT)) as re17, + DATENAME(day, CAST(-2.5 as SMALLINT)) as re18, + DATENAME(day, CAST(-2.5 as MONEY)) as re19, + DATENAME(day, CAST(-2.5 as SMALLMONEY)) as re20, + DATENAME(day, CAST(-2.5 as BIT)) as re21 +); +GO + +CREATE VIEW Datetime_view8 as ( + SELECT + DATEPART(day, CAST(2.5 as DECIMAL)) as re1, + DATEPART(day, CAST(2.5 as NUMERIC(30,8))) as re2, + DATEPART(day, CAST(2.5 as FLOAT)) as re3, + DATEPART(day, CAST(2.5 as REAL)) as re4, + DATEPART(day, CAST(2.5 as INT)) as re5, + DATEPART(day, CAST(2.5 as BIGINT)) as re6, + DATEPART(day, CAST(2.5 as SMALLINT)) as re7, + DATEPART(day, CAST(2.5 as TINYINT)) as re8, + DATEPART(day, CAST(2.5 as MONEY)) as re9, + DATEPART(day, CAST(2.5 as SMALLMONEY)) as re10, + DATEPART(day, CAST(2.5 as BIT)) as re11, + DATEPART(day, CAST(-2.5 as DECIMAL)) as re12, + DATEPART(day, CAST(-2.5 as NUMERIC(30,8))) as re13, + DATEPART(day, CAST(-2.5 as FLOAT)) as re14, + DATEPART(day, CAST(-2.5 as REAL)) as re15, + DATEPART(day, CAST(-2.5 as INT)) as re16, + DATEPART(day, CAST(-2.5 as BIGINT)) as re17, + DATEPART(day, CAST(-2.5 as SMALLINT)) as re18, + DATEPART(day, CAST(-2.5 as MONEY)) as re19, + DATEPART(day, CAST(-2.5 as SMALLMONEY)) as re20, + DATEPART(day, CAST(-2.5 as BIT)) as re21 ); GO diff --git a/test/JDBC/expected/TestDatetime-numeric-dateaddfunction-vu-verify.out b/test/JDBC/expected/TestDatetime-numeric-dateaddfunction-vu-verify.out index 37aabe2233..56817beab8 100644 --- a/test/JDBC/expected/TestDatetime-numeric-dateaddfunction-vu-verify.out +++ b/test/JDBC/expected/TestDatetime-numeric-dateaddfunction-vu-verify.out @@ -22,24 +22,40 @@ smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!# DROP VIEW Datetime_view4 GO --- Should throw ERROR : Argument data type bit is invalid for argument 2 of dateadd function. -SELECT DATEADD(minute, CAST(1 as BIT), CAST(2.5 as BIT)) +-- output from SQL Server : +-- 1900-01-04 00:01:00.000 1900-01-03 12:01:00.000 1900-01-03 12:01:00.000 1900-01-03 12:01:00.000 1900-01-03 00:01:00.000 1900-01-03 00:01:00.000 1900-01-03 00:01:00.000 1900-01-03 00:01:00.000 1900-01-03 12:01:00.000 1900-01-03 12:01:00.000 1899-12-28 23:59:00.000 1899-12-29 11:59:00.000 1899-12-29 11:59:00.000 1899-12-29 11:59:00.000 1899-12-29 23:59:00.000 1899-12-29 23:59:00.000 1899-12-29 23:59:00.000 1899-12-29 11:59:00.000 1899-12-29 11:59:00.000 +SELECT * FROM Datetime_view5 +GO +~~START~~ +datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime +1900-01-04 00:01:00.0#!#1900-01-03 12:01:00.0#!#1900-01-03 12:01:00.0#!#1900-01-03 12:01:00.0#!#1900-01-03 00:01:00.0#!#1900-01-03 00:01:00.0#!#1900-01-03 00:01:00.0#!#1900-01-03 00:01:00.0#!#1900-01-03 12:01:00.0#!#1900-01-03 12:01:00.0#!#1900-01-02 00:01:00.0#!#1899-12-29 00:01:00.0#!#1899-12-29 12:01:00.0#!#1899-12-29 12:01:00.0#!#1899-12-29 12:01:00.0#!#1899-12-30 00:01:00.0#!#1899-12-30 00:01:00.0#!#1899-12-30 00:01:00.0#!#1899-12-29 12:01:00.0#!#1899-12-29 12:01:00.0#!#1900-01-02 00:01:00.0 +~~END~~ + +DROP VIEW Datetime_view5 GO -~~ERROR (Code: 33557097)~~ -~~ERROR (Message: Argument data type bit is invalid for argument 2 of dateadd function.)~~ +-- output from SQL Server : +-- 4 3 3 3 3 3 3 3 3 3 2 29 29 29 29 30 30 30 29 29 2 +SELECT * FROM Datetime_view7 +GO +~~START~~ +text#!#text#!#text#!#text#!#text#!#text#!#text#!#text#!#text#!#text#!#text#!#text#!#text#!#text#!#text#!#text#!#text#!#text#!#text#!#text#!#text +4#!#3#!#3#!#3#!#3#!#3#!#3#!#3#!#3#!#3#!#2#!#29#!#29#!#29#!#29#!#30#!#30#!#30#!#29#!#29#!#2 +~~END~~ +DROP VIEW Datetime_view7 +GO -- output from SQL Server : --- 1900-01-04 00:01:00.000 1900-01-03 12:01:00.000 1900-01-03 12:01:00.000 1900-01-03 12:01:00.000 1900-01-03 00:01:00.000 1900-01-03 00:01:00.000 1900-01-03 00:01:00.000 1900-01-03 00:01:00.000 1900-01-03 12:01:00.000 1900-01-03 12:01:00.000 1899-12-28 23:59:00.000 1899-12-29 11:59:00.000 1899-12-29 11:59:00.000 1899-12-29 11:59:00.000 1899-12-29 23:59:00.000 1899-12-29 23:59:00.000 1899-12-29 23:59:00.000 1899-12-29 11:59:00.000 1899-12-29 11:59:00.000 -SELECT * FROM Datetime_view5 +-- 4 3 3 3 3 3 3 3 3 3 2 29 29 29 29 30 30 30 29 29 2 +SELECT * FROM Datetime_view8 GO ~~START~~ -datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime -1900-01-04 00:01:00.0#!#1900-01-03 12:01:00.0#!#1900-01-03 12:01:00.0#!#1900-01-03 12:01:00.0#!#1900-01-03 00:01:00.0#!#1900-01-03 00:01:00.0#!#1900-01-03 00:01:00.0#!#1900-01-03 00:01:00.0#!#1900-01-03 12:01:00.0#!#1900-01-03 12:01:00.0#!#1899-12-28 23:59:00.0#!#1899-12-29 11:59:00.0#!#1899-12-29 11:59:00.0#!#1899-12-29 11:59:00.0#!#1899-12-29 23:59:00.0#!#1899-12-29 23:59:00.0#!#1899-12-29 23:59:00.0#!#1899-12-29 11:59:00.0#!#1899-12-29 11:59:00.0 +int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int +4#!#3#!#3#!#3#!#3#!#3#!#3#!#3#!#3#!#3#!#2#!#29#!#29#!#29#!#29#!#30#!#30#!#30#!#29#!#29#!#2 ~~END~~ -DROP VIEW Datetime_view5 +DROP VIEW Datetime_view8 GO -- Procedures @@ -261,9 +277,10 @@ GO SELECT * FROM dateadd_view_4 GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: Argument data type bit is invalid for argument 2 of dateadd function.)~~ +~~START~~ +datetime +1901-01-02 00:00:00.0 +~~END~~ DROP VIEW dateadd_view_4 diff --git a/test/JDBC/input/datatypes/TestDatetime-numeric-dateaddfunction-vu-prepare.sql b/test/JDBC/input/datatypes/TestDatetime-numeric-dateaddfunction-vu-prepare.sql index 10f6f41e0f..477cbfe71c 100644 --- a/test/JDBC/input/datatypes/TestDatetime-numeric-dateaddfunction-vu-prepare.sql +++ b/test/JDBC/input/datatypes/TestDatetime-numeric-dateaddfunction-vu-prepare.sql @@ -65,28 +65,161 @@ GO SELECT CONVERT(SMALLDATETIME, CAST(-2.5 as SMALLMONEY)) GO +-- Should all fail +SELECT CONVERT(DATETIME2, CAST(-2.5 as DECIMAL)) +GO +SELECT CONVERT(DATETIME2, CAST(-2.5 as NUMERIC(30,8))) +GO +SELECT CONVERT(DATETIME2, CAST(-2.5 as FLOAT)) +GO +SELECT CONVERT(DATETIME2, CAST(-2.5 as REAL)) +GO +SELECT CONVERT(DATETIME2, CAST(-2.5 as INT)) +GO +SELECT CONVERT(DATETIME2, CAST(-2.5 as BIGINT)) +GO +SELECT CONVERT(DATETIME2, CAST(-2.5 as SMALLINT)) +GO +SELECT CONVERT(DATETIME2, CAST(-2.5 as MONEY)) +GO +SELECT CONVERT(DATETIME2, CAST(-2.5 as SMALLMONEY)) +GO + +-- Should all fail +SELECT CONVERT(DATETIMEOFFSET, CAST(-2.5 as DECIMAL)) +GO +SELECT CONVERT(DATETIMEOFFSET, CAST(-2.5 as NUMERIC(30,8))) +GO +SELECT CONVERT(DATETIMEOFFSET, CAST(-2.5 as FLOAT)) +GO +SELECT CONVERT(DATETIMEOFFSET, CAST(-2.5 as REAL)) +GO +SELECT CONVERT(DATETIMEOFFSET, CAST(-2.5 as INT)) +GO +SELECT CONVERT(DATETIMEOFFSET, CAST(-2.5 as BIGINT)) +GO +SELECT CONVERT(DATETIMEOFFSET, CAST(-2.5 as SMALLINT)) +GO +SELECT CONVERT(DATETIMEOFFSET, CAST(-2.5 as MONEY)) +GO +SELECT CONVERT(DATETIMEOFFSET, CAST(-2.5 as SMALLMONEY)) +GO + +-- Should all fail +SELECT CONVERT(DATE, CAST(-2.5 as DECIMAL)) +GO +SELECT CONVERT(DATE, CAST(-2.5 as NUMERIC(30,8))) +GO +SELECT CONVERT(DATE, CAST(-2.5 as FLOAT)) +GO +SELECT CONVERT(DATE, CAST(-2.5 as REAL)) +GO +SELECT CONVERT(DATE, CAST(-2.5 as INT)) +GO +SELECT CONVERT(DATE, CAST(-2.5 as BIGINT)) +GO +SELECT CONVERT(DATE, CAST(-2.5 as SMALLINT)) +GO +SELECT CONVERT(DATE, CAST(-2.5 as MONEY)) +GO +SELECT CONVERT(DATE, CAST(-2.5 as SMALLMONEY)) +GO + +-- Should all fail +SELECT CONVERT(TIME, CAST(-2.5 as DECIMAL)) +GO +SELECT CONVERT(TIME, CAST(-2.5 as NUMERIC(30,8))) +GO +SELECT CONVERT(TIME, CAST(-2.5 as FLOAT)) +GO +SELECT CONVERT(TIME, CAST(-2.5 as REAL)) +GO +SELECT CONVERT(TIME, CAST(-2.5 as INT)) +GO +SELECT CONVERT(TIME, CAST(-2.5 as BIGINT)) +GO +SELECT CONVERT(TIME, CAST(-2.5 as SMALLINT)) +GO +SELECT CONVERT(TIME, CAST(-2.5 as MONEY)) +GO +SELECT CONVERT(TIME, CAST(-2.5 as SMALLMONEY)) +GO CREATE VIEW Datetime_view5 as ( SELECT - DATEADD(minute, CAST(1 as DECIMAL), CAST(2.5 as DECIMAL)) as re1, - DATEADD(minute, CAST(1 as NUMERIC(30,8)), CAST(2.5 as NUMERIC(30,8))) as re2, - DATEADD(minute, CAST(1 as FLOAT), CAST(2.5 as FLOAT)) as re3, - DATEADD(minute, CAST(1 as REAL), CAST(2.5 as REAL)) as re4, - DATEADD(minute, CAST(1 as INT), CAST(2.5 as INT)) as re5, - DATEADD(minute, CAST(1 as BIGINT), CAST(2.5 as BIGINT)) as re6, - DATEADD(minute, CAST(1 as SMALLINT), CAST(2.5 as SMALLINT)) as re7, - DATEADD(minute, CAST(1 as TINYINT), CAST(2.5 as TINYINT)) as re8, - DATEADD(minute, CAST(1 as MONEY), CAST(2.5 as MONEY)) as re9, - DATEADD(minute, CAST(1 as SMALLMONEY), CAST(2.5 as SMALLMONEY)) as re10, - DATEADD(minute, CAST(-1 as DECIMAL), CAST(-2.5 as DECIMAL)) as re11, - DATEADD(minute, CAST(-1 as NUMERIC(30,8)), CAST(-2.5 as NUMERIC(30,8))) as re12, - DATEADD(minute, CAST(-1 as FLOAT), CAST(-2.5 as FLOAT)) as re13, - DATEADD(minute, CAST(-1 as REAL), CAST(-2.5 as REAL)) as re14, - DATEADD(minute, CAST(-1 as INT), CAST(-2.5 as INT)) as re15, - DATEADD(minute, CAST(-1 as BIGINT), CAST(-2.5 as BIGINT)) as re16, - DATEADD(minute, CAST(-1 as SMALLINT), CAST(-2.5 as SMALLINT)) as re17, - DATEADD(minute, CAST(-1 as MONEY), CAST(-2.5 as MONEY)) as re18, - DATEADD(minute, CAST(-1 as SMALLMONEY), CAST(-2.5 as SMALLMONEY)) as re19 + DATEADD(minute, 1, CAST(2.5 as DECIMAL)) as re1, + DATEADD(minute, 1, CAST(2.5 as NUMERIC(30,8))) as re2, + DATEADD(minute, 1, CAST(2.5 as FLOAT)) as re3, + DATEADD(minute, 1, CAST(2.5 as REAL)) as re4, + DATEADD(minute, 1, CAST(2.5 as INT)) as re5, + DATEADD(minute, 1, CAST(2.5 as BIGINT)) as re6, + DATEADD(minute, 1, CAST(2.5 as SMALLINT)) as re7, + DATEADD(minute, 1, CAST(2.5 as TINYINT)) as re8, + DATEADD(minute, 1, CAST(2.5 as MONEY)) as re9, + DATEADD(minute, 1, CAST(2.5 as SMALLMONEY)) as re10, + DATEADD(minute, 1, CAST(-2.5 as BIT)) as re11, + DATEADD(minute, 1, CAST(-2.5 as DECIMAL)) as re12, + DATEADD(minute, 1, CAST(-2.5 as NUMERIC(30,8))) as re13, + DATEADD(minute, 1, CAST(-2.5 as FLOAT)) as re14, + DATEADD(minute, 1, CAST(-2.5 as REAL)) as re15, + DATEADD(minute, 1, CAST(-2.5 as INT)) as re16, + DATEADD(minute, 1, CAST(-2.5 as BIGINT)) as re17, + DATEADD(minute, 1, CAST(-2.5 as SMALLINT)) as re18, + DATEADD(minute, 1, CAST(-2.5 as MONEY)) as re19, + DATEADD(minute, 1, CAST(-2.5 as SMALLMONEY)) as re20, + DATEADD(minute, 1, CAST(-2.5 as BIT)) as re21 +); +GO + +CREATE VIEW Datetime_view7 as ( + SELECT + DATENAME(day, CAST(2.5 as DECIMAL)) as re1, + DATENAME(day, CAST(2.5 as NUMERIC(30,8))) as re2, + DATENAME(day, CAST(2.5 as FLOAT)) as re3, + DATENAME(day, CAST(2.5 as REAL)) as re4, + DATENAME(day, CAST(2.5 as INT)) as re5, + DATENAME(day, CAST(2.5 as BIGINT)) as re6, + DATENAME(day, CAST(2.5 as SMALLINT)) as re7, + DATENAME(day, CAST(2.5 as TINYINT)) as re8, + DATENAME(day, CAST(2.5 as MONEY)) as re9, + DATENAME(day, CAST(2.5 as SMALLMONEY)) as re10, + DATENAME(day, CAST(2.5 as BIT)) as re11, + DATENAME(day, CAST(-2.5 as DECIMAL)) as re12, + DATENAME(day, CAST(-2.5 as NUMERIC(30,8))) as re13, + DATENAME(day, CAST(-2.5 as FLOAT)) as re14, + DATENAME(day, CAST(-2.5 as REAL)) as re15, + DATENAME(day, CAST(-2.5 as INT)) as re16, + DATENAME(day, CAST(-2.5 as BIGINT)) as re17, + DATENAME(day, CAST(-2.5 as SMALLINT)) as re18, + DATENAME(day, CAST(-2.5 as MONEY)) as re19, + DATENAME(day, CAST(-2.5 as SMALLMONEY)) as re20, + DATENAME(day, CAST(-2.5 as BIT)) as re21 +); +GO + +CREATE VIEW Datetime_view8 as ( + SELECT + DATEPART(day, CAST(2.5 as DECIMAL)) as re1, + DATEPART(day, CAST(2.5 as NUMERIC(30,8))) as re2, + DATEPART(day, CAST(2.5 as FLOAT)) as re3, + DATEPART(day, CAST(2.5 as REAL)) as re4, + DATEPART(day, CAST(2.5 as INT)) as re5, + DATEPART(day, CAST(2.5 as BIGINT)) as re6, + DATEPART(day, CAST(2.5 as SMALLINT)) as re7, + DATEPART(day, CAST(2.5 as TINYINT)) as re8, + DATEPART(day, CAST(2.5 as MONEY)) as re9, + DATEPART(day, CAST(2.5 as SMALLMONEY)) as re10, + DATEPART(day, CAST(2.5 as BIT)) as re11, + DATEPART(day, CAST(-2.5 as DECIMAL)) as re12, + DATEPART(day, CAST(-2.5 as NUMERIC(30,8))) as re13, + DATEPART(day, CAST(-2.5 as FLOAT)) as re14, + DATEPART(day, CAST(-2.5 as REAL)) as re15, + DATEPART(day, CAST(-2.5 as INT)) as re16, + DATEPART(day, CAST(-2.5 as BIGINT)) as re17, + DATEPART(day, CAST(-2.5 as SMALLINT)) as re18, + DATEPART(day, CAST(-2.5 as MONEY)) as re19, + DATEPART(day, CAST(-2.5 as SMALLMONEY)) as re20, + DATEPART(day, CAST(-2.5 as BIT)) as re21 ); GO diff --git a/test/JDBC/input/datatypes/TestDatetime-numeric-dateaddfunction-vu-verify.sql b/test/JDBC/input/datatypes/TestDatetime-numeric-dateaddfunction-vu-verify.sql index d2c26c069d..b5e047af3e 100644 --- a/test/JDBC/input/datatypes/TestDatetime-numeric-dateaddfunction-vu-verify.sql +++ b/test/JDBC/input/datatypes/TestDatetime-numeric-dateaddfunction-vu-verify.sql @@ -12,10 +12,6 @@ GO DROP VIEW Datetime_view4 GO --- Should throw ERROR : Argument data type bit is invalid for argument 2 of dateadd function. -SELECT DATEADD(minute, CAST(1 as BIT), CAST(2.5 as BIT)) -GO - -- output from SQL Server : -- 1900-01-04 00:01:00.000 1900-01-03 12:01:00.000 1900-01-03 12:01:00.000 1900-01-03 12:01:00.000 1900-01-03 00:01:00.000 1900-01-03 00:01:00.000 1900-01-03 00:01:00.000 1900-01-03 00:01:00.000 1900-01-03 12:01:00.000 1900-01-03 12:01:00.000 1899-12-28 23:59:00.000 1899-12-29 11:59:00.000 1899-12-29 11:59:00.000 1899-12-29 11:59:00.000 1899-12-29 23:59:00.000 1899-12-29 23:59:00.000 1899-12-29 23:59:00.000 1899-12-29 11:59:00.000 1899-12-29 11:59:00.000 SELECT * FROM Datetime_view5 @@ -23,6 +19,20 @@ GO DROP VIEW Datetime_view5 GO +-- output from SQL Server : +-- 4 3 3 3 3 3 3 3 3 3 2 29 29 29 29 30 30 30 29 29 2 +SELECT * FROM Datetime_view7 +GO +DROP VIEW Datetime_view7 +GO + +-- output from SQL Server : +-- 4 3 3 3 3 3 3 3 3 3 2 29 29 29 29 30 30 30 29 29 2 +SELECT * FROM Datetime_view8 +GO +DROP VIEW Datetime_view8 +GO + -- Procedures EXEC Datetime_proc1 '1900-01-02 00:00:00', 3.1 GO From e47f0b3d82732ceba64d5633081c0b4b518813c5 Mon Sep 17 00:00:00 2001 From: Deepakshi Mittal <78574784+deepakshi-mittal@users.noreply.github.com> Date: Wed, 26 Apr 2023 10:38:17 -0700 Subject: [PATCH 078/363] Create Syslogins Catalog View in Babelfish (#1469) Task: BABEL-2476 Signed-off-by: Deepakshi Mittal --- contrib/babelfishpg_tsql/sql/ownership.sql | 55 +++++++++++++++++ .../babelfishpg_tsql--3.1.0--3.2.0.sql | 55 +++++++++++++++++ .../expected/sys_syslogins_dep-vu-cleanup.out | 20 +++++++ .../expected/sys_syslogins_dep-vu-prepare.out | 32 ++++++++++ .../expected/sys_syslogins_dep-vu-verify.out | 59 +++++++++++++++++++ .../input/sys_syslogins_dep-vu-cleanup.sql | 20 +++++++ .../input/sys_syslogins_dep-vu-prepare.sql | 32 ++++++++++ .../input/sys_syslogins_dep-vu-verify.sql | 31 ++++++++++ test/JDBC/upgrade/latest/schedule | 1 + 9 files changed, 305 insertions(+) create mode 100644 test/JDBC/expected/sys_syslogins_dep-vu-cleanup.out create mode 100644 test/JDBC/expected/sys_syslogins_dep-vu-prepare.out create mode 100644 test/JDBC/expected/sys_syslogins_dep-vu-verify.out create mode 100644 test/JDBC/input/sys_syslogins_dep-vu-cleanup.sql create mode 100644 test/JDBC/input/sys_syslogins_dep-vu-prepare.sql create mode 100644 test/JDBC/input/sys_syslogins_dep-vu-verify.sql diff --git a/contrib/babelfishpg_tsql/sql/ownership.sql b/contrib/babelfishpg_tsql/sql/ownership.sql index d3ec44abd5..f2ac6a7460 100644 --- a/contrib/babelfishpg_tsql/sql/ownership.sql +++ b/contrib/babelfishpg_tsql/sql/ownership.sql @@ -304,6 +304,61 @@ FROM pg_catalog.pg_roles AS Base INNER JOIN sys.babelfish_authid_login_ext AS Ex GRANT SELECT ON sys.server_principals TO PUBLIC; +-- SYSLOGINS +CREATE OR REPLACE VIEW sys.syslogins +AS SELECT +Base.sid AS sid, +CAST(9 AS SYS.TINYINT) AS status, +Base.create_date AS createdate, +Base.modify_date AS updatedate, +Base.create_date AS accdate, +CAST(0 AS INT) AS totcpu, +CAST(0 AS INT) AS totio, +CAST(0 AS INT) AS spacelimit, +CAST(0 AS INT) AS timelimit, +CAST(0 AS INT) AS resultlimit, +Base.name AS name, +Base.default_database_name AS dbname, +Base.default_language_name AS default_language_name, +CAST(Base.name AS SYS.NVARCHAR(128)) AS loginname, +CAST(NULL AS SYS.NVARCHAR(128)) AS password, +CAST(0 AS INT) AS denylogin, +CAST(1 AS INT) AS hasaccess, +CAST( + CASE + WHEN BASE.type_desc = 'WINDOWS_LOGIN' OR BASE.type_desc = 'WINDOWS_GROUP' THEN 1 + ELSE 0 + END +AS INT) AS isntname, +CAST( + CASE + WHEN BASE.type_desc = 'WINDOWS_GROUP' THEN 1 + ELSE 0 + END + AS INT) AS isntgroup, +CAST( + CASE + WHEN BASE.type_desc = 'WINDOWS_LOGIN' THEN 1 + ELSE 0 + END +AS INT) AS isntuser, +CAST( + CASE + WHEN pg_has_role(CAST('sysadmin' AS TEXT), Base.principal_id , 'MEMBER') = true THEN 1 + ELSE 0 + END +AS INT) AS sysadmin, +CAST(0 AS INT) AS securityadmin, +CAST(0 AS INT) AS serveradmin, +CAST(0 AS INT) AS setupadmin, +CAST(0 AS INT) AS processadmin, +CAST(0 AS INT) AS diskadmin, +CAST(0 AS INT) AS dbcreator, +CAST(0 AS INT) AS bulkadmin +FROM sys.server_principals AS Base; + +GRANT SELECT ON sys.syslogins TO PUBLIC; + -- USER extension CREATE TABLE sys.babelfish_authid_user_ext ( rolname NAME NOT NULL, diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql index 97521af502..61fd95ae5f 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql @@ -1680,6 +1680,61 @@ FROM (VALUES ('public', 'R'), ('sys', 'S'), ('INFORMATION_SCHEMA', 'S')) as dumm GRANT SELECT ON sys.database_principals TO PUBLIC; CALL sys.babelfish_drop_deprecated_object('view', 'sys', 'database_principals_deprecated_3_2_0'); +-- SYSLOGINS +CREATE OR REPLACE VIEW sys.syslogins +AS SELECT +Base.sid AS sid, +CAST(9 AS SYS.TINYINT) AS status, +Base.create_date AS createdate, +Base.modify_date AS updatedate, +Base.create_date AS accdate, +CAST(0 AS INT) AS totcpu, +CAST(0 AS INT) AS totio, +CAST(0 AS INT) AS spacelimit, +CAST(0 AS INT) AS timelimit, +CAST(0 AS INT) AS resultlimit, +Base.name AS name, +Base.default_database_name AS dbname, +Base.default_language_name AS default_language_name, +CAST(Base.name AS SYS.NVARCHAR(128)) AS loginname, +CAST(NULL AS SYS.NVARCHAR(128)) AS password, +CAST(0 AS INT) AS denylogin, +CAST(1 AS INT) AS hasaccess, +CAST( + CASE + WHEN BASE.type_desc = 'WINDOWS_LOGIN' OR BASE.type_desc = 'WINDOWS_GROUP' THEN 1 + ELSE 0 + END +AS INT) AS isntname, +CAST( + CASE + WHEN BASE.type_desc = 'WINDOWS_GROUP' THEN 1 + ELSE 0 + END + AS INT) AS isntgroup, +CAST( + CASE + WHEN BASE.type_desc = 'WINDOWS_LOGIN' THEN 1 + ELSE 0 + END +AS INT) AS isntuser, +CAST( + CASE + WHEN pg_has_role(CAST('sysadmin' AS TEXT), Base.principal_id , 'MEMBER') = true THEN 1 + ELSE 0 + END +AS INT) AS sysadmin, +CAST(0 AS INT) AS securityadmin, +CAST(0 AS INT) AS serveradmin, +CAST(0 AS INT) AS setupadmin, +CAST(0 AS INT) AS processadmin, +CAST(0 AS INT) AS diskadmin, +CAST(0 AS INT) AS dbcreator, +CAST(0 AS INT) AS bulkadmin +FROM sys.server_principals AS Base; + +GRANT SELECT ON sys.syslogins TO PUBLIC; + CREATE OR REPLACE VIEW sys.spt_tablecollations_view AS SELECT o.object_id AS object_id, diff --git a/test/JDBC/expected/sys_syslogins_dep-vu-cleanup.out b/test/JDBC/expected/sys_syslogins_dep-vu-cleanup.out new file mode 100644 index 0000000000..d50fdd126d --- /dev/null +++ b/test/JDBC/expected/sys_syslogins_dep-vu-cleanup.out @@ -0,0 +1,20 @@ +DROP VIEW sys_syslogins_dep_vu_prepare_view +GO + +DROP PROC sys_syslogins_dep_vu_prepare_proc +GO + +DROP FUNCTION sys_syslogins_dep_vu_prepare_func +GO + +DROP LOGIN sys_syslogins_dep_vu_prepare_login1 +GO + +DROP LOGIN sys_syslogins_dep_vu_prepare_login2 +GO + +DROP LOGIN [sysloginsxyz\domain_login1] +GO + +EXEC babelfish_remove_domain_mapping_entry 'sysloginsxyz' +GO diff --git a/test/JDBC/expected/sys_syslogins_dep-vu-prepare.out b/test/JDBC/expected/sys_syslogins_dep-vu-prepare.out new file mode 100644 index 0000000000..bb40443740 --- /dev/null +++ b/test/JDBC/expected/sys_syslogins_dep-vu-prepare.out @@ -0,0 +1,32 @@ +CREATE LOGIN sys_syslogins_dep_vu_prepare_login1 WITH PASSWORD = '12345' +GO + +CREATE LOGIN sys_syslogins_dep_vu_prepare_login2 WITH PASSWORD = '12345' +GO + +CREATE VIEW sys_syslogins_dep_vu_prepare_view +AS +SELECT name,dbname,default_language_name,status,totcpu,totio,spacelimit,timelimit, +resultlimit,loginname,password,denylogin,hasaccess,isntname,isntgroup,isntuser,sysadmin,securityadmin,serveradmin,setupadmin, +processadmin,diskadmin,dbcreator,bulkadmin +FROM sys.syslogins +WHERE name LIKE '%sys_syslogins_dep_vu_prepare%' +ORDER BY name +GO + +CREATE PROC sys_syslogins_dep_vu_prepare_proc +AS +SELECT name,dbname,default_language_name,status,totcpu,totio,spacelimit,timelimit, +resultlimit,loginname,password,denylogin,hasaccess,isntname,isntgroup,isntuser,sysadmin,securityadmin,serveradmin,setupadmin, +processadmin,diskadmin,dbcreator,bulkadmin +FROM sys.syslogins +WHERE name LIKE '%sys_syslogins_dep_vu_prepare%' +ORDER BY name +GO + +CREATE FUNCTION sys_syslogins_dep_vu_prepare_func() +RETURNS INT AS +BEGIN + RETURN (SELECT COUNT(*) FROM sys.syslogins WHERE name LIKE '%sys_syslogins_dep_vu_prepare%') +END +GO diff --git a/test/JDBC/expected/sys_syslogins_dep-vu-verify.out b/test/JDBC/expected/sys_syslogins_dep-vu-verify.out new file mode 100644 index 0000000000..c440e2eacc --- /dev/null +++ b/test/JDBC/expected/sys_syslogins_dep-vu-verify.out @@ -0,0 +1,59 @@ +SELECT * FROM sys_syslogins_dep_vu_prepare_view +GO +~~START~~ +varchar#!#varchar#!#varchar#!#tinyint#!#int#!#int#!#int#!#int#!#int#!#nvarchar#!#nvarchar#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int +sys_syslogins_dep_vu_prepare_login1#!#master#!#English#!#9#!#0#!#0#!#0#!#0#!#0#!#sys_syslogins_dep_vu_prepare_login1#!##!#0#!#1#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0 +sys_syslogins_dep_vu_prepare_login2#!#master#!#English#!#9#!#0#!#0#!#0#!#0#!#0#!#sys_syslogins_dep_vu_prepare_login2#!##!#0#!#1#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0 +~~END~~ + + +EXEC sys_syslogins_dep_vu_prepare_proc +GO +~~START~~ +varchar#!#varchar#!#varchar#!#tinyint#!#int#!#int#!#int#!#int#!#int#!#nvarchar#!#nvarchar#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int +sys_syslogins_dep_vu_prepare_login1#!#master#!#English#!#9#!#0#!#0#!#0#!#0#!#0#!#sys_syslogins_dep_vu_prepare_login1#!##!#0#!#1#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0 +sys_syslogins_dep_vu_prepare_login2#!#master#!#English#!#9#!#0#!#0#!#0#!#0#!#0#!#sys_syslogins_dep_vu_prepare_login2#!##!#0#!#1#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0 +~~END~~ + + +SELECT sys_syslogins_dep_vu_prepare_func() +GO +~~START~~ +int +2 +~~END~~ + + +SELECT name,dbname,default_language_name,status,totcpu,totio,spacelimit,timelimit, +resultlimit,loginname,password,denylogin,hasaccess,isntname,isntgroup,isntuser,sysadmin,securityadmin,serveradmin,setupadmin, +processadmin,diskadmin,dbcreator,bulkadmin +FROM sys.syslogins +WHERE name LIKE 'sys_syslogins_dep_vu_prepare_login%' +ORDER BY name +GO +~~START~~ +varchar#!#varchar#!#varchar#!#tinyint#!#int#!#int#!#int#!#int#!#int#!#nvarchar#!#nvarchar#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int +sys_syslogins_dep_vu_prepare_login1#!#master#!#English#!#9#!#0#!#0#!#0#!#0#!#0#!#sys_syslogins_dep_vu_prepare_login1#!##!#0#!#1#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0 +sys_syslogins_dep_vu_prepare_login2#!#master#!#English#!#9#!#0#!#0#!#0#!#0#!#0#!#sys_syslogins_dep_vu_prepare_login2#!##!#0#!#1#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0 +~~END~~ + + +-- temporary adding next two cases to verify script because of issue with upgrade of babelfish_add_domain_mapping_entry +EXEC sys.babelfish_add_domain_mapping_entry 'sysloginsxyz', 'sysloginsxyz.babel'; +GO + +CREATE LOGIN [sysloginsxyz\domain_login1] FROM WINDOWS; +GO + +SELECT name,dbname,default_language_name,status,totcpu,totio,spacelimit,timelimit, +resultlimit,loginname,password,denylogin,hasaccess,isntname,isntgroup,isntuser,sysadmin,securityadmin,serveradmin,setupadmin, +processadmin,diskadmin,dbcreator,bulkadmin +FROM sys.syslogins +WHERE name = 'sysloginsxyz\domain_login1' +ORDER BY name +GO +~~START~~ +varchar#!#varchar#!#varchar#!#tinyint#!#int#!#int#!#int#!#int#!#int#!#nvarchar#!#nvarchar#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int +sysloginsxyz\domain_login1#!#master#!#English#!#9#!#0#!#0#!#0#!#0#!#0#!#sysloginsxyz\domain_login1#!##!#0#!#1#!#1#!#0#!#1#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0 +~~END~~ + diff --git a/test/JDBC/input/sys_syslogins_dep-vu-cleanup.sql b/test/JDBC/input/sys_syslogins_dep-vu-cleanup.sql new file mode 100644 index 0000000000..87ef1fa6bf --- /dev/null +++ b/test/JDBC/input/sys_syslogins_dep-vu-cleanup.sql @@ -0,0 +1,20 @@ +DROP VIEW sys_syslogins_dep_vu_prepare_view +GO + +DROP PROC sys_syslogins_dep_vu_prepare_proc +GO + +DROP FUNCTION sys_syslogins_dep_vu_prepare_func +GO + +DROP LOGIN sys_syslogins_dep_vu_prepare_login1 +GO + +DROP LOGIN sys_syslogins_dep_vu_prepare_login2 +GO + +DROP LOGIN [sysloginsxyz\domain_login1] +GO + +EXEC babelfish_remove_domain_mapping_entry 'sysloginsxyz' +GO \ No newline at end of file diff --git a/test/JDBC/input/sys_syslogins_dep-vu-prepare.sql b/test/JDBC/input/sys_syslogins_dep-vu-prepare.sql new file mode 100644 index 0000000000..7b0a2dbd75 --- /dev/null +++ b/test/JDBC/input/sys_syslogins_dep-vu-prepare.sql @@ -0,0 +1,32 @@ +CREATE LOGIN sys_syslogins_dep_vu_prepare_login1 WITH PASSWORD = '12345' +GO + +CREATE LOGIN sys_syslogins_dep_vu_prepare_login2 WITH PASSWORD = '12345' +GO + +CREATE VIEW sys_syslogins_dep_vu_prepare_view +AS +SELECT name,dbname,default_language_name,status,totcpu,totio,spacelimit,timelimit, +resultlimit,loginname,password,denylogin,hasaccess,isntname,isntgroup,isntuser,sysadmin,securityadmin,serveradmin,setupadmin, +processadmin,diskadmin,dbcreator,bulkadmin +FROM sys.syslogins +WHERE name LIKE '%sys_syslogins_dep_vu_prepare%' +ORDER BY name +GO + +CREATE PROC sys_syslogins_dep_vu_prepare_proc +AS +SELECT name,dbname,default_language_name,status,totcpu,totio,spacelimit,timelimit, +resultlimit,loginname,password,denylogin,hasaccess,isntname,isntgroup,isntuser,sysadmin,securityadmin,serveradmin,setupadmin, +processadmin,diskadmin,dbcreator,bulkadmin +FROM sys.syslogins +WHERE name LIKE '%sys_syslogins_dep_vu_prepare%' +ORDER BY name +GO + +CREATE FUNCTION sys_syslogins_dep_vu_prepare_func() +RETURNS INT AS +BEGIN + RETURN (SELECT COUNT(*) FROM sys.syslogins WHERE name LIKE '%sys_syslogins_dep_vu_prepare%') +END +GO \ No newline at end of file diff --git a/test/JDBC/input/sys_syslogins_dep-vu-verify.sql b/test/JDBC/input/sys_syslogins_dep-vu-verify.sql new file mode 100644 index 0000000000..65432aa3b1 --- /dev/null +++ b/test/JDBC/input/sys_syslogins_dep-vu-verify.sql @@ -0,0 +1,31 @@ +SELECT * FROM sys_syslogins_dep_vu_prepare_view +GO + +EXEC sys_syslogins_dep_vu_prepare_proc +GO + +SELECT sys_syslogins_dep_vu_prepare_func() +GO + +SELECT name,dbname,default_language_name,status,totcpu,totio,spacelimit,timelimit, +resultlimit,loginname,password,denylogin,hasaccess,isntname,isntgroup,isntuser,sysadmin,securityadmin,serveradmin,setupadmin, +processadmin,diskadmin,dbcreator,bulkadmin +FROM sys.syslogins +WHERE name LIKE 'sys_syslogins_dep_vu_prepare_login%' +ORDER BY name +GO + +-- temporary adding next two cases to verify script because of issue with upgrade of babelfish_add_domain_mapping_entry +EXEC sys.babelfish_add_domain_mapping_entry 'sysloginsxyz', 'sysloginsxyz.babel'; +GO + +CREATE LOGIN [sysloginsxyz\domain_login1] FROM WINDOWS; +GO + +SELECT name,dbname,default_language_name,status,totcpu,totio,spacelimit,timelimit, +resultlimit,loginname,password,denylogin,hasaccess,isntname,isntgroup,isntuser,sysadmin,securityadmin,serveradmin,setupadmin, +processadmin,diskadmin,dbcreator,bulkadmin +FROM sys.syslogins +WHERE name = 'sysloginsxyz\domain_login1' +ORDER BY name +GO \ No newline at end of file diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index 977f64ed92..a7d17a8876 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -263,6 +263,7 @@ sys-database_files sys-database_filestream_options sys-database_mirroring sys_database_principals_dep +sys_syslogins_dep sys-database_recovery_status sys-databases sys-databases-dep From e9a600b12f0047efb98a9e131164e43ce1e09f95 Mon Sep 17 00:00:00 2001 From: Sharu Goel <30777678+thephantomthief@users.noreply.github.com> Date: Thu, 27 Apr 2023 14:59:34 +0530 Subject: [PATCH 079/363] Support four-part object names (#1451) Adding support for referencing remote objects i.e. objects that reside in a remote server using four-part object names. Four-part object names have been implemented by rewriting such references using T-SQL OPENQUERY(). Currently, read-only operations are permitted on objects referenced using a four-part object names. DMLs are not supported yet. Task: BABEL-856 Signed-off-by: Sharu Goel goelshar@amazon.com --- contrib/babelfishpg_tsql/src/linked_servers.c | 16 +- contrib/babelfishpg_tsql/src/tsqlIface.cpp | 57 ++- .../src/tsqlUnsupportedFeatureHandler.cpp | 29 +- test/JDBC/expected/BABEL-2455.out | 7 +- .../expected/four-part-names-vu-cleanup.out | 6 + .../expected/four-part-names-vu-prepare.out | 10 + .../expected/four-part-names-vu-verify.out | 427 ++++++++++++++++++ .../expected/linked_servers-vu-verify.out | 4 +- test/JDBC/input/BABEL-2455.sql | 3 +- .../JDBC/input/four-part-names-vu-cleanup.mix | 6 + .../JDBC/input/four-part-names-vu-prepare.mix | 10 + test/JDBC/input/four-part-names-vu-verify.sql | 219 +++++++++ test/JDBC/input/linked_servers-vu-verify.sql | 4 +- 13 files changed, 762 insertions(+), 36 deletions(-) create mode 100644 test/JDBC/expected/four-part-names-vu-cleanup.out create mode 100644 test/JDBC/expected/four-part-names-vu-prepare.out create mode 100644 test/JDBC/expected/four-part-names-vu-verify.out create mode 100644 test/JDBC/input/four-part-names-vu-cleanup.mix create mode 100644 test/JDBC/input/four-part-names-vu-prepare.mix create mode 100644 test/JDBC/input/four-part-names-vu-verify.sql diff --git a/contrib/babelfishpg_tsql/src/linked_servers.c b/contrib/babelfishpg_tsql/src/linked_servers.c index ef26faa735..9973be1e50 100644 --- a/contrib/babelfishpg_tsql/src/linked_servers.c +++ b/contrib/babelfishpg_tsql/src/linked_servers.c @@ -836,7 +836,7 @@ linked_server_establish_connection(char *servername, LinkedServerProcess * lspro static void getOpenqueryTupdescFromMetadata(char *linked_server, char *query, TupleDesc *tupdesc) { - LinkedServerProcess lsproc; + LinkedServerProcess lsproc = NULL; PG_TRY(); { @@ -1079,8 +1079,11 @@ getOpenqueryTupdescFromMetadata(char *linked_server, char *query, TupleDesc *tup } PG_FINALLY(); { - LINKED_SERVER_DEBUG("LINKED SERVER: (Metadata) - Closing connections to remote server"); - LINKED_SERVER_EXIT(); + if (lsproc) + { + LINKED_SERVER_DEBUG("LINKED SERVER: (Metadata) - Closing connections to remote server"); + LINKED_SERVER_EXIT(); + } } PG_END_TRY(); } @@ -1243,8 +1246,11 @@ openquery_imp(PG_FUNCTION_ARGS) } PG_FINALLY(); { - LINKED_SERVER_DEBUG("LINKED SERVER: (OPENQUERY) - Closing connections to remote server"); - LINKED_SERVER_EXIT(); + if (lsproc) + { + LINKED_SERVER_DEBUG("LINKED SERVER: (OPENQUERY) - Closing connections to remote server"); + LINKED_SERVER_EXIT(); + } if (query) pfree(query); diff --git a/contrib/babelfishpg_tsql/src/tsqlIface.cpp b/contrib/babelfishpg_tsql/src/tsqlIface.cpp index 8b9b3a9278..044f1e0390 100644 --- a/contrib/babelfishpg_tsql/src/tsqlIface.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlIface.cpp @@ -834,18 +834,49 @@ class tsqlCommonMutator : public TSqlParserBaseListener void exitFull_object_name(TSqlParser::Full_object_nameContext *ctx) override { - GetCtxFunc getDatabase = [](TSqlParser::Full_object_nameContext *o) { return o->database; }; - GetCtxFunc getSchema = [](TSqlParser::Full_object_nameContext *o) { return o->schema; }; - std::string rewritten_name = rewrite_object_name_with_omitted_db_and_schema_name(ctx, getDatabase, getSchema); - std::string rewritten_schema_name = rewrite_information_schema_to_information_schema_tsql(ctx, getSchema); - if (!rewritten_name.empty()) - rewritten_query_fragment.emplace(std::make_pair(ctx->start->getStartIndex(), std::make_pair(::getFullText(ctx), rewritten_name))); - if (pltsql_enable_tsql_information_schema && !rewritten_schema_name.empty()) - rewritten_query_fragment.emplace(std::make_pair(ctx->schema->start->getStartIndex(), std::make_pair(::getFullText(ctx->schema), rewritten_schema_name))); + if (ctx->DOT().size() >= 3 && ctx->server) /* server.db.schema.objname */ + { + TSqlParser::IdContext *obj_server = ctx->server; + TSqlParser::IdContext *obj_database = ctx->database; + TSqlParser::IdContext *obj_schema = ctx->schema; + TSqlParser::IdContext *obj_name = ctx->object_name; - // qualified identifier doesn't need delimiter - if (ctx->DOT().empty() && does_object_name_need_delimiter(ctx->object_name)) - rewritten_query_fragment.emplace(std::make_pair(ctx->object_name->start->getStartIndex(), std::make_pair(::getFullText(ctx->object_name), delimit_identifier(ctx->object_name)))); + std::string full_object_name = ::getFullText(ctx); + + std::string server_name_str = getIDName(obj_server->DOUBLE_QUOTE_ID(), obj_server->SQUARE_BRACKET_ID(), obj_server->ID()); + std::string quoted_server_str = std::string("'") + server_name_str + std::string("'"); + + std::string three_part_name = ::getFullText(obj_database) + std::string(".") + ::getFullText(obj_schema) + std::string(".") + ::getFullText(obj_name); + + /* + * When we come across a four-part object name, we will replace it with OPENQUERY(). Currently, + * we only support four-part object names in read-only context. So, a call like: + * + * SELECT col_a, col_b FROM server_name.db_name.schema_name.obj_name + * + * will be re-written as: + * + * SELECT col_a, col_b FROM OPENQUERY('server_name', 'SELECT * FROM db_name.schema_name.obj_name') + */ + std::string str = std::string("OPENQUERY(") + quoted_server_str + std::string(", 'SELECT * FROM ") + three_part_name + std::string("')"); + + rewritten_query_fragment.emplace(std::make_pair(obj_server->start->getStartIndex(), std::make_pair(::getFullText(ctx), str))); + } + else + { + GetCtxFunc getDatabase = [](TSqlParser::Full_object_nameContext *o) { return o->database; }; + GetCtxFunc getSchema = [](TSqlParser::Full_object_nameContext *o) { return o->schema; }; + std::string rewritten_name = rewrite_object_name_with_omitted_db_and_schema_name(ctx, getDatabase, getSchema); + std::string rewritten_schema_name = rewrite_information_schema_to_information_schema_tsql(ctx, getSchema); + if (!rewritten_name.empty()) + rewritten_query_fragment.emplace(std::make_pair(ctx->start->getStartIndex(), std::make_pair(::getFullText(ctx), rewritten_name))); + if (pltsql_enable_tsql_information_schema && !rewritten_schema_name.empty()) + rewritten_query_fragment.emplace(std::make_pair(ctx->schema->start->getStartIndex(), std::make_pair(::getFullText(ctx->schema), rewritten_schema_name))); + + // qualified identifier doesn't need delimiter + if (ctx->DOT().empty() && does_object_name_need_delimiter(ctx->object_name)) + rewritten_query_fragment.emplace(std::make_pair(ctx->object_name->start->getStartIndex(), std::make_pair(::getFullText(ctx->object_name), delimit_identifier(ctx->object_name)))); + } } void exitTable_name(TSqlParser::Table_nameContext *ctx) override @@ -1783,7 +1814,7 @@ class tsqlBuilder : public tsqlCommonMutator void exitFull_object_name(TSqlParser::Full_object_nameContext *ctx) override { - if (ctx && ctx->schema) + if (ctx && (ctx->DOT().size() <= 2) && ctx->schema) { schema_name = stripQuoteFromId(ctx->schema); is_schema_specified = true; @@ -1791,7 +1822,7 @@ class tsqlBuilder : public tsqlCommonMutator else is_schema_specified = false; tsqlCommonMutator::exitFull_object_name(ctx); - if (ctx && ctx->database) + if (ctx && (ctx->DOT().size() <= 2) && ctx->database) { db_name = stripQuoteFromId(ctx->database); diff --git a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp index c284ce9413..f2a97acfac 100644 --- a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp @@ -127,6 +127,7 @@ class TsqlUnsupportedFeatureHandlerImpl : public TsqlUnsupportedFeatureHandler antlrcpp::Any visitInsert_statement(TSqlParser::Insert_statementContext *ctx) override; antlrcpp::Any visitUpdate_statement(TSqlParser::Update_statementContext *ctx) override; antlrcpp::Any visitDelete_statement(TSqlParser::Delete_statementContext *ctx) override; + antlrcpp::Any visitDelete_statement_from(TSqlParser::Delete_statement_fromContext *ctx) override; antlrcpp::Any visitMerge_statement(TSqlParser::Merge_statementContext *ctx) override { handle(INSTR_UNSUPPORTED_TSQL_MERGE, "MERGE", getLineAndPos(ctx)); return visitChildren(ctx); } antlrcpp::Any visitBulk_insert_statement(TSqlParser::Bulk_insert_statementContext *ctx) override; @@ -199,7 +200,6 @@ class TsqlUnsupportedFeatureHandlerImpl : public TsqlUnsupportedFeatureHandler antlrcpp::Any visitFunc_proc_name_schema(TSqlParser::Func_proc_name_schemaContext *ctx) override; antlrcpp::Any visitFunc_proc_name_database_schema(TSqlParser::Func_proc_name_database_schemaContext *ctx) override; antlrcpp::Any visitFunc_proc_name_server_database_schema(TSqlParser::Func_proc_name_server_database_schemaContext *ctx) override; - antlrcpp::Any visitFull_object_name(TSqlParser::Full_object_nameContext *ctx) override; antlrcpp::Any visitId(TSqlParser::IdContext *ctx) override; @@ -1094,6 +1094,10 @@ antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitInsert_statement(TSqlParse { if (ctx->insert_statement_value() && ctx->insert_statement_value()->DEFAULT() && ctx->output_clause()) handle(INSTR_UNSUPPORTED_TSQL_INSERT_STMT_DEFAULT_VALUE, "DEFAULT VALUES with OUTPUT clause", getLineAndPos(ctx->output_clause())); /* backend parser can't handle DEFAULT VALUES with output clause yet */ + + if (ctx->ddl_object() && ctx->ddl_object()->full_object_name() && ctx->ddl_object()->full_object_name()->DOT().size() >= 3 && ctx->ddl_object()->full_object_name()->server) + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "INSERT on a 4-part object name is not yet supported in Babelfish", getLineAndPos(ctx)); + return visitChildren(ctx); } @@ -1102,6 +1106,9 @@ antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitUpdate_statement(TSqlParse if (ctx->CURRENT()) // CURRENT OF handle(INSTR_UNSUPPORTED_TSQL_UPDATE_WHERE_CURRENT_OF, "CURRENT OF", getLineAndPos(ctx->CURRENT())); + if (ctx->ddl_object() && ctx->ddl_object()->full_object_name() && ctx->ddl_object()->full_object_name()->DOT().size() >= 3 && ctx->ddl_object()->full_object_name()->server) + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "UPDATE on a 4-part object name is not yet supported in Babelfish", getLineAndPos(ctx)); + for (auto elem : ctx->update_elem()) { if (elem->DOT()) @@ -1115,7 +1122,17 @@ antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitDelete_statement(TSqlParse { if (ctx->CURRENT()) // CURRENT OF handle(INSTR_UNSUPPORTED_TSQL_DELETE_WHERE_CURRENT_OF, "CURRENT OF", getLineAndPos(ctx->CURRENT())); + + return visitChildren(ctx); +} + +antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl:: visitDelete_statement_from(TSqlParser::Delete_statement_fromContext *ctx) +{ + if (ctx->ddl_object() && ctx->ddl_object()->full_object_name() && ctx->ddl_object()->full_object_name()->DOT().size() >= 3 && ctx->ddl_object()->full_object_name()->server) + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "DELETE on a 4-part object name is not yet supported in Babelfish", getLineAndPos(ctx)); + return visitChildren(ctx); + } antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitBulk_insert_statement(TSqlParser::Bulk_insert_statementContext *ctx) @@ -1358,7 +1375,7 @@ antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitFunc_proc_name_database_sc antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitFunc_proc_name_server_database_schema(TSqlParser::Func_proc_name_server_database_schemaContext *ctx) { if (ctx->DOT().size() >= 3 && ctx->server) /* server.db.schema.funcname */ - throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "Remote object reference with 4-part object name is not currently supported in Babelfish", getLineAndPos(ctx)); + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "Remote procedure/function reference with 4-part object name is not currently supported in Babelfish", getLineAndPos(ctx)); if (ctx->DOT().empty()) { @@ -1369,14 +1386,6 @@ antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitFunc_proc_name_server_data return visitChildren(ctx); } -antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitFull_object_name(TSqlParser::Full_object_nameContext *ctx) -{ - if (ctx->DOT().size() >= 3 && ctx->server) /* server.db.schema.funcname */ - throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "Remote object reference with 4-part object name is not currently supported in Babelfish", getLineAndPos(ctx)); - - return visitChildren(ctx); -} - antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitId(TSqlParser::IdContext *ctx) { if (ctx->DOLLAR_IDENTITY()) diff --git a/test/JDBC/expected/BABEL-2455.out b/test/JDBC/expected/BABEL-2455.out index 9be60385ce..17c0bb6b5d 100644 --- a/test/JDBC/expected/BABEL-2455.out +++ b/test/JDBC/expected/BABEL-2455.out @@ -315,19 +315,20 @@ go ~~ERROR (Message: trigger "s2455.tr2455" does not exist)~~ --- servername (not supported) +-- insert into with servername (not supported) insert into yourserver.master.dbo.t1 values (1); go ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: Remote object reference with 4-part object name is not currently supported in Babelfish)~~ +~~ERROR (Message: INSERT on a 4-part object name is not yet supported in Babelfish)~~ +-- function call with servername (not supported) select yourserver.master.dbo.f1(1); go ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: Remote object reference with 4-part object name is not currently supported in Babelfish)~~ +~~ERROR (Message: Remote procedure/function reference with 4-part object name is not currently supported in Babelfish)~~ -- cleanup diff --git a/test/JDBC/expected/four-part-names-vu-cleanup.out b/test/JDBC/expected/four-part-names-vu-cleanup.out new file mode 100644 index 0000000000..a0aab39a75 --- /dev/null +++ b/test/JDBC/expected/four-part-names-vu-cleanup.out @@ -0,0 +1,6 @@ +EXEC sp_dropserver 'bbf_fpn_server', 'droplogins' +GO + +-- psql +DROP EXTENSION IF EXISTS tds_fdw CASCADE; +GO diff --git a/test/JDBC/expected/four-part-names-vu-prepare.out b/test/JDBC/expected/four-part-names-vu-prepare.out new file mode 100644 index 0000000000..86726ea008 --- /dev/null +++ b/test/JDBC/expected/four-part-names-vu-prepare.out @@ -0,0 +1,10 @@ +-- psql +CREATE EXTENSION IF NOT EXISTS tds_fdw; +GO + +-- tsql +EXEC sp_addlinkedserver @server = N'bbf_fpn_server', @srvproduct=N'', @provider=N'SQLNCLI', @datasrc=N'localhost', @catalog=N'master'; +GO + +EXEC sp_addlinkedsrvlogin @rmtsrvname = 'bbf_fpn_server', @useself = 'FALSE', @rmtuser = 'jdbc_user', @rmtpassword = '12345678'; +GO diff --git a/test/JDBC/expected/four-part-names-vu-verify.out b/test/JDBC/expected/four-part-names-vu-verify.out new file mode 100644 index 0000000000..c13437f6c3 --- /dev/null +++ b/test/JDBC/expected/four-part-names-vu-verify.out @@ -0,0 +1,427 @@ +CREATE TABLE fpn_table (a int, b varchar(10)) +GO + +SELECT * FROM bbf_fpn_server.master.dbo.fpn_table +GO +~~START~~ +int#!#varchar +~~END~~ + + +INSERT INTO fpn_table VALUES (1, 'one') +INSERT INTO fpn_table VALUES (2, 'two') +INSERT INTO fpn_table VALUES (3, 'three') +INSERT INTO fpn_table VALUES (4, 'four') +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +-- server_name.database_name.schema_name.object_name (table) +SELECT a, b FROM bbf_fpn_server.master.dbo.fpn_table +GO +~~START~~ +int#!#varchar +1#!#one +2#!#two +3#!#three +4#!#four +~~END~~ + + +-- server_name.database_name.schema_name.object_name (view) +SELECT * FROM bbf_fpn_server.master.sys.data_spaces +GO +~~START~~ +varchar#!#int#!#char#!#nvarchar#!#bit#!#bit +PRIMARY#!#1#!#FG#!#ROWS_FILEGROUP#!#1#!#0 +~~END~~ + + +-- server_name.database_name..object_name +SELECT a + 1, b FROM bbf_fpn_server.master..fpn_table +GO +~~START~~ +int#!#varchar +2#!#one +3#!#two +4#!#three +5#!#four +~~END~~ + + +-- server_name..schema_name.object_name +SELECT * FROM bbf_fpn_server..sys.data_spaces +GO +~~START~~ +varchar#!#int#!#char#!#nvarchar#!#bit#!#bit +PRIMARY#!#1#!#FG#!#ROWS_FILEGROUP#!#1#!#0 +~~END~~ + + +-- server_name...object_name +SELECT a*2, REVERSE(b) FROM bbf_fpn_server...fpn_table +GO +~~START~~ +int#!#text +2#!#eno +4#!#owt +6#!#eerht +8#!#ruof +~~END~~ + + +-- Invalid server name (Should throw error) +SELECT * FROM invalid_server.master.dbo.fpn_table +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: server "invalid_server" does not exist)~~ + + +-- Invalid database name (Should throw error) +SELECT * FROM bbf_fpn_server.invalid_db.dbo.fpn_table +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: TDS client library error: Msg #: 33557097, Msg state: 1, Msg: database "invalid_db" does not exist. Make sure that the name is entered correctly., Server: BABELFISH, Process: , Line: 1, Level: 16)~~ + + +-- Invalid schema name (Should throw error) +SELECT * FROM bbf_fpn_server.master.invalid_schema.fpn_table +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: TDS client library error: Msg #: 33557097, Msg state: 1, Msg: relation "master_invalid_schema.fpn_table" does not exist, Server: BABELFISH, Process: , Line: 1, Level: 16)~~ + + +-- Invalid object name (Should throw error) +SELECT * FROM bbf_fpn_server.master.dbo.invalid_fpn_table +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: TDS client library error: Msg #: 33557097, Msg state: 1, Msg: relation "master_dbo.invalid_fpn_table" does not exist, Server: BABELFISH, Process: , Line: 1, Level: 16)~~ + + +-- four part object is a procedure (Should throw error) +EXEC bbf_fpn_server.master.dbo.sp_linkedserver +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Remote procedure/function reference with 4-part object name is not currently supported in Babelfish)~~ + + +-- INSERT should not work with four-part object name +INSERT INTO bbf_fpn_server.master.dbo.fpn_table VALUES (5, 'five') +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: INSERT on a 4-part object name is not yet supported in Babelfish)~~ + + +-- UPDATE should not work with four-part object name +UPDATE bbf_fpn_server.master.dbo.fpn_table SET b = 'Update one' WHERE a = 1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: UPDATE on a 4-part object name is not yet supported in Babelfish)~~ + + +-- DELETE should not work with four-part object name +DELETE FROM bbf_fpn_server.master.dbo.fpn_table WHERE a = 1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: DELETE on a 4-part object name is not yet supported in Babelfish)~~ + + +-- CREATE VIEW using four-part names +CREATE VIEW four_part_names_vu_verify_view AS SELECT * FROM bbf_fpn_server.master.dbo.fpn_table +GO + +SELECT * FROM four_part_names_vu_verify_view +GO +~~START~~ +int#!#varchar +1#!#one +2#!#two +3#!#three +4#!#four +~~END~~ + + +-- INSERT INTO ... SELECT +CREATE TABLE fpn_table_insert_into (a int, b varchar(10)) +GO + +INSERT INTO fpn_table_insert_into SELECT * FROM bbf_fpn_server.master.dbo.fpn_table WHERE a < 4 +GO +~~ROW COUNT: 3~~ + + +SELECT * FROM fpn_table_insert_into +GO +~~START~~ +int#!#varchar +1#!#one +2#!#two +3#!#three +~~END~~ + + +-- SELECT INTO +SELECT * INTO fpn_table_select_into FROM bbf_fpn_server.master.dbo.fpn_table +GO + +SELECT * FROM fpn_table_select_into +GO +~~START~~ +int#!#varchar +1#!#one +2#!#two +3#!#three +4#!#four +~~END~~ + + +-- JOIN between local and remote table +SELECT fpn_table.*, t2.* +FROM fpn_table_insert_into fpn_table +LEFT JOIN +bbf_fpn_server.master.dbo.fpn_table t2 +ON fpn_table.a = t2.a +GO +~~START~~ +int#!#varchar#!#int#!#varchar +1#!#one#!#1#!#one +2#!#two#!#2#!#two +3#!#three#!#3#!#three +~~END~~ + + +SELECT fpn_table.a, t2.* +FROM bbf_fpn_server.master.dbo.fpn_table fpn_table +LEFT JOIN +fpn_table_insert_into t2 +ON fpn_table.a = t2.a +GO +~~START~~ +int#!#int#!#varchar +1#!#1#!#one +2#!#2#!#two +3#!#3#!#three +4#!##!# +~~END~~ + + +-- JOIN between two remote tables +SELECT fpn_table.*, t2.a, t2.b +FROM bbf_fpn_server.master.dbo.fpn_table fpn_table +LEFT JOIN +bbf_fpn_server.master.dbo.fpn_table_insert_into t2 +ON fpn_table.a = t2.a +GO +~~START~~ +int#!#varchar#!#int#!#varchar +1#!#one#!#1#!#one +2#!#two#!#2#!#two +3#!#three#!#3#!#three +4#!#four#!##!# +~~END~~ + + +-- UPDATE on local table with JOIN containing remote table +UPDATE Table_A +SET +Table_A.a = Table_B.a + 100, +Table_A.b = Table_B.b + CAST(Table_B.a AS varchar(5)) +FROM +fpn_table_insert_into AS Table_A +INNER JOIN bbf_fpn_server.master.dbo.fpn_table AS Table_B +ON Table_A.a = Table_B.a +WHERE +Table_A.a < 3 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM fpn_table_insert_into +GO +~~START~~ +int#!#varchar +3#!#three +101#!#one1 +102#!#two2 +~~END~~ + + +-- DELETE on local table with JOIN containing remote table +DELETE Table_A +FROM +fpn_table_select_into AS Table_A +INNER JOIN bbf_fpn_server.master.dbo.fpn_table AS Table_B +ON Table_A.a = Table_B.a +WHERE +(Table_A.a + Table_B.a) % 4 = 0 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM fpn_table_select_into +GO +~~START~~ +int#!#varchar +1#!#one +3#!#three +~~END~~ + + +-- In CTE +WITH cte_table_for_fpn (a) +AS +( + SELECT a from bbf_fpn_server.master.dbo.fpn_table +) +SELECT AVG(a) FROM cte_table_for_fpn +GO +~~START~~ +int +2 +~~END~~ + + +-- In Subquery +SELECT * FROM fpn_table_insert_into WHERE a > (SELECT MAX(a) FROM bbf_fpn_server.master.dbo.fpn_table) +GO +~~START~~ +int#!#varchar +101#!#one1 +102#!#two2 +~~END~~ + + +SELECT * FROM fpn_table_select_into WHERE b IN (SELECT b FROM bbf_fpn_server.master.dbo.fpn_table) +GO +~~START~~ +int#!#varchar +1#!#one +3#!#three +~~END~~ + + +-- In Subquery as a column +SELECT a, (SELECT b from bbf_fpn_server.master.dbo.fpn_table where b = t.b) as c +FROM fpn_table_insert_into t +GO +~~START~~ +int#!#varchar +3#!#three +101#!# +102#!# +~~END~~ + + +-- In Correlated subquery +SELECT * FROM fpn_table_insert_into WHERE EXISTS (SELECT * FROM bbf_fpn_server.master.dbo.fpn_table as fpn_table_alias WHERE fpn_table_alias.a = fpn_table_insert_into.a) +GO +~~START~~ +int#!#varchar +3#!#three +~~END~~ + + + +-- Try SQL Injection +-- We cannot directly inject SQL because it will break T-SQL database identifier rules +-- We have to surround the SQL in double quotes ("") or square brackets ([]) if we want to even attempt that +-- All cases should throw an error +-- To allow identifiers be specified with double quotes +SET QUOTED_IDENTIFIER ON +GO + +-- SQL Injection in server name +-- Try to inject SQL such that the final rewritten query looks like: +-- select * from openquery('bbf_fpn_server', 'select * from fpn_table') select * from openquery('bbf_fpn_server', 'select * from master.sys.databases') +-- Will throw error: servername is invalid +select * from [bbf_fpn_server'', ''select * from fpn_table'') select * from openquery(''bbf_fpn_server].master.sys.databases +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: server "bbf_fpn_server', 'select * from fpn_table') select * from openquery('bbf_fpn_server" does not exist)~~ + + +select * from "bbf_fpn_server'', ''select * from fpn_table'') select * from openquery(''bbf_fpn_server".master.sys.databases +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: server "bbf_fpn_server', 'select * from fpn_table') select * from openquery('bbf_fpn_server" does not exist)~~ + + +-- SQL Injection in database name +-- Try to inject SQL such that the final rewritten query looks like: +-- select * from openquery('bbf_fpn_server', 'select * from fpn_table') select * from openquery('bbf_fpn_server', 'select * from master.sys.databases') +-- Will throw error: database name is invalid +select * from bbf_fpn_server.[fpn_table'') select * from openquery(''bbf_fpn_server'', ''select * from master].sys.databases +GO +~~START~~ +varchar#!#int#!#int#!#varbinary#!#datetime#!#tinyint#!#varchar#!#tinyint#!#nvarchar#!#bit#!#bit#!#bit#!#tinyint#!#nvarchar#!#bit#!#bit#!#bit#!#tinyint#!#nvarchar#!#bit#!#tinyint#!#nvarchar#!#tinyint#!#nvarchar#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#uniqueidentifier#!#bit#!#tinyint#!#nvarchar#!#bit#!#bit#!#bit#!#bit#!#uniqueidentifier#!#uniqueidentifier#!#int#!#smallint#!#nvarchar#!#int#!#nvarchar#!#bit#!#bit#!#smallint#!#tinyint#!#nvarchar#!#int#!#int#!#nvarchar#!#bit#!#bit#!#bit#!#bit#!#bit#!#int#!#nvarchar#!#nvarchar#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: TDS client library error: Msg #: 911, Msg state: 1, Msg: database "fpn_table') select * from openq8c86d09e50d4f800f5a8c351ddbe1b23" does not exist, Server: BABELFISH, Process: , Line: 1, Level: 16)~~ + + +select * from bbf_fpn_server."fpn_table'') select * from openquery(''bbf_fpn_server'', ''select * from master".sys.databases +GO +~~START~~ +varchar#!#int#!#int#!#varbinary#!#datetime#!#tinyint#!#varchar#!#tinyint#!#nvarchar#!#bit#!#bit#!#bit#!#tinyint#!#nvarchar#!#bit#!#bit#!#bit#!#tinyint#!#nvarchar#!#bit#!#tinyint#!#nvarchar#!#tinyint#!#nvarchar#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#uniqueidentifier#!#bit#!#tinyint#!#nvarchar#!#bit#!#bit#!#bit#!#bit#!#uniqueidentifier#!#uniqueidentifier#!#int#!#smallint#!#nvarchar#!#int#!#nvarchar#!#bit#!#bit#!#smallint#!#tinyint#!#nvarchar#!#int#!#int#!#nvarchar#!#bit#!#bit#!#bit#!#bit#!#bit#!#int#!#nvarchar#!#nvarchar#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: TDS client library error: Msg #: 911, Msg state: 1, Msg: database "fpn_table') select * from openq8c86d09e50d4f800f5a8c351ddbe1b23" does not exist, Server: BABELFISH, Process: , Line: 1, Level: 16)~~ + + +-- SQL Injection in schema name +-- Try to inject SQL such that the final rewritten query looks like: +-- select * from openquery('bbf_fpn_server', 'select * from master.sys.tables') select * from openquery('bbf_fpn_server', 'select * from master.sys.databases') +-- Will throw error: relation is invalid +select * from bbf_fpn_server.master.[sys.tables'') select * from openquery(''bbf_fpn_server'', ''select * from master.sys].databases +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: TDS client library error: Msg #: 33557097, Msg state: 1, Msg: relation "master_sys.tables') select * fr465ba21cd478dfdbfd9c4c52873fc1ec.databases" does not exist, Server: BABELFISH, Process: , Line: 1, Level: 16)~~ + + +select * from bbf_fpn_server.master."sys.tables'') select * from openquery(''bbf_fpn_server'', ''select * from master.sys".databases +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: TDS client library error: Msg #: 33557097, Msg state: 1, Msg: relation "master_sys.tables') select * fr465ba21cd478dfdbfd9c4c52873fc1ec.databases" does not exist, Server: BABELFISH, Process: , Line: 1, Level: 16)~~ + + +-- SQL Injection in object name +-- Try to inject SQL such that the final rewritten query looks like: +-- select * from openquery('bbf_fpn_server', 'select * from master.sys.tables') select * from openquery('bbf_fpn_server', 'select * from master.sys.databases') +-- Will throw error: relation is invalid +select * from bbf_fpn_server.master.sys.[tables'') select * from openquery(''bbf_fpn_server'', ''select * from master.sys.databases] +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: TDS client library error: Msg #: 33557097, Msg state: 1, Msg: relation "sys.tables') select * from openquer6fae7895a55a5b386bac33a1b4ac3386" does not exist, Server: BABELFISH, Process: , Line: 1, Level: 16)~~ + + +select * from bbf_fpn_server.master.sys."tables'') select * from openquery(''bbf_fpn_server'', ''select * from master.sys.databases" +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: TDS client library error: Msg #: 33557097, Msg state: 1, Msg: relation "sys.tables') select * from openquer6fae7895a55a5b386bac33a1b4ac3386" does not exist, Server: BABELFISH, Process: , Line: 1, Level: 16)~~ + + +DROP TABLE fpn_table_insert_into +DROP TABLE fpn_table_select_into +DROP TABLE fpn_table +DROP VIEW four_part_names_vu_verify_view +GO diff --git a/test/JDBC/expected/linked_servers-vu-verify.out b/test/JDBC/expected/linked_servers-vu-verify.out index 7edff2ab16..c8e2f3fb56 100644 --- a/test/JDBC/expected/linked_servers-vu-verify.out +++ b/test/JDBC/expected/linked_servers-vu-verify.out @@ -59,7 +59,7 @@ mssql_server3#!# SET NOCOUNT ON DECLARE @sp_helplinkedsrvlogin_var table(a sysname, b sysname NULL, c smallint, d sysname NULL) INSERT INTO @sp_helplinkedsrvlogin_var EXEC sp_helplinkedsrvlogin -SELECT * FROM @sp_helplinkedsrvlogin_var WHERE a <> 'bbf_server' +SELECT * FROM @sp_helplinkedsrvlogin_var WHERE a <> 'bbf_server' ORDER BY a SET NOCOUNT OFF GO ~~START~~ @@ -115,7 +115,7 @@ GO SET NOCOUNT ON DECLARE @sp_linkedservers_var table(a sysname, b nvarchar(128), c nvarchar(128), d nvarchar(4000), e nvarchar(4000), f nvarchar(4000), g sysname NULL) INSERT INTO @sp_linkedservers_var EXEC sp_linkedservers -SELECT * FROM @sp_linkedservers_var WHERE a <> 'bbf_server' +SELECT * FROM @sp_linkedservers_var WHERE a <> 'bbf_server' ORDER BY a SET NOCOUNT OFF GO ~~START~~ diff --git a/test/JDBC/input/BABEL-2455.sql b/test/JDBC/input/BABEL-2455.sql index a2d48498e8..c53d34afb6 100644 --- a/test/JDBC/input/BABEL-2455.sql +++ b/test/JDBC/input/BABEL-2455.sql @@ -152,10 +152,11 @@ go DROP TRIGGER .s2455.tr2455; go --- servername (not supported) +-- insert into with servername (not supported) insert into yourserver.master.dbo.t1 values (1); go +-- function call with servername (not supported) select yourserver.master.dbo.f1(1); go diff --git a/test/JDBC/input/four-part-names-vu-cleanup.mix b/test/JDBC/input/four-part-names-vu-cleanup.mix new file mode 100644 index 0000000000..a0aab39a75 --- /dev/null +++ b/test/JDBC/input/four-part-names-vu-cleanup.mix @@ -0,0 +1,6 @@ +EXEC sp_dropserver 'bbf_fpn_server', 'droplogins' +GO + +-- psql +DROP EXTENSION IF EXISTS tds_fdw CASCADE; +GO diff --git a/test/JDBC/input/four-part-names-vu-prepare.mix b/test/JDBC/input/four-part-names-vu-prepare.mix new file mode 100644 index 0000000000..86726ea008 --- /dev/null +++ b/test/JDBC/input/four-part-names-vu-prepare.mix @@ -0,0 +1,10 @@ +-- psql +CREATE EXTENSION IF NOT EXISTS tds_fdw; +GO + +-- tsql +EXEC sp_addlinkedserver @server = N'bbf_fpn_server', @srvproduct=N'', @provider=N'SQLNCLI', @datasrc=N'localhost', @catalog=N'master'; +GO + +EXEC sp_addlinkedsrvlogin @rmtsrvname = 'bbf_fpn_server', @useself = 'FALSE', @rmtuser = 'jdbc_user', @rmtpassword = '12345678'; +GO diff --git a/test/JDBC/input/four-part-names-vu-verify.sql b/test/JDBC/input/four-part-names-vu-verify.sql new file mode 100644 index 0000000000..ed3a8bd76b --- /dev/null +++ b/test/JDBC/input/four-part-names-vu-verify.sql @@ -0,0 +1,219 @@ +CREATE TABLE fpn_table (a int, b varchar(10)) +GO + +SELECT * FROM bbf_fpn_server.master.dbo.fpn_table +GO + +INSERT INTO fpn_table VALUES (1, 'one') +INSERT INTO fpn_table VALUES (2, 'two') +INSERT INTO fpn_table VALUES (3, 'three') +INSERT INTO fpn_table VALUES (4, 'four') +GO + +-- server_name.database_name.schema_name.object_name (table) +SELECT a, b FROM bbf_fpn_server.master.dbo.fpn_table +GO + +-- server_name.database_name.schema_name.object_name (view) +SELECT * FROM bbf_fpn_server.master.sys.data_spaces +GO + +-- server_name.database_name..object_name +SELECT a + 1, b FROM bbf_fpn_server.master..fpn_table +GO + +-- server_name..schema_name.object_name +SELECT * FROM bbf_fpn_server..sys.data_spaces +GO + +-- server_name...object_name +SELECT a*2, REVERSE(b) FROM bbf_fpn_server...fpn_table +GO + +-- Invalid server name (Should throw error) +SELECT * FROM invalid_server.master.dbo.fpn_table +GO + +-- Invalid database name (Should throw error) +SELECT * FROM bbf_fpn_server.invalid_db.dbo.fpn_table +GO + +-- Invalid schema name (Should throw error) +SELECT * FROM bbf_fpn_server.master.invalid_schema.fpn_table +GO + +-- Invalid object name (Should throw error) +SELECT * FROM bbf_fpn_server.master.dbo.invalid_fpn_table +GO + +-- four part object is a procedure (Should throw error) +EXEC bbf_fpn_server.master.dbo.sp_linkedserver +GO + +-- INSERT should not work with four-part object name +INSERT INTO bbf_fpn_server.master.dbo.fpn_table VALUES (5, 'five') +GO + +-- UPDATE should not work with four-part object name +UPDATE bbf_fpn_server.master.dbo.fpn_table SET b = 'Update one' WHERE a = 1 +GO + +-- DELETE should not work with four-part object name +DELETE FROM bbf_fpn_server.master.dbo.fpn_table WHERE a = 1 +GO + +-- CREATE VIEW using four-part names +CREATE VIEW four_part_names_vu_verify_view AS SELECT * FROM bbf_fpn_server.master.dbo.fpn_table +GO + +SELECT * FROM four_part_names_vu_verify_view +GO + +-- INSERT INTO ... SELECT +CREATE TABLE fpn_table_insert_into (a int, b varchar(10)) +GO + +INSERT INTO fpn_table_insert_into SELECT * FROM bbf_fpn_server.master.dbo.fpn_table WHERE a < 4 +GO + +SELECT * FROM fpn_table_insert_into +GO + +-- SELECT INTO +SELECT * INTO fpn_table_select_into FROM bbf_fpn_server.master.dbo.fpn_table +GO + +SELECT * FROM fpn_table_select_into +GO + +-- JOIN between local and remote table +SELECT fpn_table.*, t2.* +FROM fpn_table_insert_into fpn_table +LEFT JOIN +bbf_fpn_server.master.dbo.fpn_table t2 +ON fpn_table.a = t2.a +GO + +SELECT fpn_table.a, t2.* +FROM bbf_fpn_server.master.dbo.fpn_table fpn_table +LEFT JOIN +fpn_table_insert_into t2 +ON fpn_table.a = t2.a +GO + +-- JOIN between two remote tables +SELECT fpn_table.*, t2.a, t2.b +FROM bbf_fpn_server.master.dbo.fpn_table fpn_table +LEFT JOIN +bbf_fpn_server.master.dbo.fpn_table_insert_into t2 +ON fpn_table.a = t2.a +GO + +-- UPDATE on local table with JOIN containing remote table +UPDATE Table_A +SET +Table_A.a = Table_B.a + 100, +Table_A.b = Table_B.b + CAST(Table_B.a AS varchar(5)) +FROM +fpn_table_insert_into AS Table_A +INNER JOIN bbf_fpn_server.master.dbo.fpn_table AS Table_B +ON Table_A.a = Table_B.a +WHERE +Table_A.a < 3 +GO + +SELECT * FROM fpn_table_insert_into +GO + +-- DELETE on local table with JOIN containing remote table +DELETE Table_A +FROM +fpn_table_select_into AS Table_A +INNER JOIN bbf_fpn_server.master.dbo.fpn_table AS Table_B +ON Table_A.a = Table_B.a +WHERE +(Table_A.a + Table_B.a) % 4 = 0 +GO + +SELECT * FROM fpn_table_select_into +GO + +-- In CTE +WITH cte_table_for_fpn (a) +AS +( + SELECT a from bbf_fpn_server.master.dbo.fpn_table +) +SELECT AVG(a) FROM cte_table_for_fpn +GO + +-- In Subquery +SELECT * FROM fpn_table_insert_into WHERE a > (SELECT MAX(a) FROM bbf_fpn_server.master.dbo.fpn_table) +GO + +SELECT * FROM fpn_table_select_into WHERE b IN (SELECT b FROM bbf_fpn_server.master.dbo.fpn_table) +GO + +-- In Subquery as a column +SELECT a, (SELECT b from bbf_fpn_server.master.dbo.fpn_table where b = t.b) as c +FROM fpn_table_insert_into t +GO + +-- In Correlated subquery +SELECT * FROM fpn_table_insert_into WHERE EXISTS (SELECT * FROM bbf_fpn_server.master.dbo.fpn_table as fpn_table_alias WHERE fpn_table_alias.a = fpn_table_insert_into.a) +GO + +-- Try SQL Injection +-- We cannot directly inject SQL because it will break T-SQL database identifier rules +-- We have to surround the SQL in double quotes ("") or square brackets ([]) if we want to even attempt that +-- All cases should throw an error + +-- To allow identifiers be specified with double quotes +SET QUOTED_IDENTIFIER ON +GO + +-- SQL Injection in server name +-- Try to inject SQL such that the final rewritten query looks like: +-- select * from openquery('bbf_fpn_server', 'select * from fpn_table') select * from openquery('bbf_fpn_server', 'select * from master.sys.databases') +-- Will throw error: servername is invalid +select * from [bbf_fpn_server'', ''select * from fpn_table'') select * from openquery(''bbf_fpn_server].master.sys.databases +GO + +select * from "bbf_fpn_server'', ''select * from fpn_table'') select * from openquery(''bbf_fpn_server".master.sys.databases +GO + +-- SQL Injection in database name +-- Try to inject SQL such that the final rewritten query looks like: +-- select * from openquery('bbf_fpn_server', 'select * from fpn_table') select * from openquery('bbf_fpn_server', 'select * from master.sys.databases') +-- Will throw error: database name is invalid +select * from bbf_fpn_server.[fpn_table'') select * from openquery(''bbf_fpn_server'', ''select * from master].sys.databases +GO + +select * from bbf_fpn_server."fpn_table'') select * from openquery(''bbf_fpn_server'', ''select * from master".sys.databases +GO + +-- SQL Injection in schema name +-- Try to inject SQL such that the final rewritten query looks like: +-- select * from openquery('bbf_fpn_server', 'select * from master.sys.tables') select * from openquery('bbf_fpn_server', 'select * from master.sys.databases') +-- Will throw error: relation is invalid +select * from bbf_fpn_server.master.[sys.tables'') select * from openquery(''bbf_fpn_server'', ''select * from master.sys].databases +GO + +select * from bbf_fpn_server.master."sys.tables'') select * from openquery(''bbf_fpn_server'', ''select * from master.sys".databases +GO + +-- SQL Injection in object name +-- Try to inject SQL such that the final rewritten query looks like: +-- select * from openquery('bbf_fpn_server', 'select * from master.sys.tables') select * from openquery('bbf_fpn_server', 'select * from master.sys.databases') +-- Will throw error: relation is invalid +select * from bbf_fpn_server.master.sys.[tables'') select * from openquery(''bbf_fpn_server'', ''select * from master.sys.databases] +GO + +select * from bbf_fpn_server.master.sys."tables'') select * from openquery(''bbf_fpn_server'', ''select * from master.sys.databases" +GO + +DROP TABLE fpn_table_insert_into +DROP TABLE fpn_table_select_into +DROP TABLE fpn_table +DROP VIEW four_part_names_vu_verify_view +GO diff --git a/test/JDBC/input/linked_servers-vu-verify.sql b/test/JDBC/input/linked_servers-vu-verify.sql index 83d55d38d2..5f84d76d79 100644 --- a/test/JDBC/input/linked_servers-vu-verify.sql +++ b/test/JDBC/input/linked_servers-vu-verify.sql @@ -18,7 +18,7 @@ GO SET NOCOUNT ON DECLARE @sp_helplinkedsrvlogin_var table(a sysname, b sysname NULL, c smallint, d sysname NULL) INSERT INTO @sp_helplinkedsrvlogin_var EXEC sp_helplinkedsrvlogin -SELECT * FROM @sp_helplinkedsrvlogin_var WHERE a <> 'bbf_server' +SELECT * FROM @sp_helplinkedsrvlogin_var WHERE a <> 'bbf_server' ORDER BY a SET NOCOUNT OFF GO @@ -45,7 +45,7 @@ GO SET NOCOUNT ON DECLARE @sp_linkedservers_var table(a sysname, b nvarchar(128), c nvarchar(128), d nvarchar(4000), e nvarchar(4000), f nvarchar(4000), g sysname NULL) INSERT INTO @sp_linkedservers_var EXEC sp_linkedservers -SELECT * FROM @sp_linkedservers_var WHERE a <> 'bbf_server' +SELECT * FROM @sp_linkedservers_var WHERE a <> 'bbf_server' ORDER BY a SET NOCOUNT OFF GO From 9539a833dea0151a9ff769b4726998e5cc2290c9 Mon Sep 17 00:00:00 2001 From: Ashish Prasad <56514722+hash-16@users.noreply.github.com> Date: Thu, 27 Apr 2023 21:19:44 +0530 Subject: [PATCH 080/363] Fix test regarding indexes in DDL Test Framework (#1472) Updated a test regarding indexes in the DDL Test Framework. Signed-off-by: Ashish Prasad pashisht@amazon.com --- test/python/expected/pyodbc/ddl_tables_index.out | 2 -- test/python/input/ddl_tables_index.sql | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/test/python/expected/pyodbc/ddl_tables_index.out b/test/python/expected/pyodbc/ddl_tables_index.out index e3756f7087..b432206b1f 100644 --- a/test/python/expected/pyodbc/ddl_tables_index.out +++ b/test/python/expected/pyodbc/ddl_tables_index.out @@ -54,8 +54,6 @@ SET ANSI_NULLS ON SET QUOTED_IDENTIFIER ON CREATE TABLE [dbo].[table_unique]( [a] [int] NOT NULL, - [b] [int] NOT NULL, - [c] [int] NULL, CONSTRAINT [table_unique_a_key] UNIQUE NONCLUSTERED ( [a] diff --git a/test/python/input/ddl_tables_index.sql b/test/python/input/ddl_tables_index.sql index 4e67727d39..1d606d2d07 100644 --- a/test/python/input/ddl_tables_index.sql +++ b/test/python/input/ddl_tables_index.sql @@ -24,7 +24,7 @@ DROP TABLE IF EXISTS test_null GO DROP TABLE IF EXISTS test_upper GO -Create table table_unique (a int NOT NULL UNIQUE , b int NOT NULL,c int ) +Create table table_unique (a int NOT NULL UNIQUE) GO Create table table_primary (a int NOT NULL , b int NOT NULL,c int, PRIMARY KEY(a) ) GO @@ -64,7 +64,7 @@ Create table test_upper(a char, check (upper(a) in ('A','B'))); GO Create index test_index on test_upper(a) GO -Create index test_comp_index on table_unique(a,b) +Create index test_comp_index on table_unique(a) GO --DROP From 81b2fbf70cff435c2b0ad859e2329465ab5b3bdf Mon Sep 17 00:00:00 2001 From: Deepakshi Mittal <78574784+deepakshi-mittal@users.noreply.github.com> Date: Thu, 27 Apr 2023 11:58:15 -0700 Subject: [PATCH 081/363] Restrict drop/alter login by non-sysadmin in Babelfish (#1457) * Disallow drop/alter login by non-sysadmin in Babelfish Task: BABEL-4057 Signed-off-by: Deepakshi Mittal --- contrib/babelfishpg_tsql/src/pl_handler.c | 21 ++- test/JDBC/expected/BABEL-2440.out | 8 -- test/JDBC/expected/BABEL-LOGIN-vu-cleanup.out | 9 ++ test/JDBC/expected/BABEL-LOGIN-vu-prepare.out | 13 ++ test/JDBC/expected/BABEL-LOGIN-vu-verify.out | 122 ++++++++++++++++++ .../ownership/BABEL-LOGIN-vu-cleanup.mix | 9 ++ .../ownership/BABEL-LOGIN-vu-prepare.mix | 13 ++ .../input/ownership/BABEL-LOGIN-vu-verify.mix | 66 ++++++++++ 8 files changed, 249 insertions(+), 12 deletions(-) diff --git a/contrib/babelfishpg_tsql/src/pl_handler.c b/contrib/babelfishpg_tsql/src/pl_handler.c index 583c1ec7ae..4f894a111d 100644 --- a/contrib/babelfishpg_tsql/src/pl_handler.c +++ b/contrib/babelfishpg_tsql/src/pl_handler.c @@ -2812,9 +2812,8 @@ bbf_ProcessUtility(PlannedStmt *pstmt, if (strcmp(defel->defname, "password") == 0) { - if (!is_member_of_role(GetSessionUserId(), datdba)) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + if (get_role_oid(stmt->role->rolename, true) != GetSessionUserId() && !is_member_of_role(GetSessionUserId(), datdba)) + ereport(ERROR,(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("Current login does not have privileges to alter password"))); has_password = true; @@ -2848,6 +2847,11 @@ bbf_ProcessUtility(PlannedStmt *pstmt, stmt->role->rolename = temp_login_name; } + if (!has_privs_of_role(GetSessionUserId(), datdba) && !has_password) + ereport(ERROR,(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("Current login %s does not have permission to Alter login", + GetUserNameFromId(GetSessionUserId(), true)))); + if (get_role_oid(stmt->role->rolename, true) == InvalidOid) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("Cannot drop the login '%s', because it does not exist or you do not have permission.", stmt->role->rolename))); @@ -2962,6 +2966,7 @@ bbf_ProcessUtility(PlannedStmt *pstmt, DropRoleStmt *stmt = (DropRoleStmt *) parsetree; bool drop_user = false; bool drop_role = false; + bool drop_login = false; bool all_logins = false; bool all_users = false; bool all_roles = false; @@ -2978,7 +2983,9 @@ bbf_ProcessUtility(PlannedStmt *pstmt, drop_user = true; else if (strcmp(headrol->rolename, "is_role") == 0) drop_role = true; - + else + drop_login = true; + if (drop_user || drop_role) { char *db_name = NULL; @@ -3105,6 +3112,12 @@ bbf_ProcessUtility(PlannedStmt *pstmt, else other = true; + if (drop_login && is_login(roleform->oid) && !has_privs_of_role(GetSessionUserId(), get_role_oid("sysadmin", false))){ + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("Current login %s does not have permission to Drop login", GetUserNameFromId(GetSessionUserId(), true)))); + } + ReleaseSysCache(tuple); /* Only one should be true */ diff --git a/test/JDBC/expected/BABEL-2440.out b/test/JDBC/expected/BABEL-2440.out index 7ea3ec54a9..c37f5c7315 100644 --- a/test/JDBC/expected/BABEL-2440.out +++ b/test/JDBC/expected/BABEL-2440.out @@ -21,10 +21,6 @@ guest#!#guest#!#master ALTER LOGIN r1 WITH PASSWORD = 'abc'; GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: Current login does not have privileges to alter password)~~ - SELECT session_user, current_user, db_name(); GO @@ -51,10 +47,6 @@ ignore ALTER LOGIN r1 WITH PASSWORD = '123abc' OLD_PASSWORD = 'abc'; GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: Current login does not have privileges to alter password)~~ - SELECT set_config('babelfishpg_tsql.escape_hatch_login_old_password', 'strict', 'false') GO diff --git a/test/JDBC/expected/BABEL-LOGIN-vu-cleanup.out b/test/JDBC/expected/BABEL-LOGIN-vu-cleanup.out index beb769755a..c2c9efddb3 100644 --- a/test/JDBC/expected/BABEL-LOGIN-vu-cleanup.out +++ b/test/JDBC/expected/BABEL-LOGIN-vu-cleanup.out @@ -19,3 +19,12 @@ go DROP DATABASE babel_login_vu_prepare_db1 go + +DROP LOGIN babel_4080_testlogin2; +GO + +DROP LOGIN babel_4080_sysadmin1; +GO + +DROP LOGIN babel_4080_nonsysadmin1; +GO diff --git a/test/JDBC/expected/BABEL-LOGIN-vu-prepare.out b/test/JDBC/expected/BABEL-LOGIN-vu-prepare.out index d289685c8d..1e2d00e481 100644 --- a/test/JDBC/expected/BABEL-LOGIN-vu-prepare.out +++ b/test/JDBC/expected/BABEL-LOGIN-vu-prepare.out @@ -26,3 +26,16 @@ WHERE rolname LIKE 'babel_login_vu_prepare%' ORDER BY rolname END go + +-- tsql +CREATE LOGIN babel_4080_nonsysadmin1 with PASSWORD = '1234'; +GO + +CREATE LOGIN babel_4080_sysadmin1 with PASSWORD = '1234'; +GO + +CREATE LOGIN babel_4080_testlogin1 with PASSWORD = '1234'; +GO + +CREATE LOGIN babel_4080_testlogin2 with PASSWORD = '1234'; +GO diff --git a/test/JDBC/expected/BABEL-LOGIN-vu-verify.out b/test/JDBC/expected/BABEL-LOGIN-vu-verify.out index 22737eae17..caf460a07d 100644 --- a/test/JDBC/expected/BABEL-LOGIN-vu-verify.out +++ b/test/JDBC/expected/BABEL-LOGIN-vu-verify.out @@ -460,3 +460,125 @@ DROP USER babel_login_vu_prepare_r4 go DROP LOGIN babel_login_vu_prepare_r4; go + +-- tsql +-- babel_4080 tests start here +ALTER SERVER ROLE sysadmin ADD MEMBER babel_4080_sysadmin1; +GO + +-- tsql user=babel_4080_nonsysadmin1 password=1234 + +SELECT name, type, type_desc FROM sys.server_principals where name like 'babel_4080%' order by name; +GO +~~START~~ +varchar#!#char#!#nvarchar +babel_4080_nonsysadmin1#!#S#!#SQL_LOGIN +babel_4080_sysadmin1#!#S#!#SQL_LOGIN +babel_4080_testlogin1#!#S#!#SQL_LOGIN +babel_4080_testlogin2#!#S#!#SQL_LOGIN +~~END~~ + + +ALTER LOGIN babel_4080_testlogin1 DISABLE; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Current login babel_4080_nonsysadmin1 does not have permission to Alter login)~~ + + +DROP LOGIN babel_4080_testlogin1; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Current login babel_4080_nonsysadmin1 does not have permission to Drop login)~~ + + +-- tsql user=babel_4080_sysadmin1 password=1234 +ALTER LOGIN babel_4080_sysadmin1 WITH PASSWORD = 'abcd'; +GO + +ALTER LOGIN babel_4080_testlogin1 WITH PASSWORD = 'abcd'; +GO + +ALTER LOGIN babel_4080_testlogin1 DISABLE; +GO + +SELECT rolname, rolcanlogin FROM pg_catalog.pg_roles WHERE rolname = 'babel_4080_testlogin1'; +GO +~~START~~ +varchar#!#bit +babel_4080_testlogin1#!#0 +~~END~~ + + +SELECT name, is_disabled FROM sys.server_principals WHERE name = 'babel_4080_testlogin1'; +GO +~~START~~ +varchar#!#int +babel_4080_testlogin1#!#1 +~~END~~ + + +ALTER LOGIN babel_4080_testlogin1 ENABLE; +GO + +SELECT rolname, rolcanlogin FROM pg_catalog.pg_roles WHERE rolname = 'babel_4080_testlogin1'; +GO +~~START~~ +varchar#!#bit +babel_4080_testlogin1#!#1 +~~END~~ + + +SELECT name, is_disabled FROM sys.server_principals WHERE name = 'babel_4080_testlogin1'; +GO +~~START~~ +varchar#!#int +babel_4080_testlogin1#!#0 +~~END~~ + + +DROP LOGIN babel_4080_testlogin1; +GO + +ALTER SERVER ROLE sysadmin DROP MEMBER babel_4080_sysadmin1; +GO + +-- tsql user=babel_4080_testlogin2 password=1234 +ALTER LOGIN babel_4080_testlogin2 WITH PASSWORD = 'abcd'; +GO + +-- psql +SELECT pg_terminate_backend(pid) FROM pg_stat_get_activity(NULL) +WHERE sys.suser_name(usesysid) = 'babel_4080_sysadmin1' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +GO +~~START~~ +bool +t +~~END~~ + + +SELECT pg_sleep(1); +GO +~~START~~ +void + +~~END~~ + + +SELECT pg_terminate_backend(pid) FROM pg_stat_get_activity(NULL) +WHERE sys.suser_name(usesysid) = 'babel_4080_nonsysadmin1' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +GO +~~START~~ +bool +t +~~END~~ + + +SELECT pg_sleep(1); +GO +~~START~~ +void + +~~END~~ + diff --git a/test/JDBC/input/ownership/BABEL-LOGIN-vu-cleanup.mix b/test/JDBC/input/ownership/BABEL-LOGIN-vu-cleanup.mix index beb769755a..109868ad4c 100644 --- a/test/JDBC/input/ownership/BABEL-LOGIN-vu-cleanup.mix +++ b/test/JDBC/input/ownership/BABEL-LOGIN-vu-cleanup.mix @@ -19,3 +19,12 @@ go DROP DATABASE babel_login_vu_prepare_db1 go + +DROP LOGIN babel_4080_testlogin2; +GO + +DROP LOGIN babel_4080_sysadmin1; +GO + +DROP LOGIN babel_4080_nonsysadmin1; +GO \ No newline at end of file diff --git a/test/JDBC/input/ownership/BABEL-LOGIN-vu-prepare.mix b/test/JDBC/input/ownership/BABEL-LOGIN-vu-prepare.mix index 2f46ccd0b4..cd6bd5e0e8 100644 --- a/test/JDBC/input/ownership/BABEL-LOGIN-vu-prepare.mix +++ b/test/JDBC/input/ownership/BABEL-LOGIN-vu-prepare.mix @@ -26,3 +26,16 @@ WHERE rolname LIKE 'babel_login_vu_prepare%' ORDER BY rolname END go + +-- tsql +CREATE LOGIN babel_4080_nonsysadmin1 with PASSWORD = '1234'; +GO + +CREATE LOGIN babel_4080_sysadmin1 with PASSWORD = '1234'; +GO + +CREATE LOGIN babel_4080_testlogin1 with PASSWORD = '1234'; +GO + +CREATE LOGIN babel_4080_testlogin2 with PASSWORD = '1234'; +GO \ No newline at end of file diff --git a/test/JDBC/input/ownership/BABEL-LOGIN-vu-verify.mix b/test/JDBC/input/ownership/BABEL-LOGIN-vu-verify.mix index bf2946ff93..186eb26ab7 100644 --- a/test/JDBC/input/ownership/BABEL-LOGIN-vu-verify.mix +++ b/test/JDBC/input/ownership/BABEL-LOGIN-vu-verify.mix @@ -261,3 +261,69 @@ DROP USER babel_login_vu_prepare_r4 go DROP LOGIN babel_login_vu_prepare_r4; go + +-- babel_4080 tests start here +-- tsql +ALTER SERVER ROLE sysadmin ADD MEMBER babel_4080_sysadmin1; +GO + +-- tsql user=babel_4080_nonsysadmin1 password=1234 + +SELECT name, type, type_desc FROM sys.server_principals where name like 'babel_4080%' order by name; +GO + +ALTER LOGIN babel_4080_testlogin1 DISABLE; +GO + +DROP LOGIN babel_4080_testlogin1; +GO + +-- tsql user=babel_4080_sysadmin1 password=1234 +ALTER LOGIN babel_4080_sysadmin1 WITH PASSWORD = 'abcd'; +GO + +ALTER LOGIN babel_4080_testlogin1 WITH PASSWORD = 'abcd'; +GO + +ALTER LOGIN babel_4080_testlogin1 DISABLE; +GO + +SELECT rolname, rolcanlogin FROM pg_catalog.pg_roles WHERE rolname = 'babel_4080_testlogin1'; +GO + +SELECT name, is_disabled FROM sys.server_principals WHERE name = 'babel_4080_testlogin1'; +GO + +ALTER LOGIN babel_4080_testlogin1 ENABLE; +GO + +SELECT rolname, rolcanlogin FROM pg_catalog.pg_roles WHERE rolname = 'babel_4080_testlogin1'; +GO + +SELECT name, is_disabled FROM sys.server_principals WHERE name = 'babel_4080_testlogin1'; +GO + +DROP LOGIN babel_4080_testlogin1; +GO + +ALTER SERVER ROLE sysadmin DROP MEMBER babel_4080_sysadmin1; +GO + +-- tsql user=babel_4080_testlogin2 password=1234 +ALTER LOGIN babel_4080_testlogin2 WITH PASSWORD = 'abcd'; +GO + +-- psql +SELECT pg_terminate_backend(pid) FROM pg_stat_get_activity(NULL) +WHERE sys.suser_name(usesysid) = 'babel_4080_sysadmin1' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +GO + +SELECT pg_sleep(1); +GO + +SELECT pg_terminate_backend(pid) FROM pg_stat_get_activity(NULL) +WHERE sys.suser_name(usesysid) = 'babel_4080_nonsysadmin1' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +GO + +SELECT pg_sleep(1); +GO \ No newline at end of file From 174adfc0cd34877cdee875afdb4fe5f92fa55c4b Mon Sep 17 00:00:00 2001 From: Deepakshi Mittal <78574784+deepakshi-mittal@users.noreply.github.com> Date: Thu, 27 Apr 2023 11:58:32 -0700 Subject: [PATCH 082/363] Added sanity checks for domain name in Windows Login (#1435) * Added sanity checks for domain name in Windows Login Task: BABEL-4080 Signed-off-by: Deepakshi Mittal --- contrib/babelfishpg_tsql/src/pl_handler.c | 7 + contrib/babelfishpg_tsql/src/rolecmds.c | 25 +++ contrib/babelfishpg_tsql/src/rolecmds.h | 2 + .../test_windows_login-vu-cleanup.out | 3 + .../test_windows_login-vu-prepare.out | 154 ++++++++++++++++++ .../input/test_windows_login-vu-cleanup.mix | 3 + .../input/test_windows_login-vu-prepare.mix | 54 ++++++ 7 files changed, 248 insertions(+) diff --git a/contrib/babelfishpg_tsql/src/pl_handler.c b/contrib/babelfishpg_tsql/src/pl_handler.c index 4f894a111d..0ee1a63507 100644 --- a/contrib/babelfishpg_tsql/src/pl_handler.c +++ b/contrib/babelfishpg_tsql/src/pl_handler.c @@ -2448,6 +2448,13 @@ bbf_ProcessUtility(PlannedStmt *pstmt, if (windows_login_contains_invalid_chars(orig_loginname)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("'%s' is not a valid name because it contains invalid characters.", orig_loginname))); + + /* + * Check whether the domain name contains invalid characters or not. + */ + if (windows_domain_contains_invalid_chars(orig_loginname)) + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("'%s' is not valid because the domain name contains invalid characters.", orig_loginname))); pfree(stmt->role); stmt->role = convertToUPN(orig_loginname); diff --git a/contrib/babelfishpg_tsql/src/rolecmds.c b/contrib/babelfishpg_tsql/src/rolecmds.c index 393c212a71..b1a75fe98a 100644 --- a/contrib/babelfishpg_tsql/src/rolecmds.c +++ b/contrib/babelfishpg_tsql/src/rolecmds.c @@ -2243,6 +2243,31 @@ windows_login_contains_invalid_chars(char *input) return false; } +/** + * Domain name checks, doesnot allow characters like "<>&*|quotes spaces" + * */ +bool +windows_domain_contains_invalid_chars(char *input) +{ + char *pos_slash = strchr(input, '\\'); + int domain_len = pos_slash - input; + int i = 0; + if (input == NULL) + return true; + while (i < domain_len) + { + if (input[i] == ',' || input[i] == '~' || input[i] == ':' || input[i] == '!' || + input[i] == '@' || input[i] == '#' || input[i] == '$' || input[i] == '%' || + input[i] == '_' || input[i] == '^' || input[i] == '\"' || input[i] == '\'' || + input[i] == '(' || input[i] == ')' || input[i] == '{' || input[i] == '}' || + input[i] == '\\' || input[i] == '/'|| input[i] == '<' || input[i] == '>'|| + input[i] == ' ' || input[i] == '*'|| input[i] == '|' || input[i] == '&' ) + return true; + i++; + } + return false; +} + /* * Check whether the logon_name has a valid length or not. */ diff --git a/contrib/babelfishpg_tsql/src/rolecmds.h b/contrib/babelfishpg_tsql/src/rolecmds.h index 9407726afb..75ad8f105b 100644 --- a/contrib/babelfishpg_tsql/src/rolecmds.h +++ b/contrib/babelfishpg_tsql/src/rolecmds.h @@ -77,6 +77,8 @@ extern void alter_bbf_authid_user_ext(AlterRoleStmt *stmt); extern bool is_active_login(Oid role_oid); extern char *convertToUPN(char *input); extern bool windows_login_contains_invalid_chars(char *input); +extern bool windows_domain_contains_invalid_chars(char *input); extern bool check_windows_logon_length(char *input); + #endif diff --git a/test/JDBC/expected/test_windows_login-vu-cleanup.out b/test/JDBC/expected/test_windows_login-vu-cleanup.out index f2a00e0818..870cf9753e 100644 --- a/test/JDBC/expected/test_windows_login-vu-cleanup.out +++ b/test/JDBC/expected/test_windows_login-vu-cleanup.out @@ -47,6 +47,9 @@ GO ~~ERROR (Message: Cannot drop the login 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@BABEL', because it does not exist or you do not have permission.)~~ +DROP LOGIN [ba.bel\username]; +GO + -- test for non-existent login DROP LOGIN [babel\non_existent_login] GO diff --git a/test/JDBC/expected/test_windows_login-vu-prepare.out b/test/JDBC/expected/test_windows_login-vu-prepare.out index e9a31f0abd..04d81b332b 100644 --- a/test/JDBC/expected/test_windows_login-vu-prepare.out +++ b/test/JDBC/expected/test_windows_login-vu-prepare.out @@ -341,3 +341,157 @@ GO ~~ERROR (Message: syntax error near '=' at line 2 and character position 55)~~ + +-- test for when the domain name contains invalid characters +CREATE LOGIN [